B4J Library [BANano] Progressive Web App library

Discussion in 'B4J Libraries & Classes' started by alwaysbusy, Nov 26, 2018.

  1. alwaysbusy

    alwaysbusy Expert Licensed User

    Download of the beta 1.08 here: https://www.b4x.com/android/forum/t...rogressive-web-app-library.99740/#post-627764

    INTRO


    BANano is a new B4J library to create one-page 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 uses 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, 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:

    [​IMG]
    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) 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. On the other hand B4JS does support SmartTags (like {B}, {I} etc) and does all the html encoding automatically while in BANano you will have to take care of this yourself.

    DEMO

    I will create a set of tutorial on BANano, but for those who can't wait to see it at work, you can visit https://feedback.abmaterial.com/banano.html

    This is just a 'test it all' demo. Some stuff you can see:

    After loading the page, open the Chrome Console. It will show the output of a lot of aspects of BANano. Notable are the 'mycoun't logs: this increments as a browser database is used and with every refresh it inserts a record in the database.

    You can go offline, close the browser and go back to it. In the 'network tab' you'll see some red lines (e.g. for some favicons), but this is normal as it is a bug in Chrome.

    For those who want to go even deeper, open the app.js file. I've uploaded the app in debug mode, and in good B4X tradition, you can see the original B4J code in comments so you can follow the transpile (go to the bottom of the file as some libraries are loaded first).

    A snippet:
    Code:
    ' [47] Sub BANano_Ready()
    this.banano_ready=function() {
    if (self==null) self=this;
    var _teststr;
    var _rows;
    var _v;
    var _s;
    var _conts;
    var _cont;
    var _k;
    var _r;
    var _row2c1;
    var _clientid;
    var _ops;
    var _m;
    ' [48]  Dim testStr As String = QUOTE & {23} & TAB & {24} & QUOTE
    _teststr="\""+"Hello there!"+"\t"+"after tab"+"\"";
    ' [49]  Log(testStr)
    console.log(_teststr);
    ' [51]  myFirst.Initialize( {25} )
    self._myfirst.initialize("Alain is here!");
    ' [53]  SQL.Open( {26} , {27} )
    alasql.promise("CREATE INDEXEDDB DATABASE IF NOT EXISTS bananodb;").then(function(res){
    self.sql_sqlopened();
    }).catch(function(reason){
    self.sql_sqlerror("CREATEDB", reason);
    })
    ;
    ' [55]  Dim rows As List = MiniCSS.AddRows( {28} , 6)
    _rows=_banano_minicss.addrows("r",6);
    ' [56]  MiniCSS.AddColumns( {29} ,rows.get(0),3, {30} )
    _banano_minicss.addcolumns("c",_rows[0],3,"col-sm-4");
    ' [57]  MiniCSS.AddColumns( {31} ,rows.get(1),1, {32} )
    _banano_minicss.addcolumns("c",_rows[1],1,"col-sm-12");
    ' [58]  MiniCSS.AddColumns( {33} ,rows.get(2),1, {34} )
    _banano_minicss.addcolumns("c",_rows[2],1,"col-sm-12");
    ' [59]  MiniCSS.AddColumns( {35} ,rows.get(3),3, {36} )
    _banano_minicss.addcolumns("c",_rows[3],3,"col-sm-4");
    ' [60]  MiniCSS.AddColumns( {37} ,rows.get(4),1, {38} )
    _banano_minicss.addcolumns("c",_rows[4],1,"col-sm-4");
    ' [61]  MiniCSS.AddColumns( {39} ,rows.get(5),1, {40} )
    _banano_minicss.addcolumns("c",_rows[5],1,"col-sm-12");
    ' [62]  MiniCSS.BuildGrid( {41} , rows)
    _banano_minicss.buildgrid("#body",_rows);
    ' [64]  Dim v() As String = Array( {42} , {43} )
    _v=["ala1","ala2"];
    ' [65]  For Each s As String In v
    for (var _sindex=0;_sindex<_v.length;_sindex++) {
    _s=_v[_sindex];
    ' [66]  Log(s)
    console.log(_s);
    ' [67]  Next
    }
    ' [69]  Dim conts() As BANanoElement = BANano.GetElement( {44} ).Children( {45} )
    _conts=u("#body").children().toU();
    ' [70]  For Each cont As BANanoElement In conts
    for (var _contindex=0;_contindex<_conts.length;_contindex++) {
    _cont=_conts[_contindex];
    ' [71]  Log( {46} & cont.HasClass( {47} ))
    console.log("HasClass: "+_cont.hasClass("container"));
    ' [72]  Dim rows As List = cont.Children( {48} )
    _rows=_cont.children(".row").toU();
    ' [73]  For k = 0 To rows.Size - 1
    for (_k=0;_k<=_rows.length-1;_k++) {
    ' [74]  Dim r As BANanoElement = rows.Get(k)
    _r=_rows[_k];
    ' [75]  Log(r.GetAttr( {49} ))
    console.log(_r.attr("id"));
    ' [76]  Next
    }
    ' [77]  Next
    }
    ' [78]  For k = 0 To conts.Length - 1
    for (_k=0;_k<=_conts.length-1;_k++) {
    ' [79]  Dim cont As BANanoElement = conts(k)
    _cont=_conts[_k];
    ' [80]  Log( {50} & cont.Find( {51} ).Length)
    console.log("Find .row: "+_cont.find(".row").toU().length);
    ' [81]  Next
    }
    ' [83]  MiniCSS.Header( {52} , {53} , 4, {54} )
    _banano_minicss.header("#r1c1","hdr1",4,"HEADER");
    ' [84]  MiniCSS.Content( {55} , {56} , {57} )
    _banano_minicss.content("#r1c1","cont1","This is just some paragraph text to demonstate how BANano works");
    ' [86]  BANano.GetElement( {58} ).Render(Template1, {1} )
    u("#r1c3").html(Mustache.render(self._template1,JSON.parse("{\"firstName\": \"Alain\", \"lastName\": \"Bailleul\", \"blogURL\": \"https:'alwaysbusycorner.com/\"}")));
    ' [88]  MiniCSS.Button( {59} , {60} , {61} , {62} , Me)
    _banano_minicss.button("#r2c1","btn1","PRESS ME","secondary",_banano_bananodemo);
    ' [90]  MiniCSS.LoginForm( {63} , {64} , Me)
    _banano_minicss.loginform("#r3c1","loginform",_banano_bananodemo);
    ' [92]  MiniCSS.Image( {65} , {66} , {67} , {68} )
    _banano_minicss.image("#r4c1","image1","./assets/1.jpg","my image");
    ' [94]  Dim row2c1 As BANanoElement = BANano.GetElement( {69} )
    _row2c1=u("#r2c1");
    ' [95]  Log(row2c1.GetStyle( {70} ))
    console.log(_row2c1.css("background-color"));
    ' [96]  row2c1.SetStyle( {2} )
    _row2c1.css(JSON.parse("{\"background-color\": \"red\"}"));
    ' [97]  Log(row2c1.GetStyle( {71} ))
    console.log(_row2c1.css("background-color"));
    ' [99]  row2c1.Append( {72} ).Append( {73} ).Append( {74} )
    _row2c1.append("<div>test</div>").append("<div>test2</div>").append("<div>test3</div>");
    ' [101]  RunMe
    self.runme();
    ' [103]  Dim clientId As String = {75} & Rnd(1,9999999999)
    _clientid="BananoMQTT"+(Math.floor(Math.random() * (9999999999 - 1) + 1));
    ' [104]  mqtt.Initialize( {76} , {77} ,443, {78} , True, clientId)
    self._mqtt = new Paho.MQTT.Client("iot.eclipse.org",443,"/ws",_clientid);
    self._mqtt.onConnectionLost=function() {self.mqtt_disconnected();};
    self._mqtt.onMessageArrived=function(message) {self.mqtt_messagearrived(message.destinationName, message.payloadBytes);};
    var _mqtt_conn={onSuccess:function() {self.mqtt_connected(true);}, onFailure: function() {self.mqtt_connected(false);useSSL=true}};
    ' [106]  Dim ops As BANanoMQTTConnectOptions
    _ops={};
    ' [107]  ops.Initialize( {79} , {80} )
    _ops.userName="";
    _ops.password="";
    ' [108]  ops.CleanSession = False
    _ops.cleanSession=false;
    ' [109]  mqtt.Connect2(ops)
    self._mqtt_conn=_ops;
    self._mqtt_conn.useSSL=true;
    self._mqtt_conn.onSuccess=function() {self.mqtt_connected(true);};
    self._mqtt_conn.onFailure=function() {self.mqtt_connected(false);};
    self._mqtt.connect(self._mqtt_conn);
    ' [111]  Dim m As Map = CreateMap( {81} : 1, {82} : 2)
    _m={"January":1, "February":2};
    ' [112]  Log(m.Get( {83} ))
    console.log(_m["January"]);
    ' End Sub

    };
    LICENSE

    Note that BANano will have the same License as ABMaterial. A small reminder:
    The philosophy of ABMaterial/BANano (and myself) is giving anyone the chance to easily build great WebApps without having to spend any money. One of the reasons I picked B4J was because it is free. Those who can spare something, donate to stimulate my continuation on the project and in so help giving other not so fortunate people an equal chance to grow. Any derived development tool or generator that uses ABMaterial/BANano must follow this philosophy so the tool must be available with 100% of its features for free (not even a ‘limited’ free version is acceptable).

    This has no impact on whatever WebApp you make with ABMaterial/BANano, but is solely a protection against some ‘money-grubber’ who sees the potential of the ABMaterial/BANano framework and thinks of making some easy money using my engine by simply writing a layer above it. Just to be clear, ‘FEE’ here means ANY form of payment or compensation, donations included.

    Cheers,

    Alain
     
    Last edited: Dec 13, 2018 at 3:53 PM
  2. Erel

    Erel Administrator Staff Member Licensed User

    Very impressive. This is a 100% client solution. Are you actually using the B4J compiler?
     
    joulongleu likes this.
  3. Mashiane

    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!
     
    joulongleu likes this.
  4. alwaysbusy

    alwaysbusy Expert Licensed User

    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. I will send you the source code of the library. If, one day, you want to use it as a template to build it in the B4JCompiler and make a real B4W platform out of it, please feel free to do so.

    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). I guess using your custom views, theoretically, we could even use the Designer to make the interface (not there yet).

    An app looks like this:
    Code:
    ' WILL BE IGNORED IN THE JAVASCRIPT FILE
    Sub AppStart (Args() As String)
       
    ' you can change some output params here
       BANano.Initialize("BANano""BANanoDemo",1)
     
       BANano.Header.Title=
    "BANano Demo"
       
    ' must be added to B4J's Files
       BANano.Header.AddFavicon("favicon-32x32.png""32x32")
       BANano.Header.AddFavicon(
    "favicon-16x16.png""16x16")
       BANano.Header.AddAppleTouchIcon(
    "apple-touch-icon.png""180x180")
       BANano.Header.AddMSTileIcon(
    "mstile-150x150.png""144x144")
       BANano.Header.SetMaskIcon(
    "safari-pinned-tab.svg")
       BANano.Header.AddManifestIcon(
    "android-chrome-192x192.png""192x192")
       BANano.Header.AddManifestIcon(
    "android-chrome-256x256.png""256x256")
     
       
    ' you can pick another one if you want
       BANano.Header.AddCSSFile("mini-nord.min.css")
     
       
    ' DO NOT USE FOR PRODUCTION AS THERE IS NO GUARANTEE IT WILL KEEP WORKING!
       ' USE YOUR OWN SERVER AND UPLOAD THE donotdelete.gif TO IT!
       BANano.ExternalTestConnectionServer = "http://gorgeousapps.com"
             
       
    ' start the build
       BANano.Build(File.DirApp)
    End Sub

    ' WILL BE IGNORED IN THE JAVASCRIPT FILE
    Sub Application_Error (Error As Exception, StackTrace As StringAs Boolean
       
    Return True
    End Sub

    ' HERE STARTS YOUR APP
    Sub BANano_Ready()

    End Sub
    So except for the AppStart() and Application_Error() methods, all the rest you write is converted to JavaScript by the BANano library.

    The great thing about it is that one can use the IDE to check syntax (huge advantage). Although the final app is offline, I see it working as a full solution with a REST API written using jServer. e.g. when the user is offline, all his 'ToDo's are saved in the browsers IndexedDB using BANanoSQL. When it goes online, it syncs with the database using the jServer REST solution. Or even communicate with other B4X solutions using MQTT (BANanoMQTTClient can be used for that).

    I got the idea for BANano when someone on the forum mentioned Tizen. I think, with some modification, BANano could be a start to support this. If someone writes a wrapper around the Tau.js library in B4J using BANano, and I'll let it generate the JavaScript in a Tizen folder stucture, it may be compiled with the Tizen compiler.

    One does need knowledge of how webapps work, but BANano helps you a great deal. For example making a working list is very simple (I use the MiniCSS framework here):
    Code:
    public Sub List(TargetID As StringID 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
    Which then can be used in your app as:
    Code:
    ...
    ' adding a list
    Dim MyList As List
    MyList.Initialize
    MyList.Add(
    "Apple")
    MyList.Add(
    "Orange")
    MyList.Add(
    "Strawberry")
    MiniCSS.List(
    "r4c1""MyList"False, MyList, Me)
    ...

    Sub MyList_Clicked(event As BANanoEvent)
       
    Log("Clicked on: " & event.ID)
    End Sub
    As you can see, it quickly beomes obvious that your SmartStrings are a crucial tool!
     
  5. alwaysbusy

    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!).

    DOWNLOAD http://gorgeousapps.com/BANano1.08.zip

    BANano
    Author:
    Alain Bailleul
    Version: 1.08
    • BANanoSQL
      Events:
      • SQLExecuteResult (Tag as String As , Result as List As )
      • SQLOpened ( As )
      • SQLExecuteError (Tag as String As , Reason as String As )
      Methods:
      • ExecuteWait (Query As java.lang.String, Args As anywheresoftware.b4a.objects.collections.List) As anywheresoftware.b4a.objects.collections.List
        Returns the result as a List of maps containing the requested data in case of a SELECT

        Note: Methods using ExecuteWait can NOT return a value!
      • Execute (Query As java.lang.String, Args As anywheresoftware.b4a.objects.collections.List, tag As java.lang.String) As void
        Will return the result in the SQLResult(Tag as String, Result as List) event. The tag can be used to see where it is coming from.

        Result returns a list of maps containing the requested data in case of a SELECT

        if an error occurs, SQLExecuteError() will be raised with Tag you passed
      • OpenWait (eventName As java.lang.String, databaseName As java.lang.String) As void
        Opens the database and creates it if it does not exist. Uses IndexedDB so everything works with promises.

        Note: Methods using OpenWait can NOT return a value!
      • Open (eventName As java.lang.String, databaseName As java.lang.String) As void
        Opens the database and creates it if it does not exist. Uses IndexedDB so everything works with promises.

        When the database is created and open the event SQLOpened() will be raised

        if an error occurs, SQLExecuteError() will be raised with Tag="CREATEDB"
    • BANanoRegEx
      Methods:
      • IgnoreCase As boolean
        Checks whether the "i" modifier is set
      • LastIndex As int
        The lastIndex property specifies the index at which to start the next match.
      • InitializeString (patternS As java.lang.String) As void
        Creates a new BANanoRegEx object using the given string

        see <a href="https://www.w3schools.com/jsref/jsref_obj_regexp.asp">Javascript RegEx reference</a> for the pattern.
      • InitializePattern (pattern As java.lang.String) As void
        Creates a new BANanoRegEx object using the given pattern
        the outer quotes will be removed

        see <a href="https://www.w3schools.com/jsref/jsref_obj_regexp.asp">Javascript RegEx reference</a> for the pattern.
      • Global As boolean
        Checks whether the "g" modifier is set
      • Source As java.lang.String
        Return the text of the RegExp pattern
      • SearchString (s As java.lang.String, patternS As java.lang.String) As int
        The search() method searches a string for a specified value and returns the position of the match

        you don't need to use BANano.RegEx to initiate it.
      • ReplaceString (s As java.lang.String, patternS As java.lang.String, byStr As java.lang.String) As java.lang.String
        The replace() method replaces a specified value with another value in a string
        the outer quotes will be removed

        you don't need to use BANano.RegEx to initiate it.
      • MultiLine As boolean
        Check whether or not the "m" modifier is set
      • Exec (s As java.lang.String) As java.lang.String
        Tests for a match in a string. Returns the first match
      • Test (s As java.lang.String) As boolean
        Tests for a match in a string. Returns true or false
      • SearchPattern (s As java.lang.String, pattern As java.lang.String) As int
        The search() method searches a string for a specified value and returns the position of the match
        the outer quotes will be removed

        you don't need to use BANano.RegEx to initiate it.
      • ReplacePattern (s As java.lang.String, pattern As java.lang.String, byStr As java.lang.String) As java.lang.String
        The replace() method replaces a specified value with another value in a string

        you don't need to use BANano.RegEx to initiate it.
    • BANanoObject
      Methods:
      • RunMethod (methodName As java.lang.String, params As java.lang.Object) As com.ab.banano.BANanoObject
        Runs a method on the JavaScript object.

        NOTE: the outer Array will be removed in the javascript.
        So if you want to pass an array, you have to add an extra array.

        e.g. if you want to pass "[0,0], "Alain", you actually have to pass [[0,0], "Alain"]

        <code>
        RunMethod("myMethod", Array(Array(0,0), "Alain"))
        </code>

        If only one, non Array parram is passed, you can ignore this.

        e.g. this is valid

        RunMethod("myMethod", "Alain")
      • GetField (field As java.lang.String) As com.ab.banano.BANanoObject
        Gets a field value
      • Initialize2 (jsObject As java.lang.String, params As java.lang.Object) As com.ab.banano.BANanoObject
        To initialize for a 'New libObjectName' javascript library

        e.g. Javascript:
        <code>
        let datepicker = new When({
        input: document.getElementById('...'),
        singleDate: true
        });
        datepicker.showHeader = true;
        </code>

        Translated to B4J:
        <code>
        Dim datepicker As BANanoObject
        datepicker.Initialize2("When", CreateMap("input": BANano.GetElement("#datepicker").ToObject, "singleDate": True))
        datepicker.RunMethod("showHeader", True)
        </code>
      • SetField (field As java.lang.String, value As java.lang.Object) As com.ab.banano.BANanoObject
        Sets a field value
      • Initialize (jsObject As java.lang.Object) As void
        Can be used e.g. to connect a BANanoObject to a JavaScript object
      • Selector (selector As java.lang.Object) As com.ab.banano.BANanoObject
        Useful for e.g. jQuery selectors

        <code>
        Dim jQ as BANanoObject
        jQ.Initialize("$")
        JQ.Selector("#btn2").RunMethod("Click", Array(BANano.CallBack(Me, "btn2_clicked", Null))))

        Sub Btn2_Clicked()
        BANano.Msgbox("btn2 clicked through BANanoObject and jQuery!")
        End Sub
        </code>
    • BANanoMQTTConnectOptions
      Methods:
      • SetLastWill (Topic As java.lang.String, Payload As byte[], QOS As int, Retained As boolean) As void
      • Initialize (UserName As java.lang.String, Password As java.lang.String) As void
        Initializes the object and sets the username and password.
        Pass empty strings if username or password are not required.
      Properties:
      • UserName As java.lang.String
        Gets or sets the connection user name.
      • CleanSession As boolean [write only]
        If set to true (default value) then the state will not be preserved in the case of client restarts.
      • Password As java.lang.String
        Gets or sets the connection password.
    • BANanoMQTTClient
      Events:
      • Connected (Success As Boolean)
      • Disconnected
      • MessageArrived (Topic As String, Payload() As Byte)
      Methods:
      • Publish2 (Topic As java.lang.String, Payload As byte[], QOS As int, Retained As boolean) As void
      • Connect As void
      • Close As void
      • Subscribe (Topic As java.lang.String, QOS As int) As void
      • Unsubscribe (Topic As java.lang.String) As void
      • Initialize (EventName As java.lang.String, Server As java.lang.String, port As int, path As java.lang.String, isSecure As boolean, ClientID As java.lang.String) As void
        Only Websockets are supported
      • Connect2 (Options As com.ab.banano.BANanoMQTTConnectOptions) As void
      • Publish (Topic As java.lang.String, Payload As byte[]) As void
      Properties:
      • QOS_0_MOST_ONCE As int [read only]
      • QOS_1_LEAST_ONCE As int [read only]
      • ClientID As java.lang.String [read only]
      • QOS_2_EXACTLY_ONCE As int [read only]
    • BANanoJSONParser
      Methods:
      • NextArray As anywheresoftware.b4a.objects.collections.List
      • NextObject As anywheresoftware.b4a.objects.collections.Map
        Parses the text assuming that the top level value is an object.
      • Initialize (Text As java.lang.String) As void
        Initializes the object and sets the text that will be parsed.
    • BANanoJSONGenerator
      Methods:
      • ToPrettyString (Indent As int) As java.lang.String
        Creates a JSON string from the initialized object.
        The string will be indented and easier for reading.
        Note that the string created is a valid JSON string.
        Indent - Number of spaces to add to each level.
      • Initialize2 (List As anywheresoftware.b4a.objects.collections.List) As void
        Initializes the object with the given List.
      • ToString As java.lang.String
        Creates a JSON string from the initialized object.
        This string does not include any extra whitespace.
      • Initialize (Map As anywheresoftware.b4a.objects.collections.Map) As void
        Initializes the object with the given Map.
    • BANanoHeader
      Fields:
      • Description As java.lang.String
      • Keywords As java.lang.String
      • Viewport As java.lang.String
      • MSTileColor As java.lang.String
      • Title As java.lang.String
      • Charset As java.lang.String
      • Manifest As java.lang.String
      • MaskIconColor As java.lang.String
      • Language As java.lang.String
      • Author As java.lang.String
      • BaseURL As java.lang.String
      • ThemeColor As java.lang.String
      • Expires As long
      • BaseTarget As java.lang.String
      • BackgroundColor As java.lang.String
      Methods:
      • AddAppleTouchIcon (AssetFileNameOrURL As java.lang.String, size As java.lang.String) As void
        home screen icons for Safari and iOS
      • AddFavicon (AssetFileNameOrURL As java.lang.String, size As java.lang.String) As void
        Add additional fav icons
      • AddCSSFile (AssetFileNameOrURL As java.lang.String) As void
        Load an extra css file. if an asset file it will be copied to the styles folder
      • AddJavascriptFile (AssetFileNameOrURL As java.lang.String) As void
        Load an extra javascript file. if an asset file it will be copied to the scripts folder
      • AddManifestIcon (AssetFileNameOrURL As java.lang.String, size As java.lang.String) As void
        PWA Icon used in the manifest.json file
      • AddMeta (metaTag As java.lang.String) As void
        must be a full html meta tag. Use smartstrings! e.g.

        "$<meta name="keywords" content="HTML,CSS,XML,JavaScript">$"
      • AddMSTileIcon (AssetFileNameOrURL As java.lang.String, size As java.lang.String) As void
        home screen icons for Microsoft
      • SetMaskIcon (AssetFileNameOrURL As java.lang.String) As void
        Set the Mask Icon
    • BANanoEvent
      Methods:
      • AltKey As boolean
      • ScreenX As int
      • ScreenY As int
      • ClientX As int
      • DeltaZ As int
      • DeltaMode As int
      • ClientY As int
      • DeltaY As int
      • DeltaX As int
      • MetaKey As boolean
      • ShiftKey As boolean
      • Char As java.lang.String
      • KeyCode As java.lang.String
      • ID As java.lang.String
      • PageX As int
      • PageY As int
      • CharCode As java.lang.String
      • OffsetX As int
      • OffsetY As int
      • TimeStamp As int
      • Type As java.lang.String
      • CurrentTarget As java.lang.String
      • RelatedTarget As java.lang.String
      • PreventDefault As void
      • CtrlKey As boolean
      • Buttons As int
      • Key As java.lang.String
      • Detail As java.lang.Object[]
    • BANanoElement
      Methods:
      • Before (html As java.lang.String) As com.ab.banano.BANanoElement
        Add some html as a sibling before each of the matched elements

        Note: it is better to use the RenderBefore method, as it is much more powerful
      • ToggleClass (Class As java.lang.String) As com.ab.banano.BANanoElement
        Toggles the class of matched elements
      • Parent (filter As java.lang.String) As com.ab.banano.BANanoElement[]
        Retrieve each parent of the matched nodes, optionally filtered by a selector
      • SetText (text As java.lang.String) As com.ab.banano.BANanoElement
        Set the text content of matched elements
      • Render (htmlTemplate As java.lang.String, jsonData As java.lang.String) As com.ab.banano.BANanoElement
        Sets the innerHTML of the target using the htmlTemplate and the provided jsonData

        The htmlTemplate is a <a href="https://github.com/janl/mustache.js">Mustache</a> template.
      • SetChecked (checked As boolean) As com.ab.banano.BANanoElement
        Set the checked value of matched elements
      • Remove As com.ab.banano.BANanoElement
        Removes the matched elements.
      • GetChecked As boolean
        Retrieve the checked value of matched elements
      • Initialize (target As java.lang.Object) As void
        Target: and ID (use #), class (use ."), tag etc...
      • SetData (name As java.lang.String, value As java.lang.String) As com.ab.banano.BANanoElement
        Handle data-* attributes for the matched elements
      • Off (events As java.lang.String) As com.ab.banano.BANanoElement
        Remove event handler from matched nodes
      • Prepend (html As java.lang.String) As com.ab.banano.BANanoElement
        Add some html as a child at the beginning of each of the matched elements

        Note: it is better to use the RenderPrepend method, as it is much more powerful
      • Empty As com.ab.banano.BANanoElement
        Remove all child nodes of the matched elements.
      • Last As com.ab.banano.BANanoElement[]
        Retrieve the last of the matched nodes
      • Trigger (event As java.lang.String, params As java.lang.String[]) As com.ab.banano.BANanoElement
        Triggers an event.

        Params: MUST be defined as Array("", 0, ...)
        Will be returned in the event.detail property
      • SetAttr (name As java.lang.String, value As java.lang.String) As com.ab.banano.BANanoElement
        Handle attributes for the matched elements
      • AddClass (Class As java.lang.String) As com.ab.banano.BANanoElement
        Add html class(es) to all of the matched elements
      • GetStyle (property As java.lang.String) As java.lang.String
        Returns the property value
      • GetHTML As java.lang.String
        Retrieve the html of the elements
      • Children (filter As java.lang.String) As com.ab.banano.BANanoElement[]
        Get the direct children of all of the nodes with a filter *
      • First As com.ab.banano.BANanoElement[]
        Retrieve the first of the matched nodes
      • SetStyle (jsonString As java.lang.String) As void
        Sets the style of the target BANanoElement.

        example:

        <code>
        dim json as JSONGenerator
        json.initialize($"{ "width": "200px", "height": "200px", "background": "green", "border-radius": "5px" }"$)
        BANano.GetElement("#someid").SetStyle(json.ToString)

        or using simply the string (must be valid Json!):
        BANano.GetElment("#someid").SetStyle($"{ "width": "200px", "height": "200px", "background": "green", "border-radius": "5px" }"$)

        </code>
      • Siblings (filter As java.lang.String) As com.ab.banano.BANanoElement[]
        Get the siblings of all of the nodes with a filter *
      • RenderReplace (htmlTemplate As java.lang.String, jsonData As java.lang.String) As com.ab.banano.BANanoElement
        Replaces the target using the htmlTemplate and the provided jsonData

        The htmlTemplate is a <a href="https://github.com/janl/mustache.js">Mustache</a> template.
      • Replace (html As java.lang.String) As com.ab.banano.BANanoElement
        Replace the matched elements with the passed elements

        Note: it is better to use the RenderReplace method, as it is much more powerful
      • ToObject As com.ab.banano.BANanoObject
        Returns a BANanoObject: nodes[0], the native html object
      • RenderAppend (htmlTemplate As java.lang.String, jsonData As java.lang.String) As com.ab.banano.BANanoElement
        Add some html as a child at the end of each of the matched elements using the htmlTemplate and the provided jsonData

        The htmlTemplate is a <a href="https://github.com/janl/mustache.js">Mustache</a> template.
      • Scroll As void
        Scroll to the first matched element, smoothly if supported.
      • Closest (filter As java.lang.String) As com.ab.banano.BANanoElement[]
        Find the first ancestor that matches the selector for each node
      • HandleEvents (events As java.lang.String, module As java.lang.Object, method As java.lang.String) As com.ab.banano.BANanoElement
        module: the module or class where the method is defined
        method: the method you want to call

        This function is the same as on(), but it executes the e.preventDefault()

        The method MUST be defined like this:

        <code>
        sub methodName(event As BANanoEvent)
        log(event.ID)
        end sub
        </code>
      • RemoveClass (Class As java.lang.String) As com.ab.banano.BANanoElement
        Remove html class(es) to all of the matched elements.
      • SetHTML (html As java.lang.String) As com.ab.banano.BANanoElement
        Set the html of the elements.

        Note: it is better to use the Render method, as it is much more powerful
      • HasClass (Class As java.lang.String) As boolean
        Find if any of the matched elements contains the class passed
      • GetAttr (name As java.lang.String) As java.lang.String
        Handle attributes for the matched elements
      • RenderBefore (htmlTemplate As java.lang.String, jsonData As java.lang.String) As com.ab.banano.BANanoElement
        Add some html as a sibling before each of the matched elements using the htmlTemplate and the provided jsonData

        The htmlTemplate is a <a href="https://github.com/janl/mustache.js">Mustache</a> template.
      • Not (filter As java.lang.String) As com.ab.banano.BANanoElement[]
        Remove known nodes from nodes
      • Append (html As java.lang.String) As com.ab.banano.BANanoElement
        Add some html as a child at the end of each of the matched elements

        Note: it is better to use the RenderAppend method, as it is much more powerful
      • Length As int
        You can check how many elements are matched with .Length
      • Filter (filter As java.lang.String) As com.ab.banano.BANanoElement[]
        Get the direct children of the nodes with a filter
      • GetData (name As java.lang.String) As java.lang.String
        Handle data-* attributes for the matched elements
      • After (html As java.lang.String) As com.ab.banano.BANanoElement
        Add some html as a sibling after each of the matched elements

        Note: it is better to use the RenderAfter method, as it is much more powerful
      • Find (filter As java.lang.String) As com.ab.banano.BANanoElement[]
        Get all of the descendants of the nodes with a filter
      • RenderAfter (htmlTemplate As java.lang.String, jsonData As java.lang.String) As com.ab.banano.BANanoElement
        Add some html as a sibling after each of the matched elements using the htmlTemplate and the provided jsonData

        The htmlTemplate is a <a href="https://github.com/janl/mustache.js">Mustache</a> template.
      • GetText As java.lang.String
        Retrieve the text content of matched elements
      • SetValue (text As java.lang.String) As com.ab.banano.BANanoElement
        Set the value content of matched elements
      • On (events As java.lang.String, module As java.lang.Object, method As java.lang.String) As com.ab.banano.BANanoElement
        module: the module or class where the method is defined
        method: the method you want to call

        The method MUST be defined like this:

        <code>
        sub methodName(event As BANanoEvent)
        log(event.ID)
        end sub
        </code>
      • GetValue As java.lang.String
        Retrieve the value content of matched elements
      • RenderPrepend (html As java.lang.String) As com.ab.banano.BANanoElement
        Add some html as a child at the beginning of each of the matched elements using the htmlTemplate and the provided jsonData

        The htmlTemplate is a <a href="https://github.com/janl/mustache.js">Mustache</a> template.
    • BANano
      Events:
      • Ready ( As )
      • CallAjaxResult (Success as Boolean As , UniqueID as String As , Result As String)
      • IsConnectedResult (Tag as String As , Result as boolean As )
      • EmailSent (Tag as String As , Message as String As )
      Fields:
      • Header As com.ab.banano.BANanoHeader
      • Version As java.lang.String
      • SERVICEWORKER_NAME As java.lang.String
      • JAVASCRIPT_NAME As java.lang.String
      • VersionName As java.lang.String
      • Version108 As java.lang.String
      • MANIFEST_NAME As java.lang.String
      • HTML_NAME As java.lang.String
      Methods:
      • EncodeURI (o As java.lang.Object) As java.lang.String
        The encodeURI() function is used to encode a URI.

        This function encodes special characters, except: , / ? : @ & = + $ # (Use EncodeURIComponent() to encode these characters).
      • parseFloat (o As java.lang.Object) As double
        The parseFloat() function parses a string and returns a floating point number.
      • CallBack (module As java.lang.Object, methodName As java.lang.String, params As anywheresoftware.b4a.objects.collections.List) As java.lang.Object
      • UNDEFINED As java.lang.Object
        transpiles as 'undefined'
      • IsFinite (o As java.lang.Object) As boolean
        The isFinite() function determines whether a number is a finite, legal number.
      • DecodeURIComponent (o As java.lang.Object) As java.lang.String
        The decodeURIComponent() function decodes a URI component.
      • SendEmail (token As java.lang.String, tag As java.lang.String, from As java.lang.String, to As java.lang.String, subject As java.lang.String, body As java.lang.String) As void
        Sends a simple email

        Use https://www.smtpjs.com/ to encrypt your credentials and generate the token. It will look
        somthing like this:

        It will raise the _EmailSent() event, returning the tag and a message. Can be OK or an error message.
      • Initialize (eventName As java.lang.String, appShortName As java.lang.String, appVersion As long) As void
        Do not uses spaces in the appShortName!
      • INFINITY As java.lang.Object
        transpiles as 'Infinity'
      • ToElement (obj As com.ab.banano.BANanoObject) As com.ab.banano.BANanoElement
        Converts the BANanoObject to a BANAnoElement
      • SetLocalStorage (key As java.lang.String, json As java.lang.Object) As void
        To set data into localStorage, you must use the LocalStorageSet API. There are two arguments:
        key for the Object's key, and json for the key value

        example:

        <code>
        dim json as JSONGenerator
        json.initialize("{ founded: '1992', formed: 'California', members: ['Tom Delonge', 'Mark Hoppus', 'Travis Barker']}")
        SetLocalStorage("someband", json)
        </code>
      • CheckInternetConnection (tag As java.lang.String) As void
        Checks if the app can reach the internet

        Will raise the banano IsConnected(Tag as String, Result as boolean) event

        you can then use the tag to see who was the caller and act accordingly
      • Build (outputDir As java.lang.String) As void
        Should be called in AppStart() in the Main module.
      • RunInlineJavascriptMethod (methodName As java.lang.String, Params As anywheresoftware.b4a.objects.collections.List) As java.lang.Object
        Method to call an inline Javascript method. The methodName is Case Sensitive!

        For inline javascript, use #If JAVASCRIPT/#End If

        Note: it does not mather where you put inline javascript, all of it is global.

        Example:<code> *
        Log(BANano.RunInlineJavascriptMethod("evaluate", Array As String("10 * 20")))

        #if JAVASCRIPT
        function evaluate(s) {
        // so we get back a string
        return '' + eval(s);
        }
        #End If
        </code>
      • CallAjaxWait (url As java.lang.String, type As java.lang.String, dataType As java.lang.String, data As java.lang.Object, withCredentials As boolean, headers As anywheresoftware.b4a.objects.collections.Map) As java.lang.String
        Makes an ajax call. Returns the result of the call

        Note: Methods using CallAjaxWait can NOT return a value!
      • EncodeURIComponent (o As java.lang.Object) As java.lang.String
        The encodeURIComponent() function encodes a URI component.

        This function encodes special characters. In addition, it encodes the following characters: , / ? : @ & = + $ #
      • RemoveLocalStorage (key As java.lang.String) As void
        Deletes the key from the LocalStorage
      • DecodeURI (o As java.lang.Object) As java.lang.String
        The decodeURI() function is used to decode a URI.
      • FromBase64 (s As java.lang.String) As java.lang.String
        Converts a base 64 string back to a normal string
      • Eval (o As java.lang.Object) As java.lang.Object
        The eval() function evaluates or executes an argument.

        If the argument is an expression, eval() evaluates the expression. If the argument is one or more JavaScript statements, eval() executes the statements.
      • Window As com.ab.banano.BANanoObject
        Returns the Window Object as a BANanoObject. From there on, you can access all the rest (like document, innerWidth, navigator)
        using the BANanoObject methods

        example:
        <code>
        Log(BANano.Window.GetField("navigator").GetField("appName"))
        </code>
      • DebugTrackMethod (moduleName As java.lang.String, methodName As java.lang.String) As void
        Will track this method in the Browsers log
      • Msgbox (text As java.lang.String) As void
        Shows an alert box, same as BANano.Alert
      • ToObject (elem As com.ab.banano.BANanoElement) As com.ab.banano.BANanoObject
        Converts the BANanoElement to a BANanoObject
      • CheckInternetConnectionWait As boolean
        Checks if the app can reach the internet

        Note: Methods using CheckInternetConnectionWait can NOT return a value!
      • GetElement (target As java.lang.String) As com.ab.banano.BANanoElement
        Target: and ID (use #), class (use ."), tag etc...
      • TypeOf (var As java.lang.Object) As java.lang.Object
        to get the type of the object
      • ToBase64 (s As java.lang.String) As java.lang.String
        Converts a string to a base 64 string.
      • IsNaN (o As java.lang.Object) As boolean
        The isNaN() function determines whether a value is an illegal number (Not-a-Number).
      • EmptyLocalStorage (key As java.lang.String) As void
        Empty the LocalStorage for this domain
      • IsTablet As boolean
        Returns if the browser is running on a tablet
      • parseInt (o As java.lang.Object) As int
        The parseInt() function parses a string and returns an integer.
      • DebugTrackLine (moduleName As java.lang.String, virtualLineNumber As int) As void
        When running in debug mode, you can get some extra debug information by tracking some line.
        In the generated javascript file, some comment lines showing the the B4J code have a virtual number prefix: [number]

        You can use this number to track the transpiling of that line.

        Tracks in the B4J log
      • GetCookie (name As java.lang.String) As java.lang.String
        Returns a the value of the cookie
      • SetCookie (name As java.lang.String, value As java.lang.String, jsonOptions As java.lang.String) As void
        jsonOptions: expires, path, domain, secure

        example: expires 7 days from now

        SetCookie("mycookie", "myvalue", "{expires: 7, path: '', domain: 'mydomain.com', secure: 'true'}")
      • IsPhone As boolean
        Returns if the browser is running on a phone
      • CallAjax (url As java.lang.String, type As java.lang.String, dataType As java.lang.String, data As java.lang.Object, uniqueId As java.lang.String, withCredentials As boolean, headers As anywheresoftware.b4a.objects.collections.Map) As void
        Makes an ajax call. Returns the result of the call to BANano_CallAjaxResult()

        Example:<code>
        dim headers as Map
        headers.initialize
        headers.put("Content-Type", "application/json")
        BANano.CallAjax("https://reqres.in/api/users?page=2","GET","jsonp", "","ID0001", false, headers)

        Sub BANano_CallAjaxResult(Success As Boolean, UniqueID As String, Result As String)
        Log(Success)
        Log(UniqueID)
        Log(Result)
        End Sub
        </code>
      • Alert (text As java.lang.String) As void
        Shows an alert box, same as BANano.Msgbox
      • NAN As java.lang.Object
        transpiles as 'NaN' (Not-a-Number)
      • GetLocalStorage (key As java.lang.String) As java.lang.Object
        Returns the saved json from the key
      • ToString (o As java.lang.Object) As java.lang.String
        The ToString() function converts the value of an object to a string.

        Note: The ToString() function returns the same value as toString() of the individual objects.
      • RemoveCookie (name As java.lang.String, jsonOptions As java.lang.String) As void
        Deletes a cookie.

        IMPORTANT! When deleting a cookie and you're not relying on the default attributes,
        you must pass the exact same path and domain attributes that were used to set the cookie

        example:

        RemoveCookie("mycookie", "{path: '', domain: 'mydomain.com'}")
      Properties:
      • Initialbody As java.lang.String [write only]
        Can ONLY be used in AppStart(). It writes the string directly as the innerHML of the body tag.
      • ExternalTestConnectionServer As java.lang.String [write only]
        By default the connection to the internet is tested by checking if donotdelete.gif can be retrieved
        from the assets folder where the app is hosted.

        However, if you do not put it on a host (e.g. just by opening the .html file from disk),
        You can upload the donotdelete.gif to some host on the internet to test for an internet connection.
      • UseServiceWorker As boolean [write only]
        Can ONLY be used in AppStart(). Set this param to false if you do not want to use a ServiceWorker
        Default true

    Not supported B4J Core keywords (may be incomplete!):

    Plugins (wrapped libraries):

    - Leaflet by @Kiffi : https://www.b4x.com/android/forum/threads/banano-leaflet-wrapper.100389
     
    Last edited: Dec 13, 2018 at 7:12 PM
    moster67, fredo, DonManfred and 5 others like this.
  6. Don Oso

    Don Oso Member Licensed User

    Just one word ..... WOW !!

    Thanks Alain !
     
    joulongleu and alwaysbusy like this.
  7. alwaysbusy

    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:
    Code:
    ' 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 StringAs 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 StringID 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 StringID 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 StringID 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 StringID 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 StringID 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 StringID 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 StringID 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 StringID 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: Dec 3, 2018
    keirS, joulongleu and mindful like this.
  8. Roberto P.

    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
     
    joulongleu likes this.
  9. Kiffi

    Kiffi Active Member Licensed User

    That looks very promising!

    [​IMG]

    Greetings ... Peter
     
    joulongleu and alwaysbusy like this.
  10. alwaysbusy

    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):
    Code:
    Public Sub Button(TargetID As StringID 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:
    Code:
    dim myTarget as BANanoElement = GetElement("myid")
    mytarget.addClass(
    "myclass")

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

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

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

    Example usage:
    Code:
    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
     
    joulongleu and Kiffi like this.
  11. Kiffi

    Kiffi Active Member Licensed User

    Very cool! Thanks a lot, Alain! [​IMG]

    Greetings ... Peter
     
    joulongleu likes this.
  12. Harris

    Harris Well-Known Member Licensed User

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

    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.
     
  13. alwaysbusy

    alwaysbusy Expert Licensed User

    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.

    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.

    Some days, it is more of a curse... ;)
     
    Erel and Harris like this.
  14. alwaysbusy

    alwaysbusy Expert Licensed User

  15. alwaysbusy

    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.

    Code:
    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
     
    Kiffi, micro, Mashiane and 1 other person like this.
  16. alwaysbusy

    alwaysbusy Expert Licensed User

    Erel and mindful like this.
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice