<commit_before># ParsePage
ParsePage is a template parser engine, good for web development

## Languages supported
- [PHP](php)
- [.NET](dot.net)
- [Javascript](js) (limited features for now)
- Perl

## Overview

When you create a website you have to generate html code for the client's browser. There are many ways how to do that, but one of the best practices is to separate _code_, _data_ and _design_. It works as: _data_ stored in some database, _code_ read it, combine with _design_ and output to browser. Something like that implemented in modern MVC web frameworks.

Separating _design_ from _code_ and _data_ can be done using _templates_. Therefore each html page generated for browser should be created with one or more templates.

Websites contains many pages, but usually most of pages have same layout (i.e. top nav, aside nav, main content area, footer).

**Core idea of ParsePage templates** is to have main page template and then build final page from sub-templates stored in directory specific for particular page. This is a bit different approach from what other template engines offer.

Templates contains special tags `<~tag>`, which replaced by actual data passed to ParsePage engine or by content of other templates (i.e. templates may include other templates).

TODO - add image here how templates works

## Sample

### Sample main template:

_/page_tpl.html_
```html
<!DOCTYPE html>
<html lang="en"><head></head>
<body>
  <h1><~title></h1>
  <~main>
  <footer>site footer<footer>
</body>
</html>
```

### Sub-templates for test page:

_/test/title.html_
```html
Test page header
```

_/test/main.html_
```html
<p><~data></p>
<p><~more_data></p>
```

### Sample code.
This will load `page_tpl.html` layout and insert/parse sub-templates from `/test` directory, then output to browser;
```php
$ps=array(
  'data' => 'Hello World!',
  'more_data' => 12345,
);
parse_page('/test', '/page_tpl.html', $ps);
```

## Documentation

### /template directory structure

All templates should be placed under single directory accessible by website code, we name it `/template` (relative to website root).
Sample stucture:
```
page_tpl.html  - main template for website pages
page_tpl_print.html - main template for printed pages
page_tpl_layout2.html - main template for website pages with layout 2
common/ - directory with common sub-templates
home/ - directory with sub-templates for website Home page
contact/ - directory with sub-templates for website Contact page
```

### Code

Generally ParsePage called as following (depending on language syntax will differ):

`parse_page(BASE_DIR, PAGE_TPL_FILE, PS, [OUTPUT_FILENAME])`

where:
- `BASE_DIR` - directory (relative to /template) with sub-templates for current page
- `PAGE_TPL_FILE` - path (relative to /template) to main page template/layout used for current page
- `PS` - "parse strings" - associative array (hashtable) with variable names/values to be replaced in templates
- `OUTPUT_FILENAME` - optional, output file name, if defined ParsePage will write output to this file, instead of output to browser

### Tag syntax

Tags in templates should be in `<~tag_name [optional attributes]>` format.

`tag_name` could be:

- **name of the variable** passed to ParsePage engine. In this case ParsePage replace tag with variable value (optionally processed according attributes).
  - if variable is an array/hashtable squares can be used to get particular keys/index - `<~var[aaa][0][bbb]>`
  - if no variable with such name passed ParsePage will look for sub-template file with such name (see below)
- **path to sub-template**. In this case ParsePage will look for sub-template file, parse it recursively and replace tag with parsed content
  - if no file found tag repalced with empty string
  - path can be:
    - `tag_name` - will look for `tag_name.html` in `BASE_DIR` (i.e. default sub-template extension is `html`)
    - `tag_name.ext` - will look for `tag_name.ext` in `BASE_DIR`
    - `./tag_name` - (relative path) will look for `tag_name.html` in directory relative to currently parsed template file (see samples)
    - `/subdir/tag_name` - (absolute path) will look for `/subdir/tag_name.html` relative to `/template` directory

Note, CSRF shield integrated - all vars escaped, if var shouldn't be escaped use `noescape` attr: `<~raw_variable noescape>`

### Supported attributes

- `var` - tag is variable, no fileseek necessary even if no such variable passed to ParsePage: `<~tag var>`
- `ifXX` - if confitions, if false - tag replaced with empty string
  - `<~tag ifeq="var" value="XXX">` - tag/template will be parsed only if var=XXX
  - `<~tag ifne="var" value="XXX">` - tag/template will be parsed only if var!=XXX
  - `<~tag ifgt="var" value="XXX">` - tag/template will be parsed only if var>XXX
  - `<~tag ifge="var" value="XXX">` - tag/template will be parsed only if var>=XXX
  - `<~tag iflt="var" value="XXX">` - tag/template will be parsed only if var<XXX
  - `<~tag ifle="var" value="XXX">` - tag/template will be parsed only if var<=XXX
- `vvalue` - used with `ifXX` conditions to indicate that value to compare should be read from PS variable
  - `<~tag ifeq="var" vvalue="var2">` - tag parsed if PS['var']==PS['var2']
- `if`
    - `<~tag if="var">` - tag parsed if var is evaluated as TRUE, equivalent to `if ($var)`
- `unless`
    - `<~tag unless="var">` - tag parsed if var is evaluated as TRUE, equivalent to `if (!$var)`
    - TRUE values:
      - non-empty string, but not equal to '0'!
      - 1 or other non-zero number
      - true (boolean)
    - FALSE values:
      - '0'
      - 0
      - false (boolean)
      - ''
      - unset/undefined variable
- `repeat` - this tag is repeat content (PS should contain reference to array of hashtables),
  - `<~tag repeat inline>repeated sub-template content</~tag>` - inline sample
  - inside repeat sub-template supported repeat vars:
    - repeat.first (0-not first, 1-first)
    - repeat.last  (0-not last, 1-last)
    - repeat.total (total number of items)
    - repeat.index  (0-based)
    - repeat.iteration (1-based)
- `sub` - this tag tells parser to use sub-hashtable for parse sub-template (PS variable should contain reference to hashtable)
- `inline` - this tag tells parser that sub-template is not in file - it's between <~tag>...</~tag> , useful in combination with 'repeat' and 'if'
- `parent` - this tag need to be read from paren't PS var, not in current PS hashtable (usually used inside `repeat` sub-templates)
- `select="var"` - this tag tells parser to load file with tag name and use it as value|display for <select> html tag, example:

     <select name="item[fcombo]">
     <option value=""> - select -
     <~./fcombo.sel select="fcombo">
     </select>

- `radio="var" name="YYY" [delim="ZZZ"]` - this tag tell parser to load file and use it as value|display for <input type=radio> html tags, example: `<~fradio.sel radio="fradio" name="item[fradio]" delim="&nbsp;">`
- `selvalue="var"` - display value (fetched from the tag name file) for the var (example: to display 'select' and 'radio' values in List view), example: `<~fcombo.sel selvalue="fcombo">`
- `htmlescape` - replace special symbols by their html equivalents (such as <>,",'). This attribute is applied automatically to all tags by default.
- `noescape` - will not apply htmlescape to tag value
- `date` - will format tag value as date, format depends on language: (PHP)[http://php.net/manual/en/function.date.php], (ASP.NET)[https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.80).aspx]
  - `<~tag date>` or `<~tag date="d M Y H:i">`
- `truncate` - truncates a variable to a character length (default 80), optionally - append trchar if truncated, truncate at word boundary (trword), truncate at end or in the middle (trend)
  - `<~tag truncate="80" trchar="..." trword="1" trend="1">` - default values
- `strip_tags` - remove any html tags from value
- `trim` - remove leading and trailing space from value<commit_msg>minor doc fix<commit_after># ParsePage
ParsePage is a template parser engine, good for web development

## Languages supported
- [PHP](php)
- [.NET](dot.net)
- [Javascript](js) (limited features for now)
- Perl

## Overview

When you create a website you have to generate html code for the client's browser. There are many ways how to do that, but one of the best practices is to separate _code_, _data_ and _design_. It works as: _data_ stored in some database, _code_ read it, combine with _design_ and output to browser. Something like that implemented in modern MVC web frameworks.

Separating _design_ from _code_ and _data_ can be done using _templates_. Therefore each html page generated for browser should be created with one or more templates.

Websites contains many pages, but usually most of pages have same layout (i.e. top nav, aside nav, main content area, footer).

**Core idea of ParsePage templates** is to have main page template and then build final page from sub-templates stored in directory specific for particular page. This is a bit different approach from what other template engines offer.

Templates contains special tags `<~tag>`, which replaced by actual data passed to ParsePage engine or by content of other templates (i.e. templates may include other templates).

TODO - add image here how templates works

## Sample

### Sample main template:

_/page_tpl.html_
```html
<!DOCTYPE html>
<html lang="en"><head></head>
<body>
  <h1><~title></h1>
  <~main>
  <footer>site footer<footer>
</body>
</html>
```

### Sub-templates for test page:

_/test/title.html_
```html
Test page header
```

_/test/main.html_
```html
<p><~data></p>
<p><~more_data></p>
```

### Sample code.
This will load `page_tpl.html` layout and insert/parse sub-templates from `/test` directory, then output to browser;
```php
$ps=array(
  'data' => 'Hello World!',
  'more_data' => 12345,
);
parse_page('/test', '/page_tpl.html', $ps);
```

## Documentation

### /template directory structure

All templates should be placed under single directory accessible by website code, we name it `/template` (relative to website root).
Sample stucture:
```
page_tpl.html  - main template for website pages
page_tpl_print.html - main template for printed pages
page_tpl_layout2.html - main template for website pages with layout 2
common/ - directory with common sub-templates
home/ - directory with sub-templates for website Home page
contact/ - directory with sub-templates for website Contact page
```

### Code

Generally ParsePage called as following (depending on language syntax will differ):

`parse_page(BASE_DIR, PAGE_TPL_FILE, PS, [OUTPUT_FILENAME])`

where:
- `BASE_DIR` - directory (relative to /template) with sub-templates for current page
- `PAGE_TPL_FILE` - path (relative to /template) to main page template/layout used for current page
- `PS` - "parse strings" - associative array (hashtable) with variable names/values to be replaced in templates
- `OUTPUT_FILENAME` - optional, output file name, if defined ParsePage will write output to this file, instead of output to browser

### Tag syntax

Tags in templates should be in `<~tag_name [optional attributes]>` format.

`tag_name` could be:

- **name of the variable** passed to ParsePage engine. In this case ParsePage replace tag with variable value (optionally processed according attributes).
  - if variable is an array/hashtable squares can be used to get particular keys/index - `<~var[aaa][0][bbb]>`
  - if no variable with such name passed ParsePage will look for sub-template file with such name (see below)
- **path to sub-template**. In this case ParsePage will look for sub-template file, parse it recursively and replace tag with parsed content
  - if no file found tag repalced with empty string
  - path can be:
    - `tag_name` - will look for `tag_name.html` in `BASE_DIR` (i.e. default sub-template extension is `html`)
    - `tag_name.ext` - will look for `tag_name.ext` in `BASE_DIR`
    - `./tag_name` - (relative path) will look for `tag_name.html` in directory relative to currently parsed template file (see samples)
    - `/subdir/tag_name` - (absolute path) will look for `/subdir/tag_name.html` relative to `/template` directory

Note, CSRF shield integrated - all vars escaped, if var shouldn't be escaped use `noescape` attr: `<~raw_variable noescape>`

### Supported attributes

- `var` - tag is variable, no fileseek necessary even if no such variable passed to ParsePage: `<~tag var>`
- `ifXX` - if confitions, if false - tag replaced with empty string
  - `<~tag ifeq="var" value="XXX">` - tag/template will be parsed only if var=XXX
  - `<~tag ifne="var" value="XXX">` - tag/template will be parsed only if var!=XXX
  - `<~tag ifgt="var" value="XXX">` - tag/template will be parsed only if var>XXX
  - `<~tag ifge="var" value="XXX">` - tag/template will be parsed only if var>=XXX
  - `<~tag iflt="var" value="XXX">` - tag/template will be parsed only if var<XXX
  - `<~tag ifle="var" value="XXX">` - tag/template will be parsed only if var<=XXX
- `vvalue` - used with `ifXX` conditions to indicate that value to compare should be read from PS variable
  - `<~tag ifeq="var" vvalue="var2">` - tag parsed if PS['var']==PS['var2']
- `if`
    - `<~tag if="var">` - tag parsed if var is evaluated as TRUE, equivalent to `if ($var)`
- `unless`
    - `<~tag unless="var">` - tag parsed if var is evaluated as TRUE, equivalent to `if (!$var)`
    - TRUE values:
      - non-empty string, but not equal to '0'!
      - 1 or other non-zero number
      - true (boolean)
    - FALSE values:
      - '0'
      - 0
      - false (boolean)
      - ''
      - unset/undefined variable
- `repeat` - this tag is repeat content (PS should contain reference to array of hashtables),
  - `<~tag repeat inline>repeated sub-template content</~tag>` - inline sample
  - inside repeat sub-template supported repeat vars:
    - repeat.first (0-not first, 1-first)
    - repeat.last  (0-not last, 1-last)
    - repeat.total (total number of items)
    - repeat.index  (0-based)
    - repeat.iteration (1-based)
- `sub` - this tag tells parser to use sub-hashtable for parse sub-template (PS variable should contain reference to hashtable)
- `inline` - this tag tells parser that sub-template is not in file - it's between <~tag>...</~tag> , useful in combination with 'repeat' and 'if'
- `parent` - this tag need to be read from paren't PS var, not in current PS hashtable (usually used inside `repeat` sub-templates)
- `select="var"` - this tag tells parser to load file with tag name and use it as value|display for <select> html tag, example:

     <select name="item[fcombo]">
     <option value=""> - select -
     <~./fcombo.sel select="fcombo">
     </select>

- `radio="var" name="YYY" [delim="ZZZ"]` - this tag tell parser to load file and use it as value|display for <input type=radio> html tags, example: `<~fradio.sel radio="fradio" name="item[fradio]" delim="&nbsp;">`
- `selvalue="var"` - display value (fetched from the tag name file) for the var (example: to display 'select' and 'radio' values in List view), example: `<~fcombo.sel selvalue="fcombo">`
- `htmlescape` - replace special symbols by their html equivalents (such as <>,",'). This attribute is applied automatically to all tags by default.
- `noescape` - will not apply htmlescape to tag value
- `date` - will format tag value as date, format depends on language: [PHP](http://php.net/manual/en/function.date.php), [ASP.NET](https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.80).aspx)
  - `<~tag date>` or `<~tag date="d M Y H:i">`
- `truncate` - truncates a variable to a character length (default 80), optionally - append trchar if truncated, truncate at word boundary (trword), truncate at end or in the middle (trend)
  - `<~tag truncate="80" trchar="..." trword="1" trend="1">` - default values
- `strip_tags` - remove any html tags from value
- `trim` - remove leading and trailing space from value
{'fraction_non_alphanumeric': 0.11732194447933676, 'fraction_numerical': 0.004145207888456224, 'mean_word_length': 3.965076395385095, 'pattern_counts': {'":': 0, '<': 105, '<?xml version=': 0, '>': 109, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1902382', 'n_tokens_mistral': 4840, 'n_tokens_neox': 4698, 'n_words': 2033}