Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/eftec/bladeonehtml

BladeOne HTML Extension
https://github.com/eftec/bladeonehtml

html-css php-library template-engine views

Last synced: 3 months ago
JSON representation

BladeOne HTML Extension

Awesome Lists containing this project

README

        

# BladeOneHtml
It is a PHP library that allows to create forms (view) easily, cleanly and without killing the performance. It uses the library BladeOne to renders the view. This library only uses a single dependency, one file and nothing more.

This library works in two ways:

* It compiles a script (our view that use our tags), in a native PHP code.
* And the next read, if the script exists, then it uses it (instead of re-compiling). And since the script is native code, then it is exactly like to work in vanilla-php,
but it is way easy to write and to maintenance.

[![Packagist](https://img.shields.io/packagist/v/eftec/bladeonehtml.svg)](https://packagist.org/packages/eftec/bladeonehtml)
[![Total Downloads](https://poser.pugx.org/eftec/bladeonehtml/downloads)](https://packagist.org/packages/eftec/bladeonehtml)
[![Maintenance](https://img.shields.io/maintenance/yes/2024.svg)]()
[![composer](https://img.shields.io/badge/composer-%3E1.6-blue.svg)]()
[![php](https://img.shields.io/badge/php-7.4-green.svg)]()
[![php](https://img.shields.io/badge/php-8.0-green.svg)]()
[![php](https://img.shields.io/badge/php-8.1-green.svg)]()
[![CocoaPods](https://img.shields.io/badge/docs-71%25-yellow.svg)]()

* [BladeOneHtml](#bladeonehtml)
* [Usage](#usage)
* [Template basic](#template-basic)
* [Template usage](#template-usage)
* [input](#input)
* [hidden](#hidden)
* [label](#label)
* [image](#image)
* [select](#select)
* [item](#item)
* [items](#items)
* [optgroup](#optgroup)
* [checkbox](#checkbox)
* [radio](#radio)
* [textarea](#textarea)
* [button](#button)
* [link](#link)
* [checkboxes](#checkboxes)
* [radios](#radios)
* [file](#file)
* [ul](#ul)
* [ol](#ol)
* [pagination](#pagination)
* [table](#table)
* [tablehead](#tablehead)
* [tablebody](#tablebody)
* [tablefooter](#tablefooter)
* [tablerows](#tablerows)
* [cells](#cells)
* [cssbox](#cssbox)
* [How to add a new css into the cssbox?](#how-to-add-a-new-css-into-the-cssbox)
* [jsbox](#jsbox)
* [How to add a new JavaScript into the cssbox?](#how-to-add-a-new-javascript-into-the-cssbox)
* [jscodebox](#jscodebox)
* [Template Customization](#template-customization)
* [Set a default class](#set-a-default-class)
* [Set a custom pattern](#set-a-custom-pattern)
* [Pattern-Variables inside the code](#pattern-variables-inside-the-code)
* [Custom attribute](#custom-attribute)
* [Methods](#methods)
* [useBootstrap5](#usebootstrap5)
* [Note: If we want to use the css box, then we need to add to our view the next code](#note-if-we-want-to-use-the-css-box-then-we-need-to-add-to-our-view-the-next-code)
* [useBootstrap4](#usebootstrap4)
* [Note: If we want to use the css box, then we need to add to our view the next code](#note-if-we-want-to-use-the-css-box-then-we-need-to-add-to-our-view-the-next-code-1)
* [useBootstrap3](#usebootstrap3)
* [addCss](#addcss)
* [addJS](#addjs)
* [addJSCode](#addjscode)
* [Public Fields](#public-fields)
* [$pattern](#pattern)
* [$defaultClass](#defaultclass)
* [$customAttr](#customattr)
* [Creating a new pattern](#creating-a-new-pattern)
* [1- Adding a new pattern](#1--adding-a-new-pattern)
* [2- Creating a new method](#2--creating-a-new-method)
* [3- Creating a new parent Method (container method)](#3--creating-a-new-parent-method-container-method)
* [4- Advanced](#4--advanced-)
* [Version history](#version-history)

## Usage

1. This library requires eftec/bladeone. You could install via Composer in the root folder of your project as

> composer require eftec/bladeonehtml

2. And you should extend the class as follows (BladeOneHtml is a Trait)

```php
include "vendor/autoload.php";

use eftec\bladeone\BladeOne;
use eftec\bladeonehtml\BladeOneHtml;

class myBlade extends BladeOne {
use BladeOneHtml;
}

$blade=new myBlade();

// for our example:
$myvalue=@$_REQUEST['myform'];
echo $blade->run("exampleview", ['myvalue'=>$myvalue]);
```

3. Create a folders called 📁 "\views" and 📁 "\compiles"
4. Inside views, creates the next file 📄 "\views\exampleview.blade.php"

```html

@form()
@input(type="text" name="myform" value=$myvalue)
@button(type="submit" value="Send")
@endform()

```

$blade=new myBlade();

![](docs/img1.jpg)

## Template basic

This library adds a new set of tags for the template. The tags uses named arguments, so it is easily configurable.

> @<tag>(argument1="value" argument2='value' argument3=value argument4=$variable argument5=function(), argument6="aaa $aaa")

This library uses the native html arguments but some arguments are special

| Argument | Description | example |
|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|
| text | It adds a content between the tags. **The inner value is always un-quoted.** | @tag(text="hello") -> <tag>hello</tag> |
| pre | It adds a content before the tag | @tag(pre="hello") -> hello<tag></tag> |
| post | It adds a content after the tag | @tag(post="hello") -> <tag></tag>hello |
| between | It adds a content between the tags (it works similar than text) | @tag(between="hello") -> <tag>hello</tag> |
| value | Usually it works as the normal "**value**" of html but it also could works differently (in @textarea works like **text**) | @tag(value="hello") -> < tag value="hello"></tag> |
| values | Some components needs a list of object/arrays. This argument is used to sets the list of values | @tag(values=$countries) |
| alias | Some components needs or use a list of object/array. This argument is to reference any row inside the list. If **values** is set and **alias** is missing, then it creates a new alias called values+"Row". | @tag($values=$countries alias=$country)
@tag($values=$countries ) **it asumes alias=$countriesRow** |
| optgroup | The tag @select could list grouped elements. This argument is used to set the grouping | @tag($values=$countries alias=$country @optgroup=$country->continent) |

Let's say the next example

```
@input(value="hello world" type="text" )
```

It is rendered as

```

```

If the tag uses a variable of function, then this view

```
@input(value=$hello type="text" )
```

Is converted into

``` // the

```

The method $this->e is used to escape the method.

> Note: This library allows any tag, even custom tags (but only if they don't enter in conflict with the special tags, see table)
>
> @input(value="hello world" type="text" mycustomtag="hi" )
>
> Is converted into
````html

````

## Template usage

### input

It shows an input HTML.

Basic example:

```html
@input(id="id1" value="hello world$somevar" type="text" )
```

![](docs/input_label.jpg)

### hidden

It generates a hidden field

Basic example:

```
@hidden(name="id1" value="hello world$somevar" )
```

### label

It shows a label html

```html
@label(for="id1" text="hello world:")
```

![](docs/input_label.jpg)

### image

It shows an image

```
@image(src="https://via.placeholder.com/350x150")
```

![](docs/image.jpg)

### select

It shows a select (dropdown list) html object

Example:

```
@select(id="aaa" value=$selection values=$countries alias=$country)
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@items( id="chkx" value=$country->id text=$country->name)
@endselect
```

> Note 1: @items requires the arguments values in the parent (@select) and the arguments **value** (the selectable value) and **text** (the visible value)
> Note 2: @items requires an **id**, assigned in the same tag or in the parent tag (in this case, the parent is @select)
> Note 3: By standard, the argument **id** must be unique.

![](docs/select.jpg)

### item

**@item** is a utility tag used inside other tags. This behaves depending on of their parent tag. It adds a simple
line/row to the parent object.

Example:

```
@select()
@item(value='aaa' text='hello world')
@endselect

```

It renders

```

hello world

```

### items

**@items** is a utilitarian tag used inside some tags. This behaves depending on of their parent tag. It adds a
multiples lines/rows to the parent object using the tag **values**

> Note: This tag requires some arguments:
>
> * the parent(or this tag) requires the tag **values**
> * the parent requires the tag **value** It indicates the current selection (if any)
> * the parent(or this tag) requires the tag **alias** If alias is missing then it uses the name of values + "Row", i.e. values=product -> alias= productRow
> * the parent(or this tag) requires the tag **id**
> * The rendered "id" will be generated using this id+"_"+"id of the row". i.e. id="idproduct" => idproduct_0, idproduct_1
> * Why? It is because the id must be unique (html specs)

Example, if $countries is a list of objects then :

```
@select(id="aaa" value=$selection values=$countries alias=$country)
@items( id="chkx" value=$country->id text=$country->name)
@endselect
```

If $countries is a list of arrays then:

```
@select(id="aaa" value=$selection values=$countries alias=$country)
@items( id="chkx" value=$country['id'] text=$country['name'])
@endselect
```

Inside the tag items, you could use the next variables

| variable (where values is the variable used) | Specification |
|----------------------------------------------------------|-----------------------------------------------------------------------|
| **$values**OptGroup | It stores the current optgroup (if any). Example: $productOptGroup |
| **$values**Key | It indicates the current key of the current row. Example: $productKey |
| $alias (if not alias is set then it uses **$values**Row) | The current row of the variable. Example: $productRow |

### optgroup

It starts an optional group (select)

Example:

```
@select(id="aaa" value=$selection values=$countries alias=$country)
@optgroup(label="group1")
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@endoptgroup
@endselect
```

> Note: this tag must be ended with the tag @endoptgroup

![](docs/optgroup.jpg)

### checkbox

It adds a single checkbox

Example:

```
@checkbox(id="idsimple" value="1" checked="1" post="it is a selection")
```

![](docs/checkbox.jpg)

### radio

It adds a single radio button

Example:

```
@radio(id="idsimple" value="1" checked="1" post="it is a selection")
```

![](docs/radio.jpg)

### textarea

It draws a text area.

Example:

```
@textarea(id="aaa" value="3333 3333 aaa3333 ")
```

![](docs/textarea.jpg)

### button

It draws a button

Example:

```
@button(value="click me" type="submit" class="test" onclick='alert("ok")')
```

![](docs/button.jpg)

### link

It adds a hyperlink

Example:

```
@link(href="https://www.google.cl" text="context")
```

![](docs/link.jpg)

### checkboxes

It shows a list of checkboxes

```
@checkboxes(id="checkbox1" value=$selection alias=$country)
@item(id="aa1" value='aaa' text='hello world' post="
")
@item(id="aa2" value='aaa' text='hello world2' post="
")
@items(values=$countries value='id' text='name' post="
")
@endcheckboxes
```

![](docs/checkbox.jpg)

### radios

It shows a list of radio buttons

```
@radios(id="radios1" name="aaa" value=$selection alias=$country)
@item(value='aaa' text='hello world' post="
")
@item(value='aaa' text='hello world2' post="
")
@items(values=$countries value='id' text='name' post="
")
@endradios
```

![](docs/radio.jpg)

### file

It generates a file input value

```
@file(name="file" value="123.jpg" post="hello world")
```

> Note: it also renders a hidden file with name "name"+"_file" with the original value

![](docs/file.jpg)

### ul

It generates an unsorted list

```
@ul(id="aaa" value=$selection values=$countries alias=$country)
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@items(value=$country->id text=$country->name)
@endul
```

![](docs/ul.jpg)

### ol

It generates a sorted list

```
@ol(id="aaa" value=$selection values=$countries alias=$country)
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@item(value='aaa' text='hello world')
@items(value=$country->id text=$country->name)
@endol
```

![](docs/ol.jpg)

### pagination

It generates a pagination. It requires bootstrap3, bootstrap4 or bootstrap5.

You can find an example at [examples/examplepagination.php](examples/examplepagination.php)

PHP code

```php
$current=isset($_GET['_page']) ? $_GET['_page'] : 1;
echo $blade->run("examplepagination",
['totalpages'=>count($products)
,'current'=>$current
,'pagesize'=>10
,'products'=>$items
]);
```

Template

```html
@pagination(numpages=$totalpages current=$current pagesize=$pagesize urlparam='_page')
```

> Note: The page is base 1.
> Note: the argument urlparam is used to build the link (domain.dom/web.php?_page=999)

You can change the name of the buttons **prev** and **next** as follows:

```php
$this->setTranslation(['pagination'=>['prev'=>'<<>','next'=>'>']]);
```

![](docs/pagination.jpg)

### table

It renders a table

```
@table(class="table" values=$countries alias=$country border="1")
@tablehead
@cell(text="id")
@cell(text="cod")
@cell(text="name")
@endtablehead
@tablebody(id='hello world' )
@tablerows(style="background-color:azure")
@cell(text=$country->id style="background-color:orange")
@cell(text=$country->cod )
@cell(text=$country->name)
@endtablerows
@endtablebody
@tablefooter
@cell(text="id" colspan="3")
@endtablefooter
@endtable
```

![](docs/table.jpg)

#### tablehead

It renders the header of the table (optional). Each cell added inside it, is rendered as "th" HTML tag

#### tablebody

It renders the body of the table (optional). Each cell added inside the table is rendered as "td" HTML tag

#### tablefooter

It renders the footer of the table (optional). Each cell added inside it, is rendered as "th" HTML tag

#### tablerows

It generates a row inside the body

#### cells

It renders a cell inside the tablehead,tablebody (tablerows) or tablefooter

### cssbox

It renders and css added into the box

```html

@cssbox

```

#### How to add a new css into the cssbox?

Using the method addCss($css,$name)

```php
$this->addCss('','mystyle');
$this->addCss('css/stylename.css');
```

**$css** could be a link or a link tag

**$name** is optional but it avoids to add duplicates. If we add a new CSS with the same name as
a previous one, then it is ignored.

### jsbox

It renders all JavaScript links added to the box

```html


@jsbox

```

#### How to add a new JavaScript into the cssbox?

Using the method addJs($script,$name)

```php
$this->addJs('','jquery');
```

### jscodebox

```html


@jsbox
@jscodebox(ready)

```

This code adds the tags < script > automatically.

The argument **ready** indicates if we want to execute the function when the document is ready.

How to add a new JavaScript code into the **jscodebox**?

```php
$blade->addJsCode('alert("hello");');
```

## Template Customization

**BladeOneHtml** allows to modify the tags used and to set a default classes for each class.

You can set a default class and tags for Bootstrap 3/4/5 using the next method (pick only one).

```php
// if true then it loads the css and js from a cdn into the css and jsbox so it requires @cssbox and @jsbox
$blade->useBootstrap5(true);
// if true then it loads the css and js from a cdn into the css and jsbox so it requires @cssbox and @jsbox
$blade->useBootstrap4(true);
// if true then it loads the css and js from a cdn into the css and jsbox so it requires @cssbox and @jsbox
$blade->useBootstrap3(true);
```

Or you could create your own tags and classes

### Set a default class

```php
$blade->defaultClass[$tagname]='default class';
```

### Set a custom pattern

```php
$blade->pattern['nametag']='pattern';
```

Where nametag could be as follows

| Name | Description | Example | Code |
|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|------------------------------------------------------|
| nametag | It uses the pattern to use when the tag is used | input | {{pre}}{{between}}< /input>{{post}} |
| nametag_empty | The system uses this pattern if the content (between/text) is empty or not set (a self close tag). If not set, then the system uses **nametag** even if the content is empty | input_empty | {{pre}}< input{{inner}} />{{post}} |
| nametag_item | The system uses this pattern for tags @item and @items | select_item | < option{{inner}} >{{between}}< /option> |
| nametag_end | It uses this pattern when the tag must be closed | form_end | < /form> |

#### Pattern-Variables inside the code

| variable | explanation | Escaped (*) |
|-------------|--------------------------------------------------------------------------------------|-------------------------------------------------------------------|
| {{pre}} | The code before the tag : **pre** <tag ></tag> | no |
| {{post}} | The code after the tag : < tag ></tag> **post** | no |
| {{inner}} | The attributes inside the tag : < tag **inside** > </tag> | yes |
| {{between}} | The content between the tag : < tag >**between**</tag> | By default this value is escaped
but it could be un-escaped |
| {{id}} | The id attribute (it is also included in {{inner}}): < tag **id** > </tag> | yes |
| {{name}} | The name attribute (it is also included in {{inner}}): < tag **name** > </tag> | yes |

Example of a normal tag:

```php
$blade->pattern['input']='{{pre}}{{between}}{{post}}';
```

> Note :(*) What is escaped?. For example the text "", if it escaped, it is displayed as "&lt;hello&gt;"

#### Custom attribute

It is possible to add a custom attribute that it could be used inside a pattern.

For example, let's add the custom tag called **customtag**

```php
$blade->customAttr['customtag']='This attr is missing!';
$blade->pattern['alert']='{{pre}}


{{customtag}}

{{between}}
{{post}}';
```

And in the view

```html
@alert(text="hi there" class="alert-danger" customtag="it is a custom tag")

@alert(text="hi there" class="alert-danger" )

```

## Methods

The library has a lit of methods that they could be used to initialize and configure the library. They are optionals.

### useBootstrap5

It sets the patterns and classes to be compatible with bootstrap 4.

if argument is true, then it adds the CSS to the **css box** from the CDN

Our code

```php
$blade->useBootstrap5(true);
```

#### Note: If we want to use the css box, then we need to add to our view the next code

```html

@cssbox

```

### useBootstrap4

It sets the patterns and classes to be compatible with bootstrap 4.

if argument is true, then it adds the CSS to the **css box** from the CDN

Our code

```php
$blade->useBootstrap4(true);
```

#### Note: If we want to use the css box, then we need to add to our view the next code

```html

@cssbox

```

### useBootstrap3

It sets the patterns and classes to be compatible with bootstrap 3.

if argument is true, then it adds the CSS to the **css box** from the CDN

```php
$blade->useBootstrap3(true);
```

### addCss

It adds a CSS to the **css box**

```php
$this->addCss('css/datepicker.css','datepicker');
```

### addJS

It adds a javascript link to the **js box**

```php
$this->addJs('','jquery');
```

### addJSCode

It adds a javascript code to the **js box**

```php
$blade->addJsCode('alert("hello");');
```

## Public Fields

It is the list of public fields of the class. The fields are public because for performance purpose (versus to use setter and getters)

### $pattern

It stores the list of patterns used by the code

```php
$this->pattern['sometag']='{{pre}}{{between}}{{post}}';

```

> Note: see "Pattern-Variable inside the code" to see the list of pattern-variables

### $defaultClass

The default CSS class added to a specific tag.

```php
$this->defaultClass['sometag']='classred classbackgroundblue';
```

### $customAttr

It adds a custom adds that it could be used together with $this->pattern

```php
$this->customAttr['customtag']='XXXXX'; // So we could use the tag {{customtag}}. 'XXXXX' is the default value
```

> The custom attribute always removes the quotes and double quotes, so if our value is "hello" -> hello

## Creating a new pattern

It is possible to add a new pattern by extending the PHP class.

#### 1- Adding a new pattern

```
$this->pattern['mynewtag']='{{between}}';
```

#### 2- Creating a new method

You could create a new PHP class or trait and extend our class. Inside this new structure, you must add a new method with the next structure

Using a new class

```php
use eftec\bladeone\BladeOne;
use eftec\bladeonehtml\BladeOneHtml;

class MyBlade extends BladeOne {
use BladeOneHtml;
}
class MyClass extends MyBlade {
protected function compileMyNewTag($expression) { // the method must be called "compile" + your name of tag.
$args = $this->getArgs($expression); // it separates the values of the tags
$result = ['', '', '', '']; // inner, between, pre, post
// your custom code here
return $this->render($args, 'mynewtag', $result); // we should indicate to use our pattern.
}
}
```

Using a trait (recommended, why? It is because trait are more flexible)

```php
trait MyTrait {
protected function compileMyNewTag($expression) { // the method must be called "compile" + your name of tag.
$args = $this->getArgs($expression); // it separates the values of the tags
$result = ['', '', '', '']; // inner, between, pre, post
// your custom code here
return $this->render($args, 'mynewtag', $result); // we should indicate to use our pattern.
}
}

class MyClass extends BladeOne {
use BladeOneHtml;
use MyTrait; // <-- our trait
}
```

#### 3- Creating a new parent Method (container method)

For creating a parent method, you must push a new value inside $this->htmlItem. You can store whatever you want to.

```php
$this->pattern['mynewtag']='{{between}}';
```

```php
protected function compileMyNewTag($expression) {
$args = $this->getArgs($expression); // it loads and separates the arguments.
$this->htmlItem[] = ['type' => 'mynewtag','value' => @$args['value']
];
$result = ['', '', '', '']; // inner, between, pre, post
//unset($args['value']); // we could unset values that we don't want to be rendered.
return $this->render($args, 'select', $result);
}

```

> Our objective is to render PHP code, not to evaluate a code. For example, if $args['somearg']=$variable, then our value is $variable (as text), no matter the real value of the variable.

You must also create a method to end the container, and we must also add a new pattern.

```php
$this->pattern['mynewtag_end']='';
```

```php
protected function compileEndNewTag() {
$parent = @\array_pop($this->htmlItem); // remove the element from the stack
if (\is_null($parent) || $parent['type']!=='newtag') { // if no element in the stack or it's a wrong one then error
$this->showError("@endnewtag", "Missing @initial tag", true);
}
// our code
return $this->pattern[$parent['type'] . '_end']; // renders the element of the stack
}
```

Our items could know if they are inside a tag with the next operation

```php
$parent = \end($this->htmlItem);
```

#### 4- Advanced

We could create a component that requires CSS and JavaScript.

For example a date picker.

```php
protected function compileDatePicker($expression) {
$args = $this->getArgs($expression); // it loads and separates the arguments.
\array_push($this->htmlItem, ['type' => 'mynewtag','value' => @$args['value']]);
$result = ['', '', '', '']; // inner, between, pre, post
if(!isset($args['id'])) {
$this->showError("@datepicker", "Missing @id tag", true);
}
$this->addJs('','jquery'); // our script needs jquery (if it is not loaded)
$this->addCss('css/datepicker.css','datepicker');
$this->addjscode('$(.'.$args['id'].').datepicker();');

//unset($args['value']); // we could unset values that we don't want to be rendered.
return $this->render($args, 'select', $result);
}
```

> Note: It's better to add the library of jQuery and date picker once in our code

## Version history
* 2.4 2024-03-02
* Updating dependency to PHP 7.4. The extended support of PHP 7.2 ended 3 years ago.
* Added more type hinting in the code
* 2.3.2 2023-01-31
* a typo in pagination
* 2.3.1 2023-01-31
* fixed a problem with pagination.
* some cleanups
* update dependencies.
* 2.3 2022-02-04
* Now this library is compatible with PHP 7.2 and higher.
* Some cleanups and type hinting (return methods)
* 2.2 2021-12-11
* fixed a problem with optgroup and when the argument is an associative array.
* 2.1 2021-10-01
* Added support for Bootstrap 5.0
* Updated Bootstrap CDNs
* added tags @container, @row, @col
* 2.0 2021-09-24
* Dropped support for PHP 5.x. Updated support for BladeOne 4.0
* 1.8.1 2021/07/03
* It solves a problem when the argument is defined as id="somevalue$id"
* 1.8 2021/06/09
* @checkbox and @radio now works with variables. The element is checked only if the value is not null, empty or zero.
* 1.7.1 2021/02/06
* @item now marks the value "checked" or "selected" if the values is equals to the current value of the parent object
* Bootstrap 4 **CDN** now it uses the version 4.6
* for @item and @items, the field name and **idname** are created automatically. If id is set, then it uses it.
* 1.7 2021/01/12
* @button now considers value as the value of argument while text the visual content.
* It also uses in_array instead of isset().
* Compatible with PHP 8.x
* 1.6.1 2020/08/31
* Pagination now it has "first" and "last" buttons.
* 1.6 2020/08/30
* Added tag @pagination
* Added the method setTranslationControl() and getTranslationControl()
* 1.5 2020/06/07
* Added a new optional argument to processArgs() and render();
* Added unit test.
* 1.4 2020/05/02
* now it allows empty arguments. It requires BladeOne 3.43 or higher.
* added unit test.
* 1.3 2020/04/22
* added method useBootstrap3()
* added default class for textarea in useBootstrap4()
* 1.2 2020/04/21
* tag @@alert()
* fixed: @@items() now it keeps the selection
* tag @@cssbox, @@jsbox and @jscodebox
* method useBootstrap4($cdn=false) has a new argument
* 1.1 2020/04/21
* Method isVariablePHP() moved to BladeOne
* Update LICENSE.
* Added more documentation.
* 1.0 2020-04-20 First version