Pliant talk forum

Pliant talk forum

Discussion: Graphic design and HTML templates

How to allow Pliant fill-in disconnected areas on HTML page
designed by graphic artist.
Message posted by maybe Boris Reitman on 2007/05/12 18:54:36
Pliant .page mechanism is great for writing quick and dirty 
user interfaces, as the programmer generates all the HTML 
content with "text", "text_input" etc. commands.  
This is fine when all the user interface is in the middle of 
the page, between header and footer. 
(The header and footer is a mess of HTML designed by graphic artist).

But on a real website, GUI elements are spread out all over the page, in 
boxes.  For example, in the menu, there can be a box for search, or a drop-down 
box with a list of countries. The body could be a checkout form that user 
must fill in, which needs to be pretty, and have layout that is easilly modified 
by a graphic designer with standard HTML design graphics program like 
DreamWeaver.

So, basically, I need to get pliant to work with templates.  It can be something
like ASP/PHP model where HTML is interrupted and pliant code starts. I don't 
like it because it is a mess.

Or it can be another mechanism, where certain spots in the template are marked 
as boxes, and all the HtmlPage methods will render themself into correct boxes.
For example,


method page fill_designer1_template
arg_rw HtmlPage page
  # current template is "default"
  page template "designer1"
    # current template is "designer1"
    page template_box "box1"
      implicit page
        text "this text appears in box1 of template designer1"
      ...
    page template_box "box2"
      implicit page
        text "this text appears in box2 of template designer1"
  # as we leave the template block, the template is generated and all the data
  # is printed.

  # current template is again "default"

method page fill_main_page
arg_rw HtmlPage
  page template "main_page"
    page template_box "main_content"
    implicit page
      fill_designer1_template
      ...
    page template_box "search"
    implicit page
      ...

So to summarize, page methods render into bits of HTML templates,
and all the nested templates are put together by the way function invocations 
nest themselves.
The "page template" block will change current template when the block begins,
and pop it to restore the old value, when the block ends. 

For a common case that a table needs to be generated, and each row is a template
itself, the row template spec can be embedded in the main template HTML file
with some syntax, like this:

<table><tr> <th>col1</th> <td>col2</th></tr>
<define_template name="ROW_TEMPLATE1">
<tr><td> %%LEFT_CELL%% </td><td> %%RIGHT_CELL%% </td></tr>
</define_template>
</table>

The LEFT_CELL, RIGHT_CELL are the boxes into which pliant will print.
When the table template is loaded, the <define_template> definition
will be replaced with %%ROW_TEMPLATE1%% and the template code for ROW_TEMPLATE1
will be available as a template for use with "page set_template" method.

What are you thoughts ?
How can I implement this easily ? I need all the .page methods to print into 
strings organized in a dictionary keyed by box name. When it is time to generate
the HTML from the running template, the strings will be printed into the boxes.
Can I get the .page elements to print into a stream of my choosing ? 
In C++, for example, there is a StringStream class. I could write something 
similar for pliant, and tell .page elements to print into that stream.

Boris






Message posted by maybe Boris Reitman on 2007/05/12 23:43:29
After some thought, another way to implement this without printing into
strings keyed by box ids, is this algorithm:

The "set_template" instruction is a meta that rearranges the order in
which "template_box" blocks inside it are invoked, to match the order of
%%box_name%% tags in the template.   This is done by "goto" statements
that jump in the right order between the blocks, and this order can be
changed at run time, because this allows for the template to be updated
without server restart.

So this is implemented as a finite state machine "switch". When a
template is loaded, we initialize an order of boxes and save it into
an array which is cached for future use.  It is an array of fixed size
equal to the number of template_box blocks in the code.  The values of
the array is where to jump next. Essentially, this is a linked list in an
array. At the end of each "template_box" block the array is looked up to
decide to which "template_box" its required to jump.  If the value is -1,
we have reached the last block.

Note, that array must be reinitilized every time the function is invoked
and the referenced template file was changed on disk.

The values of the array should really be offsets into the generated
code, but since the sizes of the code to generate "template_box" tags
are variable, another array of the same size compiled into function body
should record the offset to beginning of each block.  Leaving the last
template_box block is equivalent to implementation of "leave part" code.

The advantages of this design is that no changes need to be done to .page
instructions (text, text_input) etc. It is also better because printing
is done into the output stream, and not into strings.  Thus, there is
no danger of creating a very large string that would take a lot of memory.

Any tips on writing such meta are appreciated.
                                                                     
Message posted by maybe Hubert Tonneau on 2007/05/13 08:46:51
There is both a scalability and latency issue with your design if the server has
to store all the content of the answer before final processing it then sending
it instead of sending it on the fly.
It is the way the Pliant HTTP server worked in it's early days.

My point of view is that the protocol has to be light on server side so that
server scalability be maximal. Remember that a server has to service many
clients, and nowdays a server is not significantly more powerfull than a client
so it's important than normal usage of the application don't bring significant
computation constrain on the server.
My personal explaination about the success of HTML/Javascript over native
graphical toolkit for remote mainly database services is that it's easy to
build a toolkit for any plateform and it can be light on the server side.
Remember: the key difference between HTML and native graphical toolkits is that
in HTML, the client computes the positions which can be just as expensive as
rendering and cannot be hardware accelerated.

So, my conclusion, also it may not fit others wishes, usage field and expierence,
was that a three tiers system is better:
. the server uses a light clean protocol to send to the proxy, so that it will
  waste no time, and avoid most memory exhaused issues
. the poxy deals with all computations to switch from clean protocol to what the
  final client expects
This is the way the new HTTP server is led. At beginning I thought that having
a proxy to convert Pliant UI clean protocol to HTML/Javascript would be more
restrictive that having the server provide directly produce HTML/Javascript,
but I changed my mind after experimenting.

The way designers currently work is, from my point of view, amateuristic (not
professional). I mean it is nearly granted that any significant application
will not work with all browsers in the future AND that what will need to be
upgraded all the time will be spread over the all code. The fact that they
don't know how to work properly, mostly because of using too poor tools, does
not mean that it's a good way to work.

Message posted by maybe Boris Reitman on 2007/05/13 10:24:14
My last design has no memory footprint -- I am printing/generating on the fly.
Read my second message.  The whole idea is to order the execution of code blocks
in to the order in which corresponding template placeholders 
appear in the template.

So, for a template of the form:

mytemplate.html:
..html1...
%%place_holder_A%%
..html2...
%%place_holder_C%%
..html3...
%%place_holder_B%%

Suppose we have three page functions: 
write_content_for_A
write_content_for_B   
write_content_for_C
each emitting lots of text

Then, the following code will apply data to the template, without any memory
overhead:

var List:Str htmlparts := load_and_split_template "mytemplate1.html"

write htmlparts:0
write_content_for_A
write htmlparts:1
write_content_for_B
write htmlparts:2
write_contetn_for_C

The problem is that I need to know that placeholder_C comes before placeholder_B
in the template, so I need to invoke write_content_for_C before write_content_for_B,
in the code.  I want to remove the need to know this information by writing a meta
that will turn the following code into the one above:

template "mytemplate1.html" 
  section "placeholder_A"
    write_content_for_A
  section "placeholder_B"
    write_content_for_B
  section "placehoder_C"
    write_content_for_C

(i used syntax "section" instead "template_box" since it is a more 
intuitive name)

The template meta will detect that C comes before B, and will reorder B and C
section blocks.  It is easy to reorder them at compile time, by just switching the blocks
around, but this way the system will not respond at runtime to updates 
to mytemplate1.html file. Therefore the reordering must be done with jump table and 
setting instruction:jump member properly.

Message posted by maybe Hubert Tonneau on 2007/05/13 12:56:03
Now I understand what you want to do.

It's fairly simple with Pliant:
You will execute your .page, but each section will record a Pliant delayed
action (Pliant lazy evaluation mechanism),
then you start copying your template to the client, and tigger each delayed
action execution when you find the corresponding keyword.
Message posted by maybe Boris Reitman on 2007/05/14 20:10:43
Here's what I got:

http://aristotle.hypervolume.com/~boris/pliant/boris.reitman/template/template.pli
http://aristotle.hypervolume.com/~boris/pliant/boris.reitman/template/t/010_template_basic.pli

The compile error message:
http://aristotle.hypervolume.com/~boris/pliant/boris.reitman/template/error.txt

The error happens at the "e freeze" line.

Note: I would like to get the template code to work with Stream first,
so that I can test it.  And then, with HtmlPage. And I want to have both options
available, because sometimes I need to render templates not in .page mode 
(when generating email, for example).  

Thanks,
Boris
Message posted by maybe Hubert Tonneau on 2007/05/14 22:19:30
That's fairly simple. Each time you ask Pliant to freeze some expression
(create a DelayedAction object that will later be restarted) all local variables
used in the body will be copied.
Some kind of variables must not be copied but rather passed by address. So are
Stream.
In your code, you force 'context' to be by address, but your Stream is named
'stream', so Pliant just reminds you that your 'stream' variable has 'Stream'
data type and 'Stream' data type has a flag set that says that it's instances
must not be copied.
Message posted by maybe  on 2007/05/15 09:06:28
Ok, it works. I updated the template.pli at above URL, and wrote this test too:

http://aristotle.hypervolume.com/~boris/pliant/boris.reitman/template/t/010_template_basic.pli

Thanks for your help,
Boris
Message posted by maybe Boris Reitman on 2007/05/18 09:07:38
I have a question about thread safety and memory usage.
Here is the scenario:

I have added a feature to the template code to parse tags of the form:
<TEMPLATE NAME="name">value</TEMPLATE>
The value is available by calling get_template_value. For example, 

----8<-------
function dostuff
  ...
  implicit stream
    template "A <TEMPLATE NAME=[dq]xxx[dq]>yyy</TEMPLATE> B"
      template_section "xxx"
        var Str value := get_template_value  # returns "yyy"
        ...
        #dostuff  # call again
--->8--------

I would ideally want to allocate template_value on the heap, since I want it to 
be different at runtime, but to have one actions dictionary per function 
definition, so that recursively calling a function doesn't allocate Dictionaries.

How do I create a C-like "static" dictionary initialized lexically, once per
block (the "template" block) ?

If I allocate template_value on the heap, whats the best way to pass it to 
freezed actions ? Like the page/stream object ?

To understand why I would want to call dostuff recursively, here is how I am 
using the template meta to slurp an SSI file and allow inplace editting of each 
included subfile:

-----------8<----------
method page insert_editable_ filename depth
  arg_rw HtmlPage page
  arg Int depth ; arg Str filename
  implicit page
    if depth > 10
      text "ERROR: looks like cyclic recursion (too deep): "+filename ; eol
      return
    var Str data := slurp_text_file filename
    var Bool is_block := data:len > 10
    css class "editable_area" block is_block style "background: "+(shunt depth%2=0 "#eee" "#ccc")
      if data<>""
        var Str space0 space1 include include_type
        while (data eparse any "<!--#include" spaces:space0 any:include_type "=[dq]" any:include "[dq]" spaces:space1 "-->" any)
          var Str match := "<!--#include"+space0+include_type+"=[dq]"+include+"[dq]"+space1+"-->"
          var Str new_filename
          if include:0 = "/" and include_type = "virtual"
            new_filename := get_apache_site_dir + include
          else
            new_filename := dirname:filename + "/" + include
          data := replace data match "<TEMPLATE NAME=[dq]ssi_include[dq]>"+new_filename+"</TEMPLATE>"
        template data
          template_section "ssi_include"
            insert_editable_ get_template_value depth+1
      else
        bold
          text "EMPTY"
      css class "edit_icon" block false
        icon "/images/edit.gif"
          edit_filename filename
----------->8----------

Once again, the code is here:

http://aristotle.hypervolume.com/~boris/pliant/boris.reitman/template/

Thanks,
Boris
Message posted by maybe Hubert Tonneau on 2007/05/29 09:21:14
> How do I create a C-like "static" dictionary initialized lexically, once per
> block (the "template" block) ?

I don't understand what C feature you are expecting.
Pliant is very similar to C: either the variable is local to the function, or
it is global.

If you want to avoid copying a large data structure over and over, I would
suggest keeping track of the changes instead, so that you can reverse the
changes when you leave a bloc.
See /pliant/protocol/http/stack.pli
The TagStack data structure is used to efficiently keep track of each styling
attribute in the Pliant old HTTP server styling engine.
As an example, if we have something like
font face "Helvetica"
  body
then when executing 'body', we need to be abble to query what is the current
'face' value.

Basically, we have an array specifying current value for each index (each named
is mapped to an index, offset, or whatever you prefer to call it), and we have
a list of transitions.
Each time we enter a block, we had a mark tag to the transitions list.
Each time we modify an entry, we fist copy the old value in the list.
Each time we leave a block, we read the list blackward up to the mark to restore
modified values.
Message posted by maybe Boris Reitman on 2007/05/29 21:11:26
I guess, the only way to do what I want is to have the "template" meta
propagate some information to nested template_section meta.

gvar Link:Argument current_actions old_actions
meta template e
  old_actions :> current_actions
  current_actions :> argument local Link:(Dictionary Str DelayedAction)
  # suckup children
  # call generate_template function passing current_actions and template string as args
  current_actons :> old_actions

meta template_section e
  # record delayed action into current_actions local variable

This way i still allocate a dictionary for each instance, but there are no thread
safety issues i have to handle.  

If this code: 

    template "... %%A%% ... %%B%% ..."
      template_section "B"
        text "bye"
      template_section "A"
        text "hi"

Is converted to:

    var Int offset := 0
    while offset < template:len
      var Str token := get_next_token template offset
      if token = "%%B%%"
        text "bye"
      eif token = "%%A%%"
        text "hi"
      else
        text token
      offset += token:len

There are no allocation issues at all and no thread safety issues.

  
Message posted by maybe Hubert Tonneau on 2007/05/29 21:40:04
I say it again: if you want more efficiency, you need to write your extended
dictionary data structure with backtracking capabilities.
Message posted by maybe Boris Reitman on 2007/06/02 16:33:33
My last message didn't post somehow. I have updated the code to a propecly 
working version:

http://aristotle.hypervolume.com/~boris/pliant/boris.reitman/template/