Share My Creation [Web][ABMaterial] framework for WebApps in B4J

[NOTE]: ABMaterial has now been released as DonationWare. See the B4J Library forum for the library, demos and more!

[UPDATE] I added a second video further into this topic
[UPDATE] I added a third video further into this topic
[UPDATE] I added a fourth video further into this topic (page 2)

ABMaterial.png


ABMaterial is a new framework combining a tuned version of Materialize CSS with the free programming tool B4J. It allows creating WebApps that not only look great thanks to Googles Material Design, but can be programmed with the powerful free tool from Anywhere software.

Here is a 'teaser' video. (Best watch it full screen although the quality isn't great)


All you see in the video is written completely in B4J without having to write a single line of HTML or CSS code! All this code is automatically generated while you can program your WebApp in an object oriented way like you are used to in the other Anywhere products like B4A, B4i and B4J. ABMaterial controls can be themed and have events you can use in B4J to manipulate the app. Using jQueryelement in ABMaterial, you do not have to worry about Futures etc, as all is taken care of in the library.

ABMaterial WebApps are Desktop, Tablet and Phone aware. Depending on the size of the screen, your app can appear different. For example when you resize the app on a desktop, you'll notice the SideBar on the left will disappear and a 'sandwich' button will appear in the TopBar.

You can create great looking WebApps for the web, tablets, phones and Raspberry Pi. ABMaterial uses WebSockets to interact between the WebApp and B4J.

Coding is very easy and follows the simplicity we're used to within B4A/B4i and B4J.

Has changed since the first post, but the general idea is the same
e.g. here is the source code of the parallax page:
B4X:
'Class module
Sub Class_Globals
    Private ws As WebSocket 'ignore
    ' will hold our page information
    Public page As ABMPage
    ' to access the constants
    Private ABM As ABMaterial 'ignore
    ' name of the page, must be the same as the class name
    Public Name As String = "CompParallaxPage"
    ' name of the app, same as in ABMApplication
    Public AppName As String = "demo"

    ' your own variables
    Dim myToastId As Int
End Sub

Public Sub Initialize
    ' build the local structure IMPORTANT!
    BuildPage
End Sub

Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
    Log("Connected")
    ws = WebSocket1
    ' connect our page with the websocket
    page.SetWebSocket(ws)
    ' Prepare the page IMPORTANT!
    page.Prepare
End Sub

Private Sub WebSocket_Disconnected
    Log("Disconnected")
End Sub

Sub Page_ParseEvent(Params As Map)
    Dim eventName As String = Params.Get("eventname")
    Dim eventParams() As String = Regex.Split(",",Params.Get("eventparams"))
    If SubExists(Me, eventName) Then
        Params.Remove("eventname")
        Params.Remove("eventparams")
        Select Case Params.Size
            Case 0
                CallSub(Me, eventName)
            Case 1
                CallSub2(Me, eventName, Params.Get(eventParams(0)))
            Case 2
                CallSub3(Me, eventName, Params.Get(eventParams(0)), Params.Get(eventParams(1)))
            Case Else
                ' cannot be called diretly, to many param
                CallSub2(Me, eventName, Params)
        End Select
    End If
End Sub

public Sub BuildPage()
    ' initialize this page using our theme mytheme
    page.InitializeWithTheme(Name, "/ws/" & AppName & "/" & Name, False, SharedModules.MyTheme)
    page.ShowLoader=True

    page.SetNavigationBar(SharedModules.MakeNavBar(page, "ABMParallax","../images/logo.png"), "", "Helpers", "ABMParallax")

    Dim GridDef As ABMGridDefinition
    GridDef.Initialize("RGrid")
    GridDef.AddRows(1,False, "").AddCell(0,0,0,12,12,12, False,"")
    GridDef.AddRows(2,True, "").AddCell(0,0,0,12,12,12, True,"")
    GridDef.AddRows(1,False, "").AddCell(0,0,0,12,12,12, False,"")

    ' add the definition
    page.AddFromGridDefinition(GridDef)

    Dim parallax1 As ABMParallax
    parallax1.Initialize(page, "parallax1", "../images/parallax1.jpg", 500)
    page.AddComponent("Rgrid1C1", parallax1)

    ' add paragraph
    page.AddComponent("Rgrid2C1", SharedModules.BuildParagraph(page,"par1","Parallax is an effect where the background content or image in this case, is moved at a different speed than the foreground content while scrolling. Adding it is as easy as using this code in B4J.") )

    ' add codeblock
    Dim code As StringBuilder
    code.Initialize
    code.Append("Dim parallax1 As ABMParallax").Append(CRLF)
    code.Append("parallax1.Initialize(page, ""parallax1"", ""../images/parallax1.jpg"", 500)").Append(CRLF)
    code.Append("page.AddComponent(""Rgrid1C1"", parallax1)").Append(CRLF)
    code.Append("").Append(CRLF)
    code.Append("// the other stuff you want to add to the page, like this block").Append(CRLF)
    code.Append("").Append(CRLF)
    code.Append("Dim parallax2 As ABMParallax").Append(CRLF)
    code.Append("parallax2.Initialize(page, ""parallax2"", ""../images/parallax2.jpg"", 500)").Append(CRLF)
    code.Append("page.AddComponent(""Rgrid4C1"", parallax2)").Append(CRLF)

    page.AddComponent("Rgrid3C1", SharedModules.BuildCodeBlock(page, "code", code))

    Dim parallax2 As ABMParallax
    parallax2.Initialize(page, "parallax2", "../images/parallax2.jpg", 500)
    page.AddComponent("Rgrid4C1", parallax2)

    SharedModules.BuildFooter(page)
End Sub

' clicked on the navigation bar
Sub Page_NavigationbarClicked(Action As String, Value As String)
    If Action = "ABMParallax" Then Return
    If Action = "Contact" Then
        Dim myTexts, myReturns As List
        myTexts.Initialize
        myReturns.Initialize
        myToastId = myToastId + 1
        page.ShowToast("toast" & myToastId, "toastred", "Hello to you too!", 5000, myTexts, myReturns)
        Return
    End If
    SharedModules.NavigateToPage(ws, Value)
End Sub

There is still a lot of work to do, but I'm glad I could already show you this :)

I'll keep you updated on the progress.

Alain Bailleul
 
Last edited:

LWGShane

Well-Known Member
Licensed User
Longtime User
This is awesome!

Question: Will this have a YouTube control?
 

alwaysbusy

Expert
Licensed User
Longtime User
@CoolBlueLava There will be a lightweight youtube control in the initial release, although with very limited interaction possibilities. If you want to play a youtube video, has some basic controls like, play, stop, mute etc, it will be possible (however, loading another video for example will not be possible). So if you're thinking about building a Youtube Player app with this control, then the answer is no. The Youtube control is a project on its own and Google has changed its api so many times, it's hardly managable anymore for a programmer (stuff like autoplay that does not work on iOS for example). Maybe it can be a side project later on, but as for now, just a basic one will be included in ABMaterial.
 

LWGShane

Well-Known Member
Licensed User
Longtime User
@CoolBlueLava There will be a lightweight youtube control in the initial release, although with very limited interaction possibilities. If you want to play a youtube video, has some basic controls like, play, stop, mute etc, it will be possible (however, loading another video for example will not be possible). So if you're thinking about building a Youtube Player app with this control, then the answer is no. The Youtube control is a project on its own and Google has changed its api so many times, it's hardly managable anymore for a programmer (stuff like autoplay that does not work on iOS for example). Maybe it can be a side project later on, but as for now, just a basic one will be included in ABMaterial.

A lightweight YT control is fine with me; all I really need it for is showing off my apps. (I'm going to be replacing my WordPress website with one coded in ABMaterial.)
 

Cableguy

Expert
Licensed User
Longtime User
Your timing is almost perfect , @alwaysbusy . I am in the final Hardware assembly of my pi based 2hdd webserver, and your ABMaterial is going to allow me the liberty I needed to create my back end!
[EDIT] Stupid question, don't bother answering!
 
Last edited:

alwaysbusy

Expert
Licensed User
Longtime User
@Cableguy ABMaterial makes use of Erels b4j server. Actually it all started when I was exploring Erels b4j WebSocket server demos.

e.g. the StartServer() method in ABMaterial looks like this:

B4X:
public Sub StartServer(srvr As Server, srvrName As String, srvrPort As Int)
    ABM.WriteAppLauchPageToDisk(File.DirApp & "\www\" & AppName, "index.html", AppName, Title, Description, AppleTouchIcon152x152, MSTileIcon144x144, FavorityIcon32x32, True)
   
    ' start the server
    srvr.Initialize(srvrName)
    srvr.AddWebSocket("/ws/" & AppName, "ABMApplication")
    For i =0 To Pages.Size - 1
        srvr.AddWebSocket("/ws/" & AppName & "/" & Pages.Get(i), Pages.Get(i))
    Next
    srvr.Port = srvrPort
    srvr.Start       
End Sub

As you can see, this looks kind of familiar.

One note: I'm using a modified version of Erels b4j_ws.js. It uses the 'ReconnectingWebSocket' instead of the 'WebSocket'. When the client websocket disconnects, it tries to reconnect to the server.

Also the RaiseEvent() method is changed:
B4X:
function b4j_raiseEvent(eventName, parameters) {
    var xhr = new XMLHttpRequest();
    var randomNum = Math.round(Math.random() * 1000000);
    xhr.open("GET", "donotdelete.conn" + "?rand=" + randomNum, true);
    xhr.onload = function (e) {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 304) {
                try {
                    if (b4j_ws.readyState !== 1) {
                        if (b4j_closeMessage === false) {
                            window.console.error("connection is closed. Trying to reconnect.");                               
                            b4j_closeMessage = true;
                        }
                    } else {
                        b4j_ws.send(JSON.stringify({type: "event", event: eventName, params: parameters}));
                    }
                } catch (e) {
                    window.console.error(e);
                }
            } else {
                RunToastNoConnection(randomNum);
                window.console.error("connection is closed. Trying to reconnect.");       
            }
        }
    };
    xhr.onerror = function (e) {
        RunToastNoConnection(randomNum);
        window.console.error("connection is closed. Trying to reconnect.");       
    };
    xhr.send(null);
}

It checks it the client side can download a very small file to see if there is an internet connection, so you do not leave the page to an unreachable URL until you're back connected to the internet.

Still have to see if this system works to everyones satisfaction.
 

Cableguy

Expert
Licensed User
Longtime User
Thanks for taking the time to answer...
One last and somehow stupid as in "I don't have a clue what I'm asking" question...
How to start an ABM web app when the end user (client) taps www.mysite.net
How is the index file overriden!?
 
Last edited:

alwaysbusy

Expert
Licensed User
Longtime User
for each app you make, a folder structure will be created in the www\ folder with all the html files automatically generated:

e.g. for my 'demo' it looks something like this:

/www/demo/index.html <--- this is the entry point to the 'app'
/www/demo/demo.css

The only thing this index.html does is redirecting the user to the first page of the app. Every page has its own index.html file.
So for the AboutPage, it looks something like this:

/www/demo/AboutPage/AboutPage.css
/www/demo/AboutPage/AboutPage.js
/www/demo/AboutPage/index.html

For the user, this is all transparent. All he does is go to your app: www.mysite.net:51042/demo

If you use port 80, you can ommit the port (like: www.mysite.net/demo)
I'm sure it could be possible to redirect www.mysite.com -> www.mysite.com/demo somehow, but I'm not familiar with this.

Remember, the index.htm files are only the 'entry' point to your app and are written only one time when you start your server jar. From then on, they are manipulated in your browser on the client side and are never 'rewritten' on your server.
 

Cableguy

Expert
Licensed User
Longtime User
for each app you make, a folder structure will be created in the www\ folder with all the html files automatically generated:

e.g. for my 'demo' it looks something like this:

/www/demo/index.html <--- this is the entry point to the 'app'
/www/demo/demo.css

The only thing this index.html does is redirecting the user to the first page of the app. Every page has its own index.html file.
So for the AboutPage, it looks something like this:

/www/demo/AboutPage/AboutPage.css
/www/demo/AboutPage/AboutPage.js
/www/demo/AboutPage/index.html

For the user, this is all transparent. All he does is go to your app: www.mysite.net:51042/demo

If you use port 80, you can ommit the port (like: www.mysite.net/demo)
I'm sure it could be possible to redirect www.mysite.com -> www.mysite.com/demo somehow, but I'm not familiar with this.

Remember, the index.htm files are only the 'entry' point to your app and are written only one time when you start your server jar. From then on, they are manipulated in your browser on the client side and are never 'rewritten' on your server.
Thank you for all the explanation, it all makes sense to me (which amazes me!)
 

Cableguy

Expert
Licensed User
Longtime User
Erel can you explain this post!!

AlwayBusy is busy creating a Library that will encapsulate several types of controls based on Google's Material Design and WebApp functionalities that will (hopefully) make webapp creating and dynamic creation of webpages a breeze...
In this thread he lets us know the project current status along with some video teasers so that we can fuel his commitment by showing him how hard we want it.
 

alwaysbusy

Expert
Licensed User
Longtime User
Final control for the release is finished! Here is the last 'eye candy' before I release the beta. Still a couple of days needed to finish the demo app so expect it early next week. I've already tested it a lot, but hope some of you will be able to give me further feedback when released.

5 new controls, and I'm especially proud I could add the last one before the release as it could have great potential. :)

So without further ado, here is the video...
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Top