📜 ⬆️ ⬇️

Templates

Now 99.9% of sites use PHP templates. In many engines, this is an integral part. I want to present you a completely different approach.
I recently developed a test task and decided to try using JS templates.

Here's what happened as a result:

1) Downloading starts with parsing the URL using .htaccess and returning the necessary HTML page.
2) The browser loads javascript from the server.
3) Runs the first initialization: uploading the template files (.skin) and the file of the required language (.lang - for example, in the form of XML).
4) It loads data and renders it to the browser using loaded templates.
5) Handles keystrokes, links, and so on. (I can tell you about the processing of back and next in another topic :))
6) If necessary, sends a request to the server to receive new data.

1. AJAX Module

A module for receiving XML / JSON and sending it to the next JS-function for further scrapping. If necessary, it is possible to launch several consecutive queries.
function ajax_load (url, parcer, par, next) {
var req, ab, done = 0;
this .request = function () {
if (window.XMLHttpRequest)
ajaxRequest = new XMLHttpRequest ();
else if (window.ActiveXObject) {
ajaxRequest = new ActiveXObject ( "Msxml2.XMLHTTP" );
if (! ajaxRequest)
ajaxRequest = new ActiveXObject ( "Microsoft.XMLHTTP" );
}
return ajaxRequest;
}
')
this .ReqStatus = function () {
if (req.readyState == 4) {
clearTimeout (ab);
if (req.status == 200) {
parcer (req, par);
if (next)
ajax_load (next [0], next [1], next [2], next [3]);
} else
alert ( "AJAX Error: \ n" + req.statusText + "\ n" + url);
}
}

if (! url)
return parcer (par);

req = this .request ();
req.onreadystatechange = this .ReqStatus;
req.open ( "GET" , url, true );
req.send ( null );
ab = window.setTimeout ( function () {req.abort ();}, 10,000);
return req;
} * This source code was highlighted with Source Code Highlighter .
With the help of this function, we will just load the data from the server without reloading the main page.
Input: URL , JS function for request processing , additional parameters for the function , [ URL for the next sequential request , JS function , additional parameters , [ URL ... ]]

2. Skin Module

A module for converting a Template with parameters into HTML.
function Skin () {
var that = this ;
this .skin = new Array ();

this .trace = function (file) {
var f, x;
var rx = / <! SKIN '([\ w \ d] +)' > ([\ s \ S] *) <! END '\ 1' > / gim
f = that.skin [file] .match (rx);
for ( var i in f) {
x = rx.exec (f [i]);
that.skin [file + "." + x [1]] = x [2];
that.trace (file + "." + x [1]);
that.skin [file] = that.skin [file] .replace (f [i], '' );
}
}

this .use = function (html) {
var str;
do {
if (! (str = html.match (/% ([\ w \ d.] +)% / gim)))
break ;
for ( var i in str) {
var tp = str [i] .replace (/% / gi, '' );
if (that.skin [tp])
html = html.replace (str [i], that.skin [tp]);
else
html = html.replace (str [i], '' );
}
} while (1);
return html;
}

this .redraw = function (window, html) {
if (! document .getElementById (window))
alert ( “ERR with ID„ + window);
document .getElementById (window) .innerHTML = that.use (html);
}
} * This source code was highlighted with Source Code Highlighter .

The module has functions:
trace - to generate additional patterns from strings, like:
<! SKIN ' name_name_1 ' > ... ... <! END 'name_name_1' >
Converting them into% pattern_1_%,% pattern_name_1.% Of nested_about_name%,% pattern_name_2%.
use - substitution of parameters in the template. Parameters in templates are stored in% parameter_name%.
redraw - writes the converted template to an element, using the HTML id to identify the desired element.

3. Using templates

Take a small part of the online store. Let it simply show, was the user or not, and output some information in the form of a table.
For example, let the template ( main.skin ) look like this:
<! SKIN 'BODY' >
< div id = “menu” >
< span class = "goods_name" onclick = "ShowInfo ();" > % LANG.INFO% </ span >
< span class = "goods_name" onclick = "ChangeLang ('rus')" > % LANG.RUSSIAN% </ span >
< span class = "goods_name" onclick = "ChangeLang ('eng')" > % LANG.ENGLISH% </ span >
</ div >
< div id = "main" >
<! SKIN 'WELCOME' >
<! SKIN 'FIRST' > % LANG.WELCOME_NEW% <! END 'FIRST' >
<! SKIN 'DATE' > % DAY%.% MONTH%.% YEAR% <! END 'DATE' >
<! SKIN 'LAST' > % LANG.WELCOME_OLD%% SKIN.WELCOME.DATE% <! END 'LAST' >
<! END 'WELCOME' >
</ div >

...

<! SKIN 'ORDER' >
< table class = "price" width = "500px" >
% PRICES%
<! SKIN 'PIECE' > < tr id = "% GOODS_ID%" > < td class = "order_name" > % GOODS.NUM%. % GOODS.NAME% </ td > < td > % GOODS.PRICE% </ td > </ tr > <! END 'PIECE' >
</ table >
<! END 'ORDER' >
<! SKIN 'LOADING' >
% LANG.LOADING%
<! END 'LOADING' >

...
<! END 'BODY' > * This code was highlighted with Source Code Highlighter .
And the XML file with the language interface ( rus.xml ):
<? xml version = "1.0" encoding = "windows-1251" ? > < objects >
< language > rus </ language >
< word name = "ENCODING" > windows-1251 </ word >
< word name = "INFO" > Information </ word >
< word name = "SUPPORT" > Contact us </ word >
< word name = "ENGLISH" > English </ word >
< word name = "RUSSIAN" > Russian </ word >
< word name = "WELCOME_NEW" > Welcome, new user. </ word >
< word name = "WELCOME_OLD" > Your last visit was </ word >
< word name = "LOADING" > Connecting to the Site Database </ word >
</ objects > This code was highlighted with Source Code Highlighter .
Now we create the JS code for initial loading the template and transferring control ( main.js ):
// Create object for templates
var skins = new Skin ();

// Adding the templates of the% LANG.xxxxxx% language loaded in XML format
function SetLanguageXML (req) {
var r = req.responseXML.getElementsByTagName ( "word" ), i;
for (i = 0; i <r.length; i ++)
skins.skin [ 'LANG.' + r [i] .attributes.getNamedItem ( "name" ) .value] = r [i] .firstChild.nodeValue;
}

// Parsing the loaded template in% SKIN.xxxxxx%
function TraceResponse (req) {
skins.skin [ 'SKIN' ] = req.responseText;
skins.trace ( 'SKIN' );
}

// Load the language, load the template, and after all this, exit to initialization
ajax_load ( "rus.xml" , SetLanguageXML, null , [ "main.skin" , TraceResponse, null , [ null , RedrawAll]]); * This source code was highlighted with Source Code Highlighter .

Add missing functions that display the template in the browser window after initialization and those used in the template on onclick:
// function to change language by onclick
function ChangeLang (lang) {
// If you have rus.xml and eng.xml, then switching to another language will only require reloading the language file.
ajax_load (lang + ".xml" , SetLanguageXML, null , [ null , RedrawAll]);
}

// Function to regenerate the initial page during initialization
function RedrawAll (req) {
// I must say that the element with id = 'body' must be declared in html. For example, <div id = 'body'> </ div>.
skins.redraw ( 'body' , skins.skin [ 'SKIN.BODY' ]);
DrawWelcome ();
}

// Functions for working with cookies
function createCookie (name, value, days) {
if (days) {
var date = new Date ();
date.setTime (date.getTime () + (days * 24 * 60 * 60 * 1000));
var expires = "; expires =" + date.toGMTString ();
}
else var expires = "" ;
document .cookie = name + "=" + value + expires + "; path = /" ;
}

function readCookie (name) {
var nameEQ = name + "=" ;
var ca = document .cookie.split ( ';' );
for ( var i = 0; i <ca.length; i ++) {
var c = ca [i];
while (c.charAt (0) == '' ) c = c.substring (1, c.length);
if (c.indexOf (nameEQ) == 0) return c.substring (nameEQ.length, c.length);
}
return null ;
}

// Display Welcome screen;)
function DrawWelcome () {
var date, t;
// Is there a cookie? Then we already had a user. Read, when and display this information.
if (t = readCookie ( 'date' )) {
date = new Date;
date.setTime (t * 1000);
skins.skin [ 'DAY' ] = date.getDate ();
skins.skin [ 'MONTH' ] = date.getMonth ();
skins.skin [ 'YEAR' ] = date.getFullYear ();
show = skins.skin [ 'SKIN.BODY.WELCOME.LAST' ];
} else {
// If this is the first time on the site, we create a cookie and display other information
date = new Date;
createCookie ( 'date' , parseInt (date.getTime () / 1000), 7);
show = skins.skin [ 'SKIN.BODY.WELCOME.FIRST' ];
}

skins.redraw ( 'main' , show);
} * This source code was highlighted with Source Code Highlighter .
I note that in many cases, engines for templates allow you to make 'executable' templates, which really makes them difficult to parse. Here it is easily implemented using Javascript:
// Load from server and display info.xml in clear format (onclick function)
function ShowInfo () {
skins.redraw ( 'main' , skins.skin [ 'SKIN.BODY.LOADING' ]);
ajax_load ( "info.xml" , DrawInfo);
}

function DrawInfo (req) {
var i;
var p = req.responseXML.getElementsByTagName ( "pricelist" );
// Zero the list of goods
skins.skin [ 'PRICES' ] = "" ;
skins.skin [ 'GOODS.NUM' ] = 1;
for (i = 0; i <p.length; i ++) {
// Set the parameters for the template
skins.skin [ 'GOODS.NAME' ] = p [i] .getElementsByTagName ( "name" ) [0] .firstChild.nodeValue;
skins.skin [ 'GOODS.PRICE' ] = p [i] .getElementsByTagName ( "price" ) [0] .firstChild.nodeValue;
skins.skin [ 'GOODS.ID' ] = p [i] .getElementsByTagName ( "id" ) [0] .firstChild.nodeValue;
// Add to the list of products, ready (rendered) parts of the table
skins.skin [ 'PRICES' ] + = skins.use (skins.skin [ 'SKIN.BODY.ORDER.PIECE' ]);
skins.skin [ 'GOODS.NUM' ] ++;
}
skins.redraw ( 'main' , skins.skin [ 'SKIN.BODY.ORDER' ]);
} * This source code was highlighted with Source Code Highlighter .
In this case, the info.xml file will need to be generated in the following form:
<? xml version = "1.0" encoding = "windows-1251" ? > < objects >
< pricelist >
< id > 1 </ id >
< name > Bread </ name >
< price > 12 </ price >
</ pricelist >
< pricelist >
< id > 2 </ id >
< name > Watermelon </ name >
< price > 200 </ price >
</ pricelist >
< pricelist >
< id > 3 </ id >
< name > Potato </ name >
< price > 32 </ price >
</ pricelist >
</ objects > This code was highlighted with Source Code Highlighter .
Finally, index.html . Yes, I was not mistaken - it was html:
< html > < head >
< meta http-equiv = "Content-Type" content = "text / html; charset = windows-1251 " >
</ head >
< body > < div id = 'body' > </ div >
< script type = "text / javascript" src = "main.js" > </ script >
</ body > </ html > This was the code highlighted with the Source Code Highlighter .

A working example can be found here: zcn.ru/market

4. Disadvantages and advantages of this approach

There are few disadvantages, but they are quite significant:
- Inability without the introduction of additional funds to work with the URL.
- It is impossible to use the "back" and "forward" keys. If the author has not provided emulation.
- Search engines can not parse Javascript and AJAX.
- The probability of a disabled JS user.

About these problems and methods of solving it was said here - habrahabr.ru/blog/webdev/44753.html , so I will not focus on them.

Pluses are also significant:
- Quite a lot (with good optimization) decreases the load on the server.
- To change the type of site does not require any refinement of PHP-code - only ccs / javascript and templates.
- Transparent and fairly clear code templates and handler. It is very easy to add new "pages".
- Simple change of various settings, simple loading of other XML-files. Language, Currency (dollar, rub), etc. Without reloading the page.

Source: https://habr.com/ru/post/28323/


All Articles