Iliad Framework, how to customize the page generation

In the previous post we talked about how to include static resources in the Pharo image to be server with our application.

Let’s start with a new web application and, as we have seen in the relative post, we must create a class deriving from ILApplication, write the path method and an empty index controller:

ILApplication subclass: #LcBlogProjectNotes
    instanceVariableNames: ''
    classVariableNames: ''
    category: 'LeonardoBlog'
"LcApplication class>>path protocol accessing"
path
    ^ 'ProjectNotes'
"LcApplication>>index protocol controllers"
index
    ^ [ :e | e h1 text:'Hi!' ]

Remember to put the index method in the protocol controllers!

Now we must integrate all the bootstrap code from the static resources generated in the previous post in the page.

Do to that we must override the updatePage: method from ILApplication like this:

"LcApplication>>updatePage protocol updating"
updatePage: aPage
    "Includes bootstrap JS"
    
    aPage head link
      rel: 'stylesheet';
      href: '/bootstrap/css/bootstrap.min.css'.
    aPage head link
      rel: 'stylesheet';
      href: '/bootstrap/css/bootstrap-theme.min.css'.
    aPage head javascript src: '/bootstrap/js/bootstrap.min.js'.
    aPage head meta
      httpEquiv: 'X-UA-Compatible';
      content: 'IE=edge'.
    aPage head meta
      name: 'viewport';
      content: 'width=device-width, initial-scale=1'.
    
    "We want a title for our app"
    aPage head title: 'A project note-taking app'

The updatePage: method get called when the page has been constructed and before its contents are sent to the browser. In this method you can customize the generated page as you want.

Voila’! We have integrated Bootstrap JS.

Advertisements
Iliad Framework, how to customize the page generation

Iliad Framework, serving static resources

In the previous lesson we talked about how to use an Iliad webapp with a browser without Javascript enabled.

In this lesson we will talk about static resources to be included in your web-app.

When you will deploy your web application in the “real world” you want your static resources served by a specific web server as Apache but, while you are developing your application, you can make use of the web server embedded inside the Pharo Smalltalk environment: Komanche.

Iliad makes really easy to serve static resources. Now we will learn how to embed in your Pharo image Bootstrap JS. Let’s assume you already downloaded the compiled distribution to a file named bootstrap-3.1.1-dist.zip and that you extracted it in a folder named ~/tmp/bootstrap-3.1.1-dist.

To include it in your Pharo image you need to derive a class from ILMemoryDirectory for every Bootstrap JS subdirectory like this:

ILMemoryDirectory subclass: #LcBootstrapCss
    instanceVariableNames: ''
    classVariableNames: ''
    category: 'LeonardoBlog'
ILMemoryDirectory subclass: #LcBootstrapFonts
    instanceVariableNames: ''
    classVariableNames: ''
    category: 'LeonardoBlog'
ILMemoryDirectory subclass: #LcBootstrapJs
    instanceVariableNames: ''
    classVariableNames: ''
    category: 'LeonardoBlog'

Now we tell the classes to load all the resources contained in the corresponding directories. Open a workspace and execute the following commands:

LcBootstrapCss addAllFilesIn:'/home/leonardo/tmp/bootstrap-3.1.1-dist/css'.
LcBootstrapJs addAllFilesIn:'/home/leonardo/tmp/bootstrap-3.1.1-dist/js'.
LcBootstrapFonts addAllFilesIn:'/home/leonardo/tmp/bootstrap-3.1.1-dist/fonts'.

You will see that a series of method are getting created under the files protocol. This is were the content of Bootstrap JS will be loaded.

Now we need to configure the subdirectory under the resources will be published. We just need to create a path method under the accessing protocol like this:

"LcBootstrapJs>>path protocol accessing"
path
    ^ 'bootstrap/js'
"LcBootstrapFonts>>path protocol accessing"
path
    ^ 'bootstrap/fonts'
"LcBootstrapCss>>path protocol accessing"
path
    ^ 'bootstrap/css'

Now we need to register these new classes to be loaded by the Iliad framework and the code to register the app must also be executed when you load your class in a fresh image. This is the place where the initialize method of the class side comes in:

"LcBootstrapJs class>>initialize protocol initialization"
initialize
    ILFileHandler addDirectory: self new
"LcBootstrapFonts class>>initialize protocol initialization"
initialize
    ILFileHandler addDirectory: self new
"LcBootstrapCss class>>initialize protocol initialization"
initialize
    ILFileHandler addDirectory: self new

Now the initialization must be done by hand in a workspace:

LcBootstrapJs initialize.
LcBootstrapCss initialize.
LcBootstrapFonts initialize.

Try using a web browser pointing to http://localhost:7070/bootstrap/js/bootstrap.js and you will see the Bootstrap Js code. The same thing happens with the other directories.

Check that also the following URLS get served:

Now you are sure that everything is working.

Iliad Framework, serving static resources

Iliad Framework, what if I don’t have Javascript?

In the previous post we talked about how events are implemented, and you saw that actions are implemented with Javascript code.

Really? You want to keep Javascript off your browsing experience? Firefox, in the new releases, even don’t have a setting to disable Javascript without installing a plugin.

The iliad framework can also degrade to a non ajax version of your application without loosing any functionality. To enable this behaviour you must evaluate this code in a new workspace:

ILAnchorElement useAjaxOnlyForActions: nil

Now disable Javascript in your browser and see your application working application with Javascript disabled. This is part of the Iliad goodness!

Iliad Framework, what if I don’t have Javascript?

Iliad Framework, how events are implemented

n the previous post we implemented the counter example. Now I would like to talk about how the event’s black magic actually works from the browser point of view.

If you are curious like me you have opened the browser source view just to see how the generated HTML looks like and you have found something like this:

<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<script type="text/javascript" src="/javascripts/jquery-1.4.4.min.js"> </script>
<script type="text/javascript" src="/javascripts/no_conflict.js"> </script>
<script type="text/javascript" src="/javascripts/iliad.js"> </script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<p>Hi! Widget example</p>
<div class="45926">
<p>0</p>
<a href="javascript:{}" onclick="iliad.evaluateAction(&quot;/leonardoBlog/widgetExample?_action=45931&amp;_state=71db1789&quot;);">++</a>
<a href="javascript:{}" onclick="iliad.evaluateAction(&quot;/leonardoBlog/widgetExample?_action=45932&amp;_state=71db1789&quot;);">--</a>
</div>
</body>
</html>

Our widget has been wrapped in a div tag that have, in my example, the class 45926. We have created two actions and these actions have been written as two Javascript calls with two parameters:

<a href="javascript:{}" onclick="iliad.evaluateAction(&quot;/leonardoBlog/widgetExample?_action=45931&amp;_state=71db1789&quot;);">++</a>
<a href="javascript:{}" onclick="iliad.evaluateAction(&quot;/leonardoBlog/widgetExample?_action=45932&amp;_state=71db1789&quot;);">--</a>

The parameter “action” is different because, on the server, two different actions have to be invoked, but the “state” variable has the same value. In effect, when we have generated the page, the state was the same between the two links.

Now I will click on the ++ link and capture the Ajax request and the server response for you:

GET http://localhost:7070/leonardoBlog/widgetExample?_action=45927&_state=71db1789
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,it;q=0.6
Connection:keep-alive
Cookie:_iliad685744=587b7bac-82f8-4e95-84bc-7a39b13aa458
Host:localhost:7070
Referer:http://localhost:7070/leonardoBlog/widgetExample
X-Requested-With:XMLHttpRequest

{
"head": [],
"widgets":
    {
      "45926":
      "<div class=\"45926\"><p>1</p><a href=\"javascript:{}\" onclick=\"iliad.evaluateAction(&quot;/leonardoBlog/widgetExample?_action=45934&amp;_state=71db1789&quot;);\">++</a><a href=\"javascript:{}\" onclick=\"iliad.evaluateAction(&quot;/leonardoBlog/widgetExample?_action=45935&amp;_state=71db1789&quot;);\">--</a></div>"
    }
}

Now the black magic is explained by itself: the page on the browser has made an Ajax request to the server telling him that it has to execute the action with the code 45927 on the state 71db1789 and the server response tell to the client that he must replace the HTML content of the widget 45926 with the new content. The server knows that which widgets must be redrawn using the markDirty method.

The meaning of the action and of the class fields should now be clear to you.

The state parameter, as you may see, doesn’t change between action invokations. Its role is managing multiple windows for the same session, for example when you have multiple tabs opened for the same session. When you have multiple tabs opened for the same session every tab has a different value for the state parameter.

Iliad Framework, how events are implemented

Iliad Framework, reacting to events

For now we have created a web application with a child widget that generate a static HTML. Now we need to receive and send data to make this application interactive.

I would like to create with you the example that you already find in the Iliad framework examples, the counter example. You can already see it in action at this link: http://localhost:7070/examples/counters.

A counter is simply an integer that starts with zero and can be incremented and decremented using two links. We start with creating an instance variable in the LcCounterWidget class that will hold the current value of the counter:

ILWidget subclass: #LcCounterWidget
    instanceVariableNames: 'value'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'LeonardoBlog'

We create the accessors accordingly with what we have said in the previous post.

"LcCounterWidget>>value protocol accessing"
value
    ^ value ifNil: [ value := 0 ].

"LcCounterWidget>>value: protocol accessing"
value:aNumber
    value := aNumber

Now I create the actions corresponding to the links under the counter:

"LcCounterWidget>>increase protocol accessing"
increase
    self value: (self value + 1).
    self markDirty.

"LcCounterWidget>>decrease protocol accessing"
decrease
    self value: (self value - 1).
    self markDirty.

As you may see these actions barely increment and decrement the value using the accessor method and then call the markDirty method, who means that the component has to be redrawn on the client side.

Now we need to modify the contents method to display the value of the counter on the page:

"LcCounterWidget>>firstWidget protocol building"
contents
    ^ [ :e |
        e p text: self value asString.
        e a
        text: '++';
        action: [ self increase ].
        e a
        text: '--';
        action: [ self decrease ] ]

Now you can try the URL: http://localhost:7070/leonardoBlog/widgetExample to see that our implementation is working.

Iliad Framework, reacting to events

Iliad Framework, the first widget

In this lesson we will create the first widget using the Iliad framework.

We have studied applications and controllers but the core of the Iliad framework is the concept of widget. Every page served by the Iliad framework is composed by widgets, as widget are written on the page as HTML tags. A widget is:

  • stateful and this means that the instace variables of the widget class are conserved between HTTP requests in the session state;
  • reusable every widget class can (and will) be used many times even in the same session using multiple widgets;
  • a container of child widgets.

Every widget is a subclass of the ILWidget class. Let’s create out first widget:

ILWidget subclass: #LcCounterWidget
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'LeonardoBlog'

The contents of a widget must be defined overriding the contents method of the widget class:

"LcCounterWidget>>contents protocol building"
contents
    ^ [ :e | e p text:'I''m a widget!' ]

When I said that every page server by the Iliad framework is composed by widgets I was actually right because also the ILApplication class extends ILWidget!

To attach out widget to the application we will add an instance variable to the application class to store the widget instance.

Create a new accessor for the firstWidget component that create the instance if needed:

"LcBlogHelloIliad>>firstWidget protocol accessing"
firstWidget
    ^ firstWidget ifNil: [ firstWidget := LcCounterWidget new ]

Now I will create a new controller just to show how the widget can be rendered:

"LcBlogHelloIliad>>widgetExample protocol contollers"
widgetExample
    ^ [ :e | e p text:'Hi! Widget example'.
    e build:self firstWidget ]

As always pay attention on putting the widgetExample in the right protocol!

Now you can go here: http://localhost:7070/leonardoBlog/widgetExample to see the example working.

This article will be long but I should make a remark on the firstWidget accessor method. We could also use the initialize method to create a new instance of the widget when the LcBlogHelloIliad class is created and this will actually work but, if you choose my implementation (which is copyied from the Iliad examples) you can reuse your old browser session to try new code and this is really good, believe me.

Iliad Framework, the first widget

Iliad Framework, on controllers

In the previous post about the Iliad Framework we build a basic web application that, in the default controller, write an “Hello World” HTML.

Now we will try to clarify how the Front Controller framework works. Every controller (remember that it must be in the controllers protocol) is mapped to a “page” of your application.

These things are best explained with an example. A controlled named firstTest in an application whose path method returns leonardoBlog will be mapped to the URL leonardoBlog/firstTest.

In the same way the controller secondTest will we mapped to leonardoBlog/secondTest. The only exception is the index controller that being the default controller is mapped to the application URL: leonardoBlog. Enough said. Let’s add some code to our application.

We create another controller named firstTest like this:

"LcBlogHelloIliad>>firstTest (protocol controllers)"
firstTest
    ^ [ :e | e h1: 'This in the first test'.
    e a linkToLocal: 'index'; text: 'Go to the index controller' ]

Now if we go to http://localhost:7070/leonardoBlog/firstTest we should see the result of the new controller.

We also created a link to the index controller using the method linkToLocal: of the ILLinkableElement class. Note that we haven’t specified the URL of the application. If you will need to change the url of the application you will not have to remember when you have put the application name.

We can also modify the original index controller to include a link to the firstTest page like this:

"LcBlogHelloIliad>>index (protocol controllers)"
index
    ^ [ :e | e h1: 'Hi world!'.
    e a linkToLocal: 'firstTest'; text: 'Go to firstTest controller' ]
Iliad Framework, on controllers