B4J Library [BANano] Website/App/PWA library with Abstract Designer support

alwaysbusy

Expert
Licensed User
BANano5.jpg

INTRO


BANano is a new B4J library to websites/webapps with (offline) Progressive Web App support. Unlike its big brother ABMaterial, BANano does not rely on any particular framework like Materialize CSS. You will have to write that part yourself, but on the other hand, you have the choice to pick which one.

Why a second framework? Well, from the start ABMaterial was build with a back server in mind. B4J has great support to setup a very powerful jServer to handle web requests. Which does mean all intelligence is at the server side and you have the full power of B4J to do whatever you want (secure database access, serial communication, cache control etc). With B4JS, some of this intelligence could be transferred to the browser side, but the app still needs internet/intranet access so this is as far as it could go.

BANano is a different animal. It can use a Service Worker to 'install' the web app in the browser, so it can also work when the user is offline. While ABMaterial builds the page from the server side, BANano builds it from the browser side. This means EVERYTHING you write in B4J is transpiled to Javascript, HTML and CSS.

But with great power comes great responsibility! Unlike ABMaterial, some basic knowledge of HTML, CSS and to some extend Javascript is needed to build BANano apps. It makes excellent use of B4X's SmartStrings to create the HTML part of the app. BANano gives you a set of tools to write your own wrapper around any framework (MiniCSS, Skeleton, Spectre, Bootstrap, ...), which then can be easily used to quickly build webapps/websites.

Note: Because Progressive Web Apps are a new technology, not all browsers do support it (e.g. on iOS, the chrome browser does not support it yet)

OVERVIEW

A quick overview to show the different uses of both frameworks:


So both frameworks have their specific target, both for the programmer and the app you want to make.

BANano is written from scratch, so although it is similar to B4JS, both support different things. B4JS is build on jQuery, while BANano uses Umbrella JS (a lighter form of jQuery, about 50x smaller) and Mustache to build the HTML.

BANano does also support some different B4J than B4JS: e.g. things like CreateMap, better support for SmartStrings etc.

Abstract Designer support in v2.0+



LICENSE

Freeware/Donationware License

B4J is Copyright (c) 2010 - 2018 by Anywhere Software All Rights Reserved.
LIBRARY (Library/library): B4J library files BANano.jar and BANano.xml (by Alain Bailleul)
SOFTWARE (Software/software): Computer Software
APPLICATION (Application/application): Any end product as the result of compiling with an Anywhere Software product
SOURCE CODE: human-readable program statements written by a programmer or developer in a high-level or assembly language that are not directly readable by a computer and that need to be compiled into object code before they can be executed by a computer

BY USING THIS LIBRARY, YOU AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE.

1. THIS LIBRARY IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL ANY COPYRIGHT HOLDER/AUTHOR/DEVELOPER BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,SPECIAL,INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY INCLUDING BUT NOT LIMITED TO LOSS OF DATA, FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER PROGRAMS OR LIBRARY, EVEN IF COPYRIGHT HOLDER/AUTHOR/DEVELOPER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

2. YOU MAY NOT COPY, SUB-LICENSE, REVERSE ENGINEER, DECOMPILE, DISASSEMBLE, OR MODIFY THIS LIBRARY IN ANY WAY.

3. YOU MAY NOT DISTRIBUTE THE LIBRARY ON ANY MEDIUM WITHOUT PRIOR NOTICE FROM ALAIN BAILLEUL (alain.bailleul@telenet.be). YOU HAVE TO ASK FOR PERMISSION IN ORDER TO MAKE THIS LIBRARY AVAILABLE FOR DISTRIBUTION OVER THE INTERNET OR ANY OTHER DISTRIBUTABLE MEDIUM.

4. YOU AGREE NOT TO DISTRIBUTE FOR A FEE AN APPLICATION USING THE LIBRARY THAT, AS ITS PRIMARY PURPOSE, IS DESIGNED TO BE AN AID IN THE DEVELOPMENT OF SOFTWARE FOR YOUR APPLICATION'S END USER. SUCH APPLICATION INCLUDES, BUT IS NOT LIMITED TO, A DEVELOPMENT IDE OR A B4J SOURCE CODE GENERATOR.

By possessing and/or using this library you are automatically agreeing to and show that you have read and understood the terms and conditions contained within this Freeware Software License Agreement. This Freeware Software License Agreement is then effective while you possess, use and continue to make use of these software products. If you do not agree with our Freeware Software License Agreement you must not possess or use our library products - this Freeware Software License Agreement will then not apply to you. This Freeware Software License Agreement is subject to change without notice.

Violators of this agreement will be prosecuted to the full extent of the law.

This library is free, however if you do enjoy it, please consider a donation to Alain Bailleul (alain.bailleul@telenet.be) for his time and efforts to make this library possible.

This license file (LICENSE.TXT) shall be included in all copies of the library or any distribution using the library in any form resulting from mechanical transformation or translation of the source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.

If you have any questions regarding this license, please contact alain.bailleul@telenet.be
Cheers,

Alain
 
Last edited:

Mashiane

Expert
Licensed User
Very impressive indeed! I was just starting to wonder how I will make my ABM apps work offline to work underground for some mining apps I'm working on. So I can just create a wrapper for myself for Material CSS and then use it with this and boom! Done! Perfect and I will have a seamless user experience.

Thanks a million for this! Viva!
 

alwaysbusy

Expert
Licensed User
Are you actually using the B4J compiler?
Partially. To configure the app and to run the BANano library and Build the app. At that point, the library takes over and transpiles the B4X source code to JavaScript.

Unlike ABM, it uses a more 'classic' way of B4X programming (e.g. one copies the assets to the 'Files' in B4J, and they are moved to the final web structure by the library).
 
Last edited:

alwaysbusy

Expert
Licensed User
Browse through the demo code get a first glance on how things work in BANano.

Don't ask questions here, but maybe use [BANano] in your subject if you have questions (or if you made a framework wrap!).
NOTE: You can now support BANano and ABMaterial here too: https://www.patreon.com/alwaysbusy
All methods are documented in the library. Unfortunately, it is getting to big to put in a forum post

Important note on naming conventions in BANano (read it!)
https://www.b4x.com/android/forum/threads/banano-nomenclature-of-banano.103675/#post-649935

Not supported B4J Core keywords (or replacements):
B4X:
Callsub, Callsub2, Callsub, Callsubdelayed, Callsubdelayed2, Callsubdelayed3: 'Use BANano.CallSub instead
Charstostring
Density
Diptocurrent
ExitApplication
Exitapplication2
File
Getenvironmentvariable
Getsystemproperty
Is 'Use BANano.IsMap, BANano.IsList, BANano.IsNull, ... instead
Isdevtool
Regex: 'Use BANAnoRegEx instead
Setsystemproperty
Smartstringformatter
Stopmessageloop
Startmessageloop
Wait: 'Use BANAno.WaitFor instead)
#if, #end: 'only CSS, CSSSmart, PHP, PHPSmart JavaScript, JavascriptSmart accepted
BANanoLibraries (wrapped libraries):

- Leaflet by @Kiffi: https://www.b4x.com/android/forum/threads/banano-leaflet-wrapper.100389
- SweetAlert 2 by Alain Bailleul: included in the zip
- Skeleton CSS by Alain Bailleul: included in the zip
- Create desktop applications (Windows, Linux, MacOS) with BANano and NW.js by @Kiffi: https://www.b4x.com/android/forum/threads/banano-nw-js-wrapper.102371/
- Kendo UI by @Kiffi: https://www.b4x.com/android/forum/threads/banano-kendo-ui-core-wrapper.103257/
- MediaRecorder by Alain Bailleul: included in the zip
- ChartKick by @Mashiane: https://www.b4x.com/android/forum/t...ts-with-1-line-of-code-using-uoecharts.104942
- Dragula (Drag/Drop) by Alain Bailleul: https://www.b4x.com/android/forum/threads/banano-library-dragula-drag-drop-made-easy.113457

BANano getting started by example:
1. BANano for Dummies by @Mashiane: https://www.b4x.com/android/forum/threads/banano-for-dummies-by-example.108722/#content

BANano tutorials:

1. Abstract Designer: https://www.b4x.com/android/forum/threads/banano-v2-1-b4j-abstract-designer.101531/
2. Abstract Designer & making libraries: https://www.b4x.com/android/forum/threads/banano-v2-2-b4j-abstract-designer.101544/
3. Talking with Javascript: https://www.b4x.com/android/forum/threads/banano-bananoobject-talks-with-javascript.100385/
4. Events: https://www.b4x.com/android/forum/threads/banano-events.100041/#content
5. BANano SQL: https://www.b4x.com/android/forum/threads/banano-working-with-bananosql.99795/#content
6. Inline php -> server code: https://www.b4x.com/android/forum/threads/banano-inline-php-server-code.101224/#content
7. Authentication to a B4J server (REST API): https://www.b4x.com/android/forum/threads/banano-inline-php-server-code.101224/#content
8. TIP: running a test Web Server: https://www.b4x.com/android/forum/threads/banano-tip-running-a-test-server.100180/
9. Resumable Sub (sort of): https://www.b4x.com/android/forum/threads/banano-resumeable-sub-sort-of.100500/#content
10. Ajax calls: https://www.b4x.com/android/forum/threads/banano-ajax-calls.100009/#content
11. Working with Promises: https://www.b4x.com/android/forum/threads/banano-working-with-promises.102413/#post-642677
12. Communication between B4J and BANano: https://www.b4x.com/android/forum/t...-communication-between-b4j-and-banano.102908/
13. Media Recorder: https://www.b4x.com/android/forum/threads/banano-capture-webcam-microphone-screen.104504/
14. Fetch API: https://www.b4x.com/android/forum/threads/banano-the-fetch-api.106666
15. Using an external editor to design your Website e.g WYSIWYG Web Builder: https://www.b4x.com/android/forum/t...ke-wysiwyg-web-builder-with-b4j-banano.115269

BANano tools:

BANanoPostProcessor by @Kiffi:alternative js compressor using node.js https://www.b4x.com/android/forum/threads/banano-bananopostprocessor.104812/

Alwaysbusy
 
Last edited:

alwaysbusy

Expert
Licensed User
Some tips to make your life easier. Unlike ABM, BANano is case sensitive in a lot of ways (e.g. for html id's, css classes, events, ...)

So if you plan to build a wrapper for a CSS/JS framework (like MiniCSS, Bootstrap, Materialize CSS), take the time to make sure everything is always lowercase. When you call one of your methods use any case you want.

An example for the MiniCSS framework:
B4X:
' TIP: you make it yourself a lot easier if you LowerCase all the IDs!
Sub Process_Globals
   Dim BANano As BANano 'ignore
End Sub

public Sub AddRows(RowIDPrefix As String, Rows As Int, classes As String) As List
   RowIDPrefix = RowIDPrefix.ToLowerCase
   Dim l As List
   l.Initialize
   For i = 1 To Rows
       Dim myRow As GridRow
       myRow.Initialize(RowIDPrefix & i, classes)
       l.Add(myRow)
   Next
   Return l
End Sub

public Sub AddColumns(CellIDPrefix As String, theRow As GridRow, Cells As Int, classes As String)
   CellIDPrefix = CellIDPrefix.ToLowerCase
   For i = 1 To Cells
       Dim myCol As GridColumn
       myCol.Initialize(theRow.ID & CellIDPrefix & i, classes)
       theRow.cols.Add(myCol)
   Next
End Sub

public Sub BuildGrid(TargetID As String, Rows As List)
   TargetID = "#" & TargetID.ToLowerCase
   Dim s As StringBuilder
   s.Initialize
   s.Append($"<div class="container">"$)
   For i = 0 To Rows.Size - 1
       Dim myRow As GridRow = Rows.Get(i)
       s.Append($"<div id="${myRow.ID}" class="${myRow.Classes}">"$)
       For j = 0 To myRow.Cols.Size - 1
           Dim myCol As GridColumn = myRow.Cols.Get(j)
           s.Append($"<div id="${myCol.ID}" class="${myCol.Classes}"></div>"$)
       Next
       s.Append($"</div>"$)
   Next
   s.Append($"</div>"$)
   BANano.GetElement(TargetID).setHTML(s.toString)
End Sub

public Sub Content(TargetID As String, ID As String, Text As String)
   TargetID = "#" & TargetID.ToLowerCase
   ID = ID.ToLowerCase
   BANano.GetElement(TargetID).RenderAppend( $"<p id="${ID}">"$ & Text & "</p>","")
End Sub

public Sub Header(TargetID As String, ID As String, Level As Int, Text As String)
   TargetID =  "#" & TargetID.ToLowerCase
   ID = ID.ToLowerCase
   BANano.GetElement(TargetID).RenderAppend($"<h${Level} id="${ID}">${Text}</h${Level}>"$,"")
End Sub

Public Sub Button(TargetID As String, ID As String, Text As String, ColorVariant As String, EventHandler As Object)
   TargetID = "#" & TargetID.ToLowerCase
   ID = ID.ToLowerCase
   Dim tgt As BANanoElement = BANano.GetElement(TargetID)
   Dim btn() as BANanoElement = tgt.RenderAppend($"<button id="${ID}" class="${ColorVariant}">${Text}</button>"$,"").Children("")
   ' defining events is very simple. Note that it has to be run AFTER adding it to the HTML DOM!
   btn(0).HandleEvents("mousedown, touchstart", EventHandler, ID & "_clicked")
End Sub

public Sub Image(TargetID As String, ID As String, Src As String, AltText As String)
   TargetID = "#" & TargetID.ToLowerCase
   ID = ID.ToLowerCase
   BANano.GetElement(TargetID).RenderAppend($"<img id="${ID}" src="${Src}" alt="${AltText}"/>"$, "")
End Sub

public Sub List(TargetID As String, ID As String, Ordered As Boolean, Items As List, EventHandler As Object)
   TargetID = "#" & TargetID.ToLowerCase
   ID = ID.ToLowerCase
   Dim s As StringBuilder
   s.Initialize
   If Ordered Then
       s.Append($"<ol id="${ID}">"$)
   Else
       s.Append($"<ul id="${ID}">"$)
   End If
   For i = 0 To Items.Size - 1
       Dim item As String = Items.Get(i)
       s.Append($"<li id="${ID}_${(i+1)}" class="${ID}_event">${item}</li>"$)
   Next
   If Ordered Then
       s.Append("</ol>")
   Else
       s.Append("</ul>")
   End If
   BANano.GetElement(TargetID).RenderAppend(s.ToString, "")
   ' defining events is very simple. Note that it has to be run AFTER adding it to the HTML DOM!
   ' we only have to define it on our class (ID & "_event") once because we can retrieve wich one from the event later
   BANano.GetElement($".${ID}_event"$).HandleEvents("mousedown, touchstart", EventHandler, ID & "_clicked")
End Sub

public Sub Code(TargetID As String, ID As String, CodeText As String)
   TargetID = "#" & TargetID.ToLowerCase
   ID = ID.ToLowerCase
   BANano.GetElement(TargetID).RenderAppend( $"<pre id="${ID}">"$ & CodeText & "</pre>","")
End Sub

public Sub BlockQuote(TargetID As String, ID As String, Text As String, cite As String)
   TargetID = "#" & TargetID.ToLowerCase
   ID = ID.ToLowerCase
   BANano.GetElement(TargetID).RenderAppend( $"<blockquote id="${ID}" cite=${cite}>"$ & Text & "</blockquote>","")
End Sub

public Sub Card(TargetID As String, ID As String, Rows As List, Classes As String)
   TargetID = "#" & TargetID.ToLowerCase
   ID = ID.ToLowerCase
   BANano.GetElement(TargetID).RenderAppend($"<div id="${ID}" class="${Classes}"></div>"$, "")
   BuildGrid(ID, Rows)
End Sub
Also a note on BANano.GetElement():

The target parameter can be a html tag (no prefix), a tags id (has prefix #) or a css class (has prefix .). So the result of your call may affect multiple html tags at once!
This can be very handy (e.g. in the List() in the above class where we are using the CSS class) where instead of making an event per list item, you can catch them all at once.

But, if not carefully used, it can give unexpected results!

Alain
 
Last edited:

Roberto P.

Well-Known Member
Licensed User
I bielive that this new framwework will have many possibilities.

I think the following developments:

- integrated with PhoneGap, for created hybrid apps
- Sync support with server
- layout design with B4j designer

I propose to support all Alain
thank
 

alwaysbusy

Expert
Licensed User
A new version 1.02 is uploaded thanks to some remarks/tests from @Kiffi:

1. There was a mistake in the example button code (that appeared to work but the event was on the wrong element):

Correct code (also updated in post #7 and the demo):
B4X:
Public Sub Button(TargetID As String, ID As String, Text As String, ColorVariant As String, EventHandler As Object)
   TargetID = "#" & TargetID.ToLowerCase
   ID = ID.ToLowerCase
   Dim tgt As BANanoElement = BANano.GetElement(TargetID)
   Dim btn() as BANanoElement = tgt.RenderAppend($"<button id="${ID}" class="${ColorVariant}">${Text}</button>"$,"").Children("")
   ' defining events is very simple. Note that it has to be run AFTER adding it to the HTML DOM!
   btn(0).HandleEvents("mousedown, touchstart", EventHandler, ID & "_clicked")
End Sub
2. Improved support for Arrays to make the above possible.

3. Fix for methods that have a return value. The last variable type in the method was handled like the return value.
Note: a method that has a return value must be put in a variable first. May be extended in a later update.

Example:

does work:
B4X:
dim myTarget as BANanoElement = GetElement("myid")
mytarget.addClass("myclass")

Sub GetElement(ID As String) As BANanoElement
   ID = ID.ToLowerCase
   Return BANano.GetElement(ID)
End Sub
does NOT work:
B4X:
GetElement("myid").addClass("myclass")

Sub GetElement(ID As String) As BANanoElement
   ID = ID.ToLowerCase
   Return BANano.GetElement(ID)
End Sub
4. Support for inline Javascript within a method:

B4X:
Sub BANano_Ready()
   
    #If JAVASCRIPT
        alert("!");
    #End If  
   
End Sub
5. Added also BANano.CheckInternetConnectionWait and BANano.CallAjaxWait

Example usage:
B4X:
If BANano.CheckInternetConnectionWait Then
       Dim res As String = BANano.CallAjaxWait("https://reqres.in/api/users?page=1","GET","jsonp", "","", "", False)
       Shared.Ajaxresult = res
       MiniCSS.Content("#r4c1", "contajax", res)
Else
       MiniCSS.Content("#r4c1", "contajax", "Cannot make Ajax call because you are not connected to the internet, but here is the last result:<br>" & Shared.Ajaxresult)
End If
6. Several other fixes, mostly typos in the javascript.

Alain
 

Harris

Expert
Licensed User
Why named BANano and not ABNano? Just curious, as I am sure you have your reasons... (typo? - BA(_ ) looks in keeping...)

Unlike ABMaterial, knowledge of HTML, CSS and to some extend Javascript is needed to build BANano apps.
This is where my trousers fall down - exposing what I don't know (or could hope to retain all the knowledge) of these other requirements.
However, like while learning ABM - it was daunting at first but it quickly became obvious (helped with B4J coding as well). I always rely on [you / and] the community to produce examples that help me learn and utilize.

Browser based would help reduce the need for 3 apps (desktop, Android, iOS) and the toil involved.

One thing many have noticed: your creative / intellectual talents never stop! I partially attribute (blame) Erel for this - since he inspires us all to excel.
 

alwaysbusy

Expert
Licensed User
Why named BANano and not ABNano
No hidden messages in this one :D It is small (compared to ABM) so Nano, and instead of Alain Bailleul I used Bailleul Alain, et voila, BANano it was :)

As this is more like a pet project compared to the serious beast ABM, it could have a more fluffier name.

Browser based would help reduce the need for 3 apps (desktop, Android, iOS) and the toil involved.
But only up to a point! Once you need OS queries, you're stuck (it is not PhoneGap). You can give your users a lot more using the other 'native' B4X tools.

your creative / intellectual talents never stop!
Some days, it is more of a curse... ;)
 

alwaysbusy

Expert
Licensed User
Uploaded version 1.04

CHANGES:

1. Important: The syntax of CallAjax and CallAjaxWait has changed to allow headers! (user and password params are gone as you have to pass them as header anyway)

2. Fixes in CallAjax/Wait (mainly in the returned Json part)

3. Fix in BANanoJSONGenerator to allow initialize to accept a Map

4. Change in SetStyle: now only allows a string as parameter, so in case of a JSONGenerator, you now have to first ToString() it. There was no clear way to determin if it was a native JSON object or a JSON string.

B4X:
Dim JSONGenerator As BANanoJSONGenerator
Dim style As Map
style.Initialize
style.Put("background", "green")
style.Put("border-radius", "5px")
JSONGenerator.Initialize(style)
   
row2c1.SetStyle(JSONGenerator.ToString)
5. Object is now an allowed Type.

6. Several other bug fixes

Download: https://www.b4x.com/android/forum/threads/banano-progressive-web-app-library.99740/#post-627764
 

alwaysbusy

Expert
Licensed User

alwaysbusy

Expert
Licensed User
Uploaded version 1.11: download https://www.b4x.com/android/forum/threads/banano-progressive-web-app-library.99740/#post-627764

CHANGES:

1. New feature to make BANano libraries (see tutorial: https://www.b4x.com/android/forum/threads/banano-creating-libraries.100412)
2. Fix where comments of inline javascript were not ignored
3. Fix for BANanoObject GetField() and SetField() using a variable instead of a string
4. Warning if you use a reseved word. This can cause trouble when BANano is transpiling your code generating bad javascript.
5. Attempt to have some kind of B4J WaitFor system using promises. (see tutorial: https://www.b4x.com/android/forum/threads/banano-resumeable-sub-sort-of.100500/)
6. Other small bug fixes
 
Last edited:

alwaysbusy

Expert
Licensed User

alwaysbusy

Expert
Licensed User
BANano v2.07: download https://www.b4x.com/android/forum/threads/banano-progressive-web-app-library.99740/#post-627764

CHANGES:

1. NEW Abstract Design system using your own Custom Views: tutorial https://www.b4x.com/android/forum/threads/banano-b4j-abstract-designer-v2-part-1.101531/
2. The signature of BuildAsLibrary has changed: it doesn't need parameters anymore and generates the files in the Additional Libraries folder immidiately.
3. Support for the Const keyword
4. You can now use inline CSS with the #if CSS tag. This can be useful if you want to quickly have a small CSS class that you want to use.
Bacause this CSS is saved in the HTML file, it is strongly advised to create a sperate CSS file if this becomes to big.

Example
B4X:
...
#if CSS
.tablehover {
   background-color: #F0F0F0;
}
#End If

#Region Internal Events
public Sub RowMouseEnter(event As BANanoEvent)
   Dim row As BANanoElement
   row.Initialize("#" & event.ID)
   row.AddClass("tablehover")
End Sub

public Sub RowMouseLeave(event As BANanoEvent)
   Dim row As BANanoElement
   row.Initialize("#" & event.ID)
   row.RemoveClass("tablehover")
End Sub
#End Region
5. The layout properties support boolean, int and float. Colors are translated to a string but as rgba(255,2255,255,1.0).

6. I've completed the Skeleton CSS library. Just the basics, but can be extended by whoever feels like it.

7. Support for getters and setters (using the lowercased prefixes set/get)

8. Support for Smart Formatting. Just wrap your text into a BANano.SF()

Supported Smart formatting Tags:

{B}{/B}: Bold
{I}{/I}: Italic
{U}{/U}: Underline
{SUB}{/SUB}: Subscript
{SUP}{/SUP}: Superscript
{BR}: Line break
{WBR}: Word break opportunity
{NBSP}: Non breakable space
{AL}http://...{AT}text{/AL}: Link, opening a new tab
{AS}http://...{AT}text{/AS}: Link, not opening a new tab
{C:#RRGGBB}{/C}: Color
{ST:styles}{/ST}: Add specific styles e.g. {ST:font-size:0.9rem;color:#2B485C}My text in font-size 0.9rem{/ST}
{IC:#RRGGBB}{/IC}: Icons (if the correct .css or font is loaded) e.g. {IC:#FFFFFF}fa fa-refresh{/IC}

Example:
B4X:
mElement.SetHTML(BANano.SF("I'm {C:#FF0000}{U}row " & (i+1) & "{/U}{/C} of a multi layout!"))
9. Bug Fixes in the transpiler

Alwaysbusy
 
Top