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

BANano7.jpg


BANano7architecture2.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.

OVERVIEW

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

overview.png

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+

BANano1.21.png


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 ([email protected]). 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 ([email protected]) 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 [email protected]

Cheers,

Alain
 
Last edited:

alwaysbusy

Expert
Licensed User
Longtime User
Note on the new param BANano.MinifyOnline = true in v2.33:

Minify will only do it in Release mode, not in Debug mode (to speed things up while debugging).

And, only the BANano.Build() command will perform it, NOT the BANano.BuildAsLibrary() command. The final app using the lib will compress it anyway if it uses this parameter.
 

Mashiane

Expert
Licensed User
Longtime User

alwaysbusy

Expert
Licensed User
Longtime User
BANano 2.38

CHANGES:

1. Fix for CallInlinePHPWait which was missing the CallAjaxWait method

2. Fix for Bit functions where the first param was ignored

3. New BANanoURL, a wrapper around the URL object

4. Shortcut for URL's CreateObjectURL() and RevokeObjectURL() on the BANano object

5. New BANanoLibrary BANanoMediaRecorder which allows WebCam/Microphone/Screen recording

see for more info: https://www.b4x.com/android/forum/threads/banano-capture-webcam-microphone-screen.104504

6. Other small transpiler fixes

Download: https://www.b4x.com/android/forum/t...library-with-abstract-designer-support.99740/

Alwaysbusy
 

Mashiane

Expert
Licensed User
Longtime User
Hi, can you check this out, I'm getting a property undefined error for the ip address, i guess it's the self.

This is in Process_Globals...

B4X:
Public IPAddress As String = "10.0.2.2" ' ip address of bluestacks
    Public PhpPath As String = $"http://${IPAddress}/BANanoJQMDemo/"$

Transpiled code...

B4X:
this._ipaddress="10.0.2.2";

this._phppath="http://" + self._ipaddress + "/BANanoJQMDemo/";


Ta!
 

Mashiane

Expert
Licensed User
Longtime User
Hi

I could be wrong but it seems like, BANano.CallAjax seems to ONLY work when the eventname for your project is "BANano", anything else results in this error.

B4X:
Uncaught TypeError: obj[xmlhttp.returnMethod] is not a function
    at XMLHttpRequest.xmlhttp.onreadystatechange (app.js:7)

At first, I thought because my event name was longer than 8 characters was the cause, nada. If this is by design, cool. #BangHead
 

alwaysbusy

Expert
Licensed User
Longtime User
BANano 2.39

CHANGES:

1. new methods AddEventListenerOpen() and CloseEventListener on many BANano objects (they do work as a pair!)

All the code between these two line will be transpiled as one block. See (2) for an example.

2. new wrapper around the XMLHttpRequest.

Usage:

B4X:
Dim aEvt As Object
Dim request As BANanoXMLHttpRequest
request.Initialize
request.Open("GET", "https://reqres.in/api/users?page=1")
request.AddEventListenerOpen("onreadystatechange", aEvt)
   If request.ReadyState = 4 Then
       If request.Status = 200 Then
           Shared.Ajaxresult = request.ResponseText
           MiniCSS.Content("#r4c1", "contajax", request.ResponseText)
       Else
           Log("Error loading")
       End If
   End If
request.CloseEventListener
request.Send

3. New method BANano.UrlBase64ToUint8Array which converts a Base64 string to a Unsigned Int array.

4. new Value and OtherField() on the BANanoEvent object

5. other transpiler fixes

Download: https://www.b4x.com/android/forum/t...library-with-abstract-designer-support.99740/

Alwaysbusy
 

Mashiane

Expert
Licensed User
Longtime User
Hi

I'm currently working on a treeview control, so far, so good. Can you please add shortcurts methods on the BANanoObject, 1. ToElement and 2. ToJSON and 3. ToMap (perhaps so that one can get keys and values from the converted object using a Map type), thanks..

For example, this code works fine so long...

B4X:
'get all ids
Sub GetAll() As String
    Dim bo As BANanoObject = tree.RunMethod("getAll","")
    Return Banano.ToJson(bo)
End Sub

'set background color
Sub SetBackgroundColor(pk As String, color As String)
    Dim node As BANanoObject = tree.RunMethod("getNodeById", Array(pk))
    If node <> Null Then
        Dim el As BANanoElement = Banano.ToElement(node)
        Dim els As String = $"{"background-color":"${color}"}"$
        el.SetStyle(els)
    End If
End Sub

Ta!
 

alwaysbusy

Expert
Licensed User
Longtime User
BANano 2.44

CHANGES:

1. new method BANano.Join(list, delimiter): Makes a new string from the list where all items are seperated by the delimiter

2. The resulting BANanoObject from the BANanoEvent.OtherField() is now chainable

3. Multi-line Json in the abstract designer now allowed

4. New BANanoJSONQuery: Query your JSON data like a database.

Tip: The query itself runs only after a method returning a normal B4J object like a Int, Map or List:

e.g. the methods All, First, Last, Pluck, Find, Count

Example usage:
B4X:
Sub FillExData() 'ignore
   Dim aEvt As Object
   Dim request As BANanoXMLHttpRequest
   request.Initialize
   request.Open("GET", "assets/movies.json")
   request.AddEventListenerOpen("onreadystatechange", aEvt)
   If request.ReadyState = 4 Then
       If request.Status = 200 Then           
           JQ.Initialize2(request.ResponseText)
           ' get number of records
           Log(JQ.Count)
           ' get the movie name in the first record
           Log(JQ.First.Get("name"))
           ' get the movie name in the last record
           Log(JQ.Last.Get("name"))
           
           ' group all movies by rating
           Dim ratings As Map = JQ.GroupBy("rating").All
           ' list per rating how many movies
           For Each rat As String In ratings.Keys
               Dim Lst As List = ratings.Get(rat)
               Log(rat & " = " & Lst.Size)               
           Next
           ' get new records with only the actors name and the movie rating
           Dim Lst As List = JQ.SelectFields(Array("actor", "rating")).All
           ' show from the first record the actor
           Log(JQ.SelectFields(Array("actor", "rating")).First.Get("actor"))
           
           ' get a subset of the records (.toJQ)
           Dim tmpJQ As BANanoJSONQuery = JQ.Where($"{'actor.$eq': 'Al Pacino', 'year.$gt': 1970 }"$) _
                   .OrWhere($"{'rating': 8.4}"$) _
                   .SelectFields(Array("name", "runtime")) _
                   .Order("{'rating': 'desc'}") _
                   .toJQ
           ' show from the subset the name of the movie with a runtime of 126 minutes (it will show the first found)
           Log(tmpJQ.Find("runtime", 126).Get("name"))
           
       Else
           Log("Error loading")
       End If
   End If
   request.CloseEventListener
   request.Send
End Sub

5. New BANanoMutationObserver and BANanoMutationRecord.

Example 1: log everything that happens in the DOM on document level
B4X:
Dim Document As BANanoObject
Document.Initialize("document")

Dim DocumentObserver As BANanoMutationObserver
DocumentObserver.Initialize("DocumentObserver")

DocumentObserver.ChildList = True
DocumentObserver.Attributes = True
DocumentObserver.AttributeOldValue = True
DocumentObserver.CharacterData = True
DocumentObserver.CharacterDataOldValue = True
DocumentObserver.SubTree = True

DocumentObserver.Observe(Document)
...
Sub DocumentObserver_CallBack(records() As BANanoMutationRecord, observer As BANanoMutationObserver)
   Log(records)
End Sub

Example 2:

On the keyup event of a textbox, change the backcolor to red
Observer: if the background changes, change it to green
B4X:
Dim TextBox As BANanoElement
TextBox.Initialize("#sktextbox1")
   
Dim TextBoxObserver As BANanoMutationObserver
TextBoxObserver.Initialize("TextBoxObserver")
TextBoxObserver.Attributes = True ' style is an attribute
TextBoxObserver.AttributeOldValue = True ' and we want to log the old value too
       
TextBoxObserver.Observe(TextBox.ToObject)
...

' on keyup make red
Sub SKTextBox1_KeyUp (event As BANanoEvent)
   SKTextBox1.Style = $"{"background-color": "red"}"$
End Sub

' observer, log the old value and change to green
Sub TextBoxObserver_CallBack(records() As BANanoMutationRecord, observer As BANanoMutationObserver)
   Dim record As BANanoMutationRecord = records(0)
   Select Case record.TypeRecord
       Case "attributes"
           Log("Previous value: " & record.OldValue)
           Dim tmpObj As BANanoElement
           tmpObj = BANano.ToElement(record.Target)
           Log("New value: " & tmpObj.GetAttr(record.AttributeName))
           SKTextBox1.Style = $"{"background-color": "green"}"$
   End Select   
End Sub

In the console Log:
B4X:
app.js:96 Previous value:
app.js:102 New value: background-color: red;
app.js:96 Previous value: background-color: red;
app.js:102 New value: background-color: green;

6. other transpiler fixes

Download: https://www.b4x.com/android/forum/t...library-with-abstract-designer-support.99740/

Alwaysbusy
 

Mashiane

Expert
Licensed User
Longtime User
BANanoJSONQuery
Hi

On version 2.44, the inline css from my lib, which gets copied to my final app is being disrupted (works well on 2.39), on further look I noticed that there is JSONQUERY:false on the style added by BANano. When I remove that part and save the index.html file everything works well with the css. Can you please help and advise. Ta!

B4X:
<style type="text/css" media="screen,print" />
    JSONQUERY:false .sweet-modal-box.alert .sweet-modal-content {color:black !important}  @media (max-width: 768px){ .parallax .parallax-image{ width: 100%; height: 640px; overflow: hidden; } .parallax .parallax-image img{ height: 100%; width: auto; } } .img-container{ width: 100%; overflow: hidden; } .img-container img{ width: 100%; } .lightbox img{ width: 100%; } .lightbox .modal-content{ overflow: hidden; } .lightbox .modal-body{ padding: 0; } @media screen and (min-width: 991px){ .lightbox .modal-dialog{ width: 960px; } } .badgenumber { position: absolute; right: -10px; top: -15px; z-index: 100; border-radius: 9px; min-width: 18px; height: 18px; text-align: center; padding: 3px 5px; font-weight: 400; font-family: 'Lato', sans-serif; font-size: 11px; } .profile-ava img { border-radius: 50%; -webkit-border-radius: 50%; border: 2px solid #688a7e; display: inline-block; min-height: 35px; height: 35px; width: 35px; min-width: 35px; }  .italic { font-style: italic }  .pointer {cursor: pointer;}
 

Mashiane

Expert
Licensed User
Longtime User
Can you provide an example?
OK, thanks, will work on it and upload, my current project is rather large sadly, if perhaps I knew what generates..

B4X:
JSONQUERY:false

because that is like an object assignment as my code works well as soon as I remove that content from the generated style sheet and I'm not using BANanoJSONQuery.

Ta!
 

alwaysbusy

Expert
Licensed User
Longtime User
BANano 2.46

CHANGES:

1. Fix for tags like <br> in Umbrella JS. See for more info: https://www.b4x.com/android/forum/threads/banano-odd-br-handling.105595/

2. New BANanoWebSocket: WebSocket client applications use the WebSocket API to communicate with WebSocket servers using the WebSocket protocol.
This can for example be a B4J server, but also any other server that supports WebSocket connections.

With WebSockets you have bi-directional communication (while connected, the server can send messages to the browser).

This example uses a normal B4J jServer. For more info on how B4J jServers work see: https://www.b4x.com/android/forum/threads/webapp-web-apps-overview.39811/

BANano code:
B4X:
Sub Process_Globals
   Private BANano As BANano 'ignore           
   ' dim our websocket
   public ws As BANanoWebSocket
End Sub

...

Sub BANano_Ready()   
   BANano.LoadLayout("#body","test")
   
   ' does the browser support websockets?
   If ws.IsSupported Then
       ' last param true = use a Reconnecting WebSocket
       ws.Initialize("ws", "ws://localhost:51042/login", "", True)
   End If   
End Sub

public Sub BrowserWriteLog(message As String)
   ' here for example we'll get the response to our question further: "Who are you?"
   Log(message)
End Sub

public Sub BrowserWriteLogWithResult(message As String) As String
   ' the server is waiting for a response....
   Log(message)
   Return message & " OK"
End Sub

Sub ws_OnOpen(event As BANanoEvent)
   Log("Websocket opened")   
End Sub

Sub ws_OnError(event As BANanoEvent)
   Log("Websocket error")
End Sub

Sub ws_OnMessage(event As BANanoEvent)
   Log("Websocket message " & event.data)   
End Sub

Sub ws_OnClose(event As BANanoEvent)
   Log("Websocket closed")
End Sub

Sub SKButton1_Click (event As BANanoEvent)
   ' special Send for B4J servers
   ' Use .Send for non-B4J servers
   ws.B4JSend("AServerFunction_BAN", CreateMap("message": "Who are you?"))
End Sub

On the server:

You can use all the B4J WebSocket methods/properties that don't use a JQueryElement:

.UpgradeRequest
.Secure
.Open
.RunFunction
.RunFunctionWithResult
.Eval
.EvalWithResult
.Flush
.Session
.Alert
.Close

Also, Future can be used.

B4J Server code:
B4X:
'WebSocket class
Sub Class_Globals
   Private ws As WebSocket 'ignore   
End Sub

Public Sub Initialize
   
End Sub

Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
   Log("Connected")
   ws = WebSocket1   
End Sub

Private Sub WebSocket_Disconnected
   Log("Disconnected")
End Sub

' a method that can be called from the browser: must end with _BAN and have only one parameter: Params as Map
public Sub AServerFunction_BAN(Params As Map)
   ' access to the UpgradeRequest object
   Log(ws.UpgradeRequest.FullRequestURI)
   
   ' is the connection secure?
   Log("Is secure? " & ws.Secure)
   
   ' is the connection open?
   Log("Is open? " & ws.Open)
   
   Log(Params.Get("message"))
   ' run a function, no return value
   ws.RunFunction("BrowserWriteLog", Array("I'm server!"))
   ws.Flush
   
   ' running a method in the browser and expect a return value. It must be a method in Main.
   Dim res As Future = ws.RunFunctionWithResult("BrowserWriteLogWithResult", Array("TestWithResult"))
   ' flush to browser
   ws.Flush
   ' print the return value
   Log(res.Value)
   
   ' run a piece of javascript, no result expected
   Dim script As String = $"window.alert('Hello!');"$
   ws.Eval(script, Null)
   ws.Flush
   
   ' run a piece of javascript, with a result from the browser
   ' here we ask what the users browser is
   Dim script2 As String = $" var ua= navigator.userAgent, tem,
       M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
       if(/trident/i.test(M[1])){
           tem=  /\brv[ :]+(\d+)/g.exec(ua) || [];
           return 'IE '+(tem[1] || '');
       }
       if(M[1]=== 'Chrome'){
           tem= ua.match(/\b(OPR|Edge)\/(\d+)/);
           if(tem!= null) return tem.slice(1).join(' ').replace('OPR', 'Opera');
       }
       M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
       if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
       return M.join(' ');"$
       
   Dim res As Future = ws.EvalWithResult(script2, Null)
   ws.Flush
   Log(res.Value)
   
   ' access to the session
   Log(ws.Session.CreationTime)
   
   ' show an alert
   ws.Alert("Alert from the server!")
   
   ' also supported
   'ws.Close
End Sub

3. Typo caused some "Needs" to be saved in the CSS.

4. Other small fixes.

Download: https://www.b4x.com/android/forum/t...-library-with-abstract-designer-support.99740

Alwaysbusy
 
Top