Html & Dom Builder

This is a convenience class to create XML and HTML element in an OO way.

DomElement

DomElement and DomElements is use to create XML elements.

use Windwalker\Dom\DomElement;

$attrs = array('id' => 'foo', 'class' => 'bar');

echo $dom = (string) new DomElement('field', 'Content', $attrs);

Output:

<field id="foo" class="bar">Content</field>

Add Children

use Windwalker\Dom\DomElement;

$attrs = array('id' => 'foo', 'class' => 'bar');

$content = array(
    new DomElement('option', 'Yes', array('value' => 1)),
    new DomElement('option', 'No', array('value' => 0))
);

echo $dom = (string) new DomElement('field', $content, $attrs);

The output will be:

<field id="foo" class="bar">
    <option value="1">Yes</option>
    <option value="0">No</option>
</field>

HtmlElement

HtmlElement is use to create HTML elements, some specific tags will force to unpaired.

use Windwalker\Dom\HtmlElement;

$attrs = array(
    'class' => 'btn btn-mini',
    'onclick' => 'return false;'
);

$html = (string) new HtmlElement('button', 'Click', $attrs);

Then we will get this HTML:

<button class="btn btn-mini" onclick="return false;">Click</button>

Get Attributes by Array Access

$class = $html['class'];

DomElements & HtmlElements

It is a collection of HtmlElement set.

$html = new HtmlElements(
    array(
        new HtmlElement('p', $content, $attrs),
        new HtmlElement('div', $content, $attrs),
        new HtmlElement('a', $content, $attrs)
    )
);

echo $html;

OR we can iterate it:

foreach ($html as $element)
{
    echo $element;
}

Attributes

$html = new HtmlElement('input', array(
    'data-string' => 'string',
    'data-empty' => '',
    'data-true'  => true,
    'data-false' => false,
    'data-null'  => null,

    // Special attributes
    'checked'    => 'checked',
    'disabled'   => true,
    'readonly'   => false
));

echo $html;

Result

<input data-string="string" data-empty="" data-true checked="checked" disabled="disabled">

Formatter

DomFormatter and HtmlFormatter will help us format XML / HTML string.

$xml = '<field id="foo" class="bar"><option value="1">Yes</option><option value="0">No</option></field>';

DomFormatter::format($xml);

Result

<field id="foo" class="bar">
    <option value="1">Yes</option>
    <option value="0">No</option>
</field>

HtmlFormatter will convert some tags to unpaired element, e.g. <img>.

Select List

use Windwalker\Html\Select\SelectList;
use Windwalker\Html\Option;

$select = new SelectList(
    'form[timezone]',
    array(
        new Option('Asia - Tokyo', 'Asia/Tokyo', array('class' => 'opt')),
        new Option('Asia - Taipei', 'Asia/Taipei'),
        new Option('Europe - Paris', 'Asia/Paris'),
        new Option('UTC', 'UTC'),
    ),
    array('class' => 'input-select'),
    'UTC',
    false
);

echo $select;

The result:

<select class="input-select" name="form[timezone]">
    <option class="opt" value="Asia/Tokyo">Asia - Tokyo</option>
    <option value="Asia/Taipei">Asia - Taipei</option>
    <option value="Asia/Paris">Europe - Paris</option>
    <option value="UTC" selected="selected">UTC</option>
</select>

Group Select

Use two level array to make options grouped.

use Windwalker\Html\Select\CheckboxList;

$select = new SelectList(
    'form[timezone]',
    array(
        'Asia' => array(
            new Option('Tokyo', 'Asia/Tokyo', array('class' => 'opt')),
            new Option('Taipei', 'Asia/Taipei')
        ),
        'Europe' => array(
            new Option('Europe - Paris', 'Asia/Paris')
        )
        ,
        new Option('UTC', 'UTC'),
    ),
    array('class' => 'input-select'),
    'UTC',
    false
);

echo $select;

The result

<select class="input-select" name="form[timezone]">
    <optgroup label="Asia">
        <option class="opt" value="Asia/Tokyo">Tokyo</option>
        <option value="Asia/Taipei">Taipei</option>
    </optgroup>

    <optgroup label="Europe">
        <option value="Asia/Paris">Europe - Paris</option>
    </optgroup>

    <option value="UTC" selected="selected">UTC</option>
</select>

Input List

CheckboxList

$select = new CheckboxList(
    'form[timezone]',
    array(
        new Option('Asia - Tokyo', 'Asia/Tokyo', array('class' => 'opt')),
        new Option('Asia - Taipei', 'Asia/Taipei'),
        new Option('Europe - Paris', 'Asia/Paris'),
        new Option('UTC', 'UTC'),
    ),
    array('class' => 'input-select'),
    'UTC',
    false
);

echo $select;

The result

<span class="checkbox-inputs input-select">
    <input class="opt" value="Asia/Tokyo" type="checkbox" name="form[timezone][]" id="form-timezone-asia-tokyo" />
    <label class="opt" id="form-timezone-asia-tokyo-label" for="form-timezone-asia-tokyo">Asia - Tokyo</label>

    <input value="Asia/Taipei" type="checkbox" name="form[timezone][]" id="form-timezone-asia-taipei" />
    <label id="form-timezone-asia-taipei-label" for="form-timezone-asia-taipei">Asia - Taipei</label>

    <input value="Asia/Paris" type="checkbox" name="form[timezone][]" id="form-timezone-asia-paris" />
    <label id="form-timezone-asia-paris-label" for="form-timezone-asia-paris">Europe - Paris</label>

    <input value="UTC" checked="checked" type="checkbox" name="form[timezone][]" id="form-timezone-utc" />
    <label id="form-timezone-utc-label" for="form-timezone-utc">UTC</label>
</span>

If you want to use div to wrap all inputs instead span, set tag name to object.

$select->setName('div');

RadioList

Same as Checkboxes, but the input type will be type="radio"

Enumeration List

UL List

use Windwalker\Html\Enum\ListItem;
use Windwalker\Html\Enum\UList;

echo new UList([
    new ListItem('Foo'),
    new ListItem('Bar', ['class' => 'baz']),
]);

// OR

echo (new UList)
    ->item('new ListItem('Foo'))
    ->item('Bar', ['class' => 'baz']);

Output

<ul>
    <li>Foo</li>
    <li class="baz">Bar</li>
</ul>

OL List

echo (new OList)
    ->item('new ListItem('Foo'))
    ->item('Bar', ['class' => 'baz']);

Output

<ol>
    <li>Foo</li>
    <li class="baz">Bar</li>
</ol>

Description List

use Windwalker\Html\Enum\DList;
use Windwalker\Html\Enum\DListDescription;
use Windwalker\Html\Enum\DListTitle;

echo (new DList)
    ->addDescription('Foo', 'foo desc')
    ->addDescription('Bar', 'bar desc');

// OR

echo (new DList)
    ->title('Foo')->desc('foo desc')
    ->title('Bar')->desc('bar desc');

// OR

echo (new DList)
    ->item(new DListTitle('Foo'))->item(new DListDescription('foo desc'))
    ->item(new DListTitle('Bar'))->item(new DListDescription('bar desc'));

Output

<dl>
    <dt>Foo</dt>
    <dd>foo desc</dd>

    <dt>Bar</dt>
    <dd>bar desc</dd>
</dl>

Form Wrapper

use Windwalker\Html\Form\FormWrapper;
use Windwalker\Html\Form\InputElement;

echo FormWrapper::create([
    new InputElement('hidden', 'id'),
    new InputElement('text', 'title'),
], ['action' => 'http://foo.com']);

Output:

<form action="http://foo.com">
    <input type="hidden" name="id" value="" />
    <input type="text" name="title" value="" />
</form>

Use start() and end()

echo FormWrapper::start('my-form', 'post', 'http://foo.com', FormWrapper::ENCTYPE_FORM_DATA, ['id' => 'admin-form']);
    // Echo inputs
echo FormWrapper::end();

Output:

<form name="my-form" id="admin-form" method="post" action="http://foo.com" enctype="multipart/form-data">
    <!-- inputs -->
</form>

Add CSRF token automatically:

$token = MySession::getFormToken();

FormWrapper::setTokenHandler(function () use ($token)
{
    return new InputElement('hidden', $token, 1);
});

echo FormWrapper::start('my-form', 'post', 'http://foo.com', FormWrapper::ENCTYPE_FORM_DATA, ['id' => 'admin-form']);
echo FormWrapper::end();

Output:

<form name="my-form" id="admin-form" method="post" action="http://foo.com" enctype="multipart/form-data">
    <!-- inputs -->
    <input type="hidden" name="e6900955e2cb8d2503f663e85eb2e7e9" value="1" />
</form>

Table Generator

Grid

Grid is a HTML table generator, see this example:

use Windwalker\Html\Grid\Grid;

$grid = new Grid(['class' => 'table table-bordered']);

// Pre-set table columns and give them a name.
$grid->setColumns(['a', 'b', 'c']);

// Create first TR row, set it as <thead>
$grid->addRow(['class' => 'head'], Grid::ROW_HEAD);

// Set <th> value
$grid->setRowCell('a', 'A');
$grid->setRowCell('b', 'B');
$grid->setRowCell('c', 'C');

// Loop 3 rows
foreach (range(1, 3) as $i)
{
    // Add a TR with class row-x
    $grid->addRow(['class' => 'row-' . $i]);

    // Set every <td> value
    $grid->setRowCell('a', 'a1');
    $grid->setRowCell('b', 'b1');
    $grid->setRowCell('c', 'c1');
}

// Add <tfoot>
$grid->addRow(['class' => 'foot'], Grid::ROW_FOOT);
$grid->setRowCell('a', 'Table footer', ['colspan' => 3]);

echo $grid;

Output:

<table class="table table-bordered">
    <thead>
        <tr class="head">
            <th>A</th>
            <th>B</th>
            <th>C</th>
        </tr>
    </thead>
    <tbody>
        <tr class="row-1">
            <td>a1</td>
            <td>b1</td>
            <td>c1</td>
        </tr>
        <tr class="row-2">
            <td>a1</td>
            <td>b1</td>
            <td>c1</td>
        </tr>
        <tr class="row-3">
            <td>a1</td>
            <td>b1</td>
            <td>c1</td>
        </tr>
    </tbody>
    <tfoot>
        <tr class="foot">
            <td colspan="3">Table footer</td>
        </tr>
    </tfoot>
</table>
A B C
a1 b1 c1
a1 b1 c1
a1 b1 c1
Table footer

KeyValue Grid

KeyValueGrid provides simple key-value table to show data similar to description list.

use Windwalker\Html\Grid\KeyValueGrid;

$items = [
    'Foo' => 'foo value',
    'Bar' => 'bar value',
    'Yoo' => 'yoo value',
];

$grid = new KeyValueGrid;

$grid->addHeader('Key', 'Value');

foreach ($items as $key => $value)
{
    $grid->addItem($key, $value);
}

echo $grid;
Key Value
Foo foo value
Bar bar value
Yoo yoo value

Add row title:

$items = [
    'Foo' => 'foo value',
    'Bar' => 'bar value',
    'Yoo' => 'yoo value',
];

$grid = new KeyValueGrid;

$grid->addHeader('Key', 'Value');

// Add a row title
$grid->addTitle('This is a subtitle');

foreach ($items as $key => $value)
{
    $grid->addItem($key, $value);
}

// Add a row title
$grid->addTitle('This is another subtitle');

foreach ($items as $key => $value)
{
    $grid->addItem($key, $value);
}

echo $grid;
Key Value
This is a subtitle
Foo foo value
Bar bar value
Yoo yoo value
This is another subtitle
Foo foo value
Bar bar value
Yoo yoo value

Use addItems() or configure() to batch add items.

$grid->addItems($items);

// Or run a callback for every item
$grid->configure($items, function (KeyValueGrid $grid, $key, $value)
{
    if ($value)
    {
        $grid->addItem($key, $value);
    }
});

Media Elements

Audio

use Windwalker\Html\Media\Audio;

echo (new Audio)
    ->controls(true)
    ->autoplay(true)
    ->loop(true)
    ->setNoSupportHint('Your browser do not support this format')
    ->addMp3Source('http://foo.com/bar.mp3')
    ->addOggSource('http://foo.com/bar.ogg')
    ->addWavSource('http://foo.com/bar.wav');

Output:


<audio controls autoplay loop>
    <source src="http://foo.com/bar.mp3" type="audio/mpeg" />
    <source src="http://foo.com/bar.ogg" type="audio/ogg" />
    <source src="http://foo.com/bar.wav" type="audio/wav" />
    Your browser do not support this format
</audio>

See HTML5 Audio Tag and Tag Source

Video

use Windwalker\Html\Media\Video;

echo (new Video)
    ->controls(true)
    ->autoplay(true)
    ->loop(true)
    ->preload(true)
    ->poster('http://foo.com/cover.jpg')
    ->setNoSupportHint('Your browser do not support this format')
    ->setMainSource('http://foo.com/bar.mp4')
    ->addMp4Source('http://foo.com/bar.mp4')
    ->addOggSource('http://foo.com/bar.ogg')
    ->addWebMSource('http://foo.com/bar.webm');

Output:

<video controls autoplay loop preload poster="http://foo.com/cover.jpg" src="http://foo.com/bar.mp4">
    <source src="http://foo.com/bar.mp4" type="video/mp4" />
    <source src="http://foo.com/bar.ogg" type="video/ogg" />
    <source src="http://foo.com/bar.webm" type="video/webm" />
    Your browser do not support this format
</video>

See HTML5 Video Tag and Tag Source

HtmlHelper

Repair Tags

We can using repair() method to repair unpaired tags by php tidy, if tidy extension not exists, will using simple tag close function to fix it.

$html = '<p>foo</i>';

$html = \Windwalker\Html\Helper\HtmlHelper::repair($html);

echo $html; // <p>foo</p>

Get JS Object

This method convert a nested array or object to JSON format that you can inject it to JS code.

use Windwalker\Html\Helper\HtmlHelper;

$option = array(
    'url' => 'http://foo.com',
    'foo' => array('bar', 'yoo')
);

echo 'var options = ' . HtmlHelper::getJSOBject($option);

Result

var options = {
    url: "http://foo.com",
    foo: ["bar", "yoo"]
}

Add \\ before a value that this method will not quote it as string.

$option = array(
    'callback' => '\\function () { }'
);

echo 'var options = ' . HtmlHelper::getJSOBject($option);

Result

var options = {
    callback: function () { }
}

XmlHelper

XmlHelper using on get attributes of SimpleXmlElement.

Get Attributes

use Windwalker\Dom\SimpleXml\XmlHelper;

$xml = <<<XML
<root>
    <field name="foo" type="bar" readonly="true">
        <option></option>
    </field>
</root>
XML;

$xml = simple_xml_load_string($xml);

$element = $xml->xpath('field');

$name = XmlHelper::getAttribute($element, 'name'); // result: foo

// Same as get()
$name = XmlHelper::get($element, 'name'); // result: foo

Get Boolean

getBool() can help us convert some string link true, 1, yes to boolean TRUE and no, false, disabled, null, none, 0 string to booleand FALSE.

$bool = XmlHelper::getBool($element, 'readonly'); // result: (boolean) TRUE

Get False

Just an alias of getBool() but FALSE will return TRUE.

Set Default

If this attribute not exists, use this value as default, or we use original value from xml.

XmlHelper::def($element, 'class', 'input');

If you found a typo or error, please help us improve this document.