Browser and front-end control

Artaengine provides few basic and simple solutions to some links between application back and front ends.

Browser dictionary

To set a tree like structure and keys to template files and CSS/JavaScript URLs an XML or PHP structure can be created. Some benefit of this dictionary are:

  • Meaningful and shorter keys are used to address the files and URLs.
  • Changing the file names and addresses will only require the dictionary to be updated.
  • Configs and options can be put on each file for example a config can mark a file to be compressed on build-out.
  • If a PHP libraries which renders front-end content requires a CSS or JavaScript resource, it can add it by a key without caring about what and where the file is.

XML or PHP only depends on your preferences. The data inside this files are optimized and cached by build-out.

The XML or PHP file containing the dictionary is set inside the application configure under the application section by the dictionary key. SEE

Below is an example:

<?xml version="1.0" encoding="UTF-8"?>
<configure>

  <configs>
    <!-- to explicitly say use Compiler Closure instead of YUI Compressor -->
    <config key="minify" value="closure"/>
  </configs>
 
  <templates>
    <template
        path="home/index.xhtml"
        name="index"
        />
    <authentication>
      <template
          path="authentication/login.xhtml"
          name="index"
          />
      <template
          path="authentication/signup.xhtml"
          name="signup"
          />
    </authentication>
  </templates>

  <javascripts>
    <js
        path="BASE_URL/js/jquery/jquery.min.js"
        name="jquery"
        />
    <jquery>
      <js
          path="BASE_URL/js/jquery/ui/jquery-ui.min.js"
          name="ui"
          />
      <js
          path="BASE_URL/js/jquery/selectlist/selectlist.min.js"
          name="multiselect"
          />
    </jquery>
    <js
        name="portal"
        path="BASE_URL/:build/js/app/portal.js"
        compress="APP_DIR/browser/resources/js/app/portal.js"
        />
    <user>
      <js
          path="BASE_URL/js/app/user/list.js"
          name="list"
          compress="APP_DIR/browser/resources/js/app/user/list.js"
          />
      <login>
        <js
            path="BASE_URL/js/libs/sha1.js"
            name="sha1"
            />
      </login>
    </user>
  </javascripts>

  <styles>
    <style
        path="BASE_URL/:build/styles/portal.css"
        name="portal"
        compress="APP_DIR/browser/resources/css/portal.js"
        />
    <user>
      <style
          path="BASE_URL/styles/user-list.css"
          name="list"
          compress="APP_DIR/browser/resources/css/user-list.js"
          />
    </user>
    <jquery>
      <style
          path="BASE_URL/js/jquery/ui/jquery-ui.css"
          name="ui"
          />
    </jquery>
  </styles>

</configure>
<?php
$configure = array(

    'templates' => array(
        array(
            'path' => 'home/index.xhtml',
            'name' => 'index',
        ),
        'authentication' => array(
            array(
                'path' => 'authentication/login.xhtml',
                'name' => 'index',
            ),
            array(
                'path' => 'authentication/signup.xhtml',
                'name' => 'signup',
            ),
        ),
    ),

    'javascripts' => array(
        array(
            'path' => 'BASE_URL/js/jquery/jquery.min.js',
            'name' => 'jquery',
        ),
        'jquery' => array(
            array(
                'path' => 'BASE_URL/js/jquery/ui/jquery-ui.min.js',
                'name' => 'ui',
            ),
            array(
                'path' => 'BASE_URL/js/jquery/selectlist/selectlist.min.js',
                'name' => 'multiselect',
            ),
        ),
        array(
            'name' => 'portal',
            'path' => 'BASE_URL/:build/js/app/portal.js',
            'compress' => 'APP_DIR/browser/resources/js/app/portal.js',
        ),
        'user' => array(
            array(
                'path' => 'BASE_URL/js/app/user/list.js',
                'name' => 'list',
                'compress' => 'APP_DIR/browser/resources/js/app/user/list.js',
            ),
            'login' => array(
                array(
                      'path' => 'BASE_URL/js/libs/sha1.js',
                      'name' => 'sha1',
                ),
            ),
        ),
    ),

    'styles' => array(
        array(
            'path' => 'BASE_URL/:build/styles/portal.css',
            'name' => 'portal',
            'compress' => 'APP_DIR/browser/resources/css/portal.js',
        ),
        'user' => array(
            array(
                'path' => 'BASE_URL/styles/user-list.css',
                'name' => 'list',
                'compress' => 'APP_DIR/browser/resources/css/user-list.js',
            ),
        ),
        'jquery' => array(
            array(
                'path' => 'BASE_URL/js/jquery/ui/jquery-ui.css',
                'name' => 'ui',
            ),
        ),
    ),
);

Below are descriptions:

Tags/keys

  • XML dictionary must be defined inside this tag. PHP dictionary must be an array set to $configure.
  • Template files are defined and mapped under this tag/key. There can only be one templates tag/key defined and it can contain tags to map template files to keys and any other tag-name to create customized tree branches.
  • This tag/key must be within the templates tag/key and must map a template file-path to a key. This tag/key must be a dead end without further expanding.
  • JavaScript URLs are defined and mapped under this tag/key. There can only be one javascripts tag/key defined and it can contain tags to map JavaScript URLs to keys and any other tag-name to create customized tree branches.
  • This tag/key must be within the javascripts tag/key and must map a JavaScript URL to a key. This tag/key must be a dead end without further expanding.
  • CSS URLs are defined and mapped under this tag/key. There can only be one styles tag/key defined and it can contain tags to map CSS URLs to keys and any other tag-name to create customized tree branches.
  • This tag/key must be within the styles tag/key and must map a CSS URL to a key. This tag/key must be a dead end without further expanding.

Attributes/keys

template or tpl, javascript or js and style or css are end tag/keyss which map a file/URL to a key and can have this attributes:

  • Server path to template file for template ends and URL to JavaScript CSS files for JavaScript and CSS ends. A JS or CSS path string may contain the :build substring, :build will be replaced by a incremental number on each builds. (To update browser cache when a CSS or JS is changed).
  • Name of the key to map to the file. A key to a file will contain other branch names when end branch is within more branches.
  • Only for JavaScript and CSS files. This value must be set to file address on server, 'APP_DIR' can be used inside value. Causes build-out to create compressed versions of files and use them instead of the original files when application is not in DEBUG mode. Compressed files do not replace not compressed files but are created with other name beside them. The engine automatically manages to switch application using compressed filed over non compressed based on DEBUG mode and no effort is required from the developers.

Key names instead of paths/URLs

A key-name to a file/URL consists of branch names to the file separated by /. In the above example:

  • home/index.xhtml
  • authentication/login.xhtml
  • authentication/signup.xhtml
  • BASE_URL/js/jquery/jquery.min.js
  • BASE_URL/js/jquery/ui/jquery-ui.min.js
  • BASE_URL/js/jquery/selectlist/selectlist.min.js
  • BASE_URL/js/app/portal.js
  • BASE_URL/js/app/user/list.js
  • BASE_URL/js/libs/sha1.js
  • BASE_URL/styles/portal.css
  • BASE_URL/styles/user-list.css
  • BASE_URL/js/jquery/ui/jquery-ui.css

Keys for templates are only useful when showing or getting the template contents in a factory by a Response method:

class Authentication extends Response
{
    public function login($request)
    {
        // get contents of "users/upload-form.xhtml"
        // by key set to the file path inside the browser dictionary
        $html = $this->getTemplate('authentication/index');
        // by template file path
        $html = $this->getTemplate('authentication/login.xhtml');

        // echos contents of users/list/index.xhtml
        // by key set to the file path inside the browser dictionary
        $this->show('authentication/index');
        // by template file path
        $this->show('authentication/login.xhtml');
    }
}

JavaScript and CSS keys are used for more purposes which will be explained later.

Using keys in factories

We can address JavaScript and CSS files inside factories by URL paths or by the defined keys that we maped to paths in the browser dictionary.

We can include JavaScript and CSS files either by key names or by URLs. The CSS and JS keys/paths are added to js and css public properties of a factory as shown below. In this example URLs assigned to JavaScript keys 'jquery', 'jquery/ui' and 'user/login/sha1' and URLs assigned to CSS key 'jquery/ui' will be resolved to their appropriate URLs inside the response context.

class Authentication extends Response
{
    public $js = array(
        'jquery',
        'jquery/ui',
    );
    public $css = array(
        'jquery/ui',
    );

    public function login($request)
    {
        $this->templatevar = 'value';
        $this->js[] = 'user/login/sha1';
        I($this->get());
        $this->show('authentication/index');
    }

    public function signup($request)
    {
        $this->show('authentication/signup');
    }
}

We can see all template variables and values by:

$this->inspect();

We will see:

array(
    'templatevar' => 'value',
    'arta' => array(
        'resources' => array(
            'fav' => 'http://app.com/images/fav.ico',
            'js' => array(
                'http://app.com/js/jquery/jquery.min.js',
                'http://app.com/js/jquery/ui/jquery-ui.min.js',
                'http://app.com/js/libs/sha1.js',
            ),
            'style' => array(
                'http://app.com/js/jquery/ui/jquery-ui.css',
            ),
            'jsx' => array(),
        ),
        'BASE_URL' => 'http://app.com/',
        'DEBUG'    => true,
    ),
),

Response adds a data structure called arta to the response context which contains the resolved JavaScript and CSS paths. This values are available in any response context like a json response or inside templates. Below we will use them inside a sample template:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title tal:content="Example"/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <link rel="shortcut icon" type="image/x-icon"
          tal:attributes="href arta/resources/fav"/>
    <link rel="stylesheet" type="text/css"
          tal:repeat="style arta/resources/css" tal:attributes="href style"/>
    <script type="text/javascript"
          tal:repeat="js arta/resources/js" tal:attributes="src js"/>
  </head>
  <body></body>
</html>

The same concepts are valid when a factory outputs JSON packs with $this->writeJson();. The template variables will be send as JSON.

Seeming-less inserting by Artaengine

This system lets plug-ins, adapters, classes, libraries,... to insert JavaScript file URLs, CSS file URLs and even JavaScript codes to js, style and jsx factory properties, all the developer needs to do is use the arta data structure inside the template or after a an AJAX callback or use arta.js which will automatically digest the arta data structure.

Currently only class Widget inside Artaengine library inserts value into this properties when creating certain widgets. Classes Form and FormSearch use class Widget, so using them would probably cause inserting values. It is important to know what keys this classes may insert because they have to be mapped to a JS/CSS URL inside browser dictionary:

When creating multiselect with class Widgets key jquery must map to jQuery library and jquery/multiselect must map to Select list plugin one for javascripts and one for styles.

When creating datePicker with class Widgets key jquery must map to jQuery library and jquery/ui must map to jQueryUI lib one for javascripts and one for styles.

Seeming-less inserting by developer

When creating custom plugins and adapters for Artaengine, the code below is and example of how to get handle to factory object and insert into the front-end properties:

    /* add this methods to the class and use them for inserting */
    private function __addJs($js)
    {
        if (property_exists(Arta::$factory, 'js')
            && !in_array($js, Arta::$factory->js))
            Arta::$factory->js[] = $js;
    }

    private function __addCss($style)
    {
        if (property_exists(Arta::$factory, 'style')
           && !in_array($style, Arta::$factory->style))
            Arta::$factory->style[] = $style;
    }

    private function __addJsSource($jsx)
    {
        if (property_exists(Arta::$factory, 'jsx'))
            Arta::$factory->jsx[] = $jsx;
    }

JS/CSS changes and browser caching

To update JS and CSS caches on browser, add :build to JS/CSS paths which are subject to changes. Each time you rebuild the application, Artaengine buildout will replace :build with a number which is the number of times application has been built.

One easy approach is to add a parameter to the end of URL:

    <js
        name="portal"
        path="BASE_URL/js/app/palangan.js?:build"
        compress="APP_DIR/browser/resources/js/app/palangan.js"
        />

A robust approach is to add a path to the URL:

    <js
        name="portal"
        path="BASE_URL/:build/js/app/palangan.js"
        compress="APP_DIR/browser/resources/js/app/palangan.js"
        />

And set rewrite rules like below to ignore the path:

Options +FollowSymlinks
RewriteEngine on

RewriteRule robots.txt robots.txt [L]

RewriteRule ^images/(.+)$ browser/resources/images/$1 [L]
RewriteRule ^(.*/)?css/(.+)$ browser/resources/css/$2 [L]
RewriteRule ^(.*/)?js/(.+)$ browser/resources/js/$2 [L]

RewriteCond %{REQUEST_FILENAME} !^(.*)\.(ico|jpg|png|gif|js|css|class)$
RewriteRule ^ start.php [L]

arta data structure

Based on application configuration, value of some factory properties and action of some factory methods this data structure is always available within the context of a factory and template:

array(
    'resources' => array(
        'fav' => 'http://app.com/images/fav.ico',
        'js' => array(
            'http://app.com/js/example.js',
        ),
        'style' => array(
            'http://app.com/css/example.css',
        ),
        'jsx' => array('alert("HI!");'),
    ),
    'BASE_URL' => 'http://app.com/',
    'DEBUG'    => True,
),

As shown before in a template and JSON pack this structure is assigned to an array called arta. Within the factory class this structure can be fetched by:

    $artaStructure = $this->arta();
    // or
    $artaStructure = $this->arta;

components:

  • Site fav icon URL, set in application configuration under application section, key fav.
  • A list(array) of JavaScrip URLs set to factory js property. The values which are set as key names, will be translated to the real URL.
  • A list(array) of CSS URLs set to factory style property. The values which are set as key names, will be translated to the real URL.
  • A list(array) of JavaScript codes to be ran after responding to a request, set to factory jsx property.
  • The same as constant BASE_URL, to make BASE_URL available for template or/and JavaScript.
  • The same as constant DEBUG, to make application status available for template or/and JavaScript. For example arta.js methods are sensitive to this value and depending on the status they show quite or loud error messages.

Implementing arta structure in a PHPTAL template:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
  <head>
    <title tal:content="Example"/>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <link rel="shortcut icon" type="image/x-icon"
          tal:attributes="href arta/resources/fav"/>
    <link rel="stylesheet" type="text/css"
          tal:repeat="style arta/resources/css" tal:attributes="href style"/>
    <script type="text/javascript"
          tal:repeat="js arta/resources/js" tal:attributes="src js"/>
    <script type="text/javascript">
      //<![CDATA[
      var BASE_URL = '${structure arta/BASE_URL}';
      var DEBUG = '${structure arta/DEBUG}';
      var CURRENT_URL = window.location;
      $(document).ready(function() {
          ${arta/resources/jsx}
      });
      //]]>
    </script>
  </head>
  <body></body>
</html>

Using YUI Compressor

Artaengine can execute YUI Compressor on your resource files when building an application.

  • Read YUI Compressor .
  • Download YUI Compressor.
  • Ectract YUI Compressor into Artaengine directory.
  • Rename so you will have something like:
    'www/arta/yuicompressor/build/yuicompressor.jar'
    Leave other files and directory inside 'www/arta/yuicompressor/'
    as they are.
  • Be sure that YUI Compressor is running correctly on your system.
  • Mark resources which should be compressed inside the browser dictionary.

When defining resources inside the browser dictionary you can mark them to be compressed on build-out. A compressed file will be created beside the original file. The compressed file-name will be as: originalname-min.ext.

Probably you would like the application to use the original files when under development and the compressed files when live. Artaengine looks at the application DEBUG state to decide loading.

Download example

URL mapping/dispatch
TOP