Git Product home page Git Product logo

twital's Introduction

Build Status Scrutinizer Quality Score Code Coverage GitHub license Packagist

What is Twital?

Twital is a template engine built on top of Twig (a template engine for PHP and default template engine on Symfomy) that adds some shortcuts and makes Twig's syntax more suitable for HTML based (XML, HTML5, XHTML, SGML) templates. Twital takes inspiration from PHPTal, TAL and AngularJS or Vue.js (just for some aspects), mixing their language syntaxes with the powerful Twig templating engine system.

Twital is fully compatible with Twig, all Twig templates can be rendered using Twital.

To better understand the Twital's benefits, consider the following Twital template, which simply shows a list of users from an array:

<ul t:if="users">
    <li t:for="user in users">
        {{ user.name }}
    </li>
</ul>

To do the same thing using Twig, you need:

{% if users %}
    <ul>
        {% for user in users %}
            <li>
                {{ user.name }}
            </li>
        {% endfor %}
    </ul>
{% endif %}

As you can see, the Twital template is more readable, less verbose and and you don't have to worry about opening and closing block instructions (they are inherited from the HTML structure).

One of the main advantages of Twital is the implicit presence of control statements, which makes templates more readable and less verbose. Furthermore, it has all Twig functionalities, such as template inheritance, translations, looping, filtering, escaping, etc.

If some Twig functionality is not directly available for Twital, you can freely mix Twig and Twital syntaxes.

In the example below, we have mixed Twital and Twig syntaxes to use Twig custom tags:

<h1 t:if="users">
    {% custom_tag %}
        {{ someUnsafeVariable }}
    {% endcustom_tag %}
</h1>

When needed, you can extend from a Twig template:

<t:extends from="layout.twig">
    
    <t:block name="content">
        Hello {{name}}!
    </t:block>
    
</t:extends>

You can also extend from Twig a Twital template:

{% extends "layout.twital" %}
    
{% block content %}
    Hello {{name}}!
{% endblock %}
    

A presentation of Twital features and advantages is available on this presentation.

Installation

The recommended ways install Twital is via Composer.

composer require goetas/twital

Documentation

Go here http://twital.readthedocs.org/ to read a more detailed documentation about Twital.

Getting started

First, you have to create a file that contains your template (named for example demo.twital.html):

<div t:if="name">
    Hello {{ name }}
</div>

Afterwards, you have to create a PHP script that instantiate the required objects:

require_once '/path/to/composer/vendor/autoload.php';
use Goetas\Twital\TwitalLoader;

$fileLoader = new Twig_Loader_Filesystem('/path/to/templates');
$twitalLoader = new TwitalLoader($fileLoader);

$twig = new Twig_Environment($twitalLoader);
echo $twig->render('demo.twital.html', array('name' => 'John'));

That's it!

Symfony Users

If you are a Symfony user, you can add Twital to your project using the TwitalBundle.

The bundle integrates all most common functionalities as Assetic, Forms, Translations, Routing, etc.

Twig Users

Starting from version Twital 1.0.0, both twig 1.x and 2.x versions are supported.

Note

The code in this project is provided under the MIT license. For professional support contact [email protected] or visit https://www.goetas.com

twital's People

Contributors

goetas avatar hason avatar lyrixx avatar pborreli avatar petrhanak avatar soukicz avatar stof avatar tzi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

twital's Issues

Request new Release w/ updated deps (masterminds/html5)

Hi, we are using this library to produce templated PDF files from HTML through Snappy.
HTML parsing takes double the time than generation of the PDF itself.

As there are quite a few performance improvements in masterminds/html5, can we get a new release with updated dependencies, at least masterminds/html5? Or were any incompatibilities introduced?

Missing SourceEvent

I have noticed unknown SourceEvent in src/Goetas/Twital/EventSubscriber/CustomNamespaceSubscriber.php

Maybe missing use Goetas\Twital\EventDispatcher\SourceEvent;?

Append/Prepend Options For t:block

Hello! I really enjoy what you've done here.

I'm in the process of re-doing a very large commercial CMS system with twig. After finding twital, -- I'm going to switch it to twital as well so we can begin taking advantage of it's features as well.

One thing I plan on forking/adding is a way to prepend/append to <t:block's, -- I've always thought the {{ parent() }} call was so ugly. If you aren't interested in a feature, -- no worries, I'll maintain my own fork.

However, if you are, ... do you have any suggestions for the syntax? It'll be later this week before I can get to it, but looking at the twital code it should be just a few lines.

It could be a few different ways: ... <t:block name="foo" type="append"> ... <t:blockappend name="foo"> ... or my favorite <t:block append="foo"> with the attributes of replace="name", prepend="name" and append="name" ...

What do you think?

edit: totally missed a sentence

Unnecessary escaping in attributes

I am trying to migrate templates from Twig to Twital and there is problem with this code:

(autoescaping is on)

<img src="{%if true%}/a/x.jpg{%endif%}">

Expected result:

<img src="/a/x.jpg">

Actual result:

<img src="%2Fa%2Fx.jpg">

I could rewrite code but it would be much more practical if it could be compatible with Twig.

Infinite loop with FixHtmlEntitiesInExpressionSubscriber

I was using version 0.1.8 and I was using this test with FixHtmlEntitiesInExpressionSubscriber:

<!-- input -->
<div><img src="{{ true ? "/b/x.jpg"}}"></div>

<!-- expected -->
<div><img src="/b/x.jpg"></div>

It work fine with 0.1.8 but after upgrading to 0.1.9 or 1.0.0. this code stucks Twital in infinite loop (probably).

Removed empty attribute

Twital is removing empty attributes which is fine for most elements except OPTION. IE9 will use option text as value if there is missing value attribute.

$twigLoader = new Goetas\Twital\TwitalLoader(new \Twig_Loader_String());
$twigLoader->addSourceAdapter('/.*/', new Goetas\Twital\SourceAdapter\HTML5Adapter());
$twig = new Twig_Environment($twigLoader);

$source = <<<EOT
<select name="my">
<option value="">XXX</option>
<option value="1">first</option>
</select>
EOT;

print_r($twig->loadTemplate($source)->render([]));

Expected output:

<select name="my">
<option value="">XXX</option>
<option value="1">first</option>
</select>
<!--  IE9 will send my=  (empty value) -->

Actual output:

<select name="my">
<option value>XXX</option>
<option value="1">first</option>
</select>
<!--  IE9 will send my=XXX -->

Twital not working within blocks

I started using twital because of its similarities to phptal.
But it seems not to work in Blocks.

Blockcode:

{% block textelement %}
<div class="form-group {{fiel.getAttributeByName('groupclass') | default(NULL)}}">
    <label for="" class="control-label">{{fiel.label |raw}} <span t:if="fiel.validation">*</span></label>
    <div t:if="fiel.errors" t:for="item fiel.errors">
        <span>{{item |raw}}</span>
    </div>
    {{fiel.generateElement() |raw}}
</div>
{% endblock textelement %}

The normal TWIG works, but the Twital elements (t:if, t:for) not.
I tried to implemente the template several ways but it wont work. Any ideas?

I need to render the blocks seperatly and use this code:
$tpl = $this->twig->load($tpl); $res = $tpl->renderBlock($block, array_merge($this->vars, $vars));

Any ideas whats wrong?

HTML5SourceAdapter ignores Doctype definition

<!DOCTYPE html>
<html>
  <head>
    <title>My Webpage</title>
  </head>
  <body>foo</body>
</html>

is transformed to

<html>
  <head>
    <title>My Webpage</title>
  </head>
  <body>foo</body>
</html>

Documentation for t:content ?

I use t:content attribute here and there, but I really can not see documentation for it. Is use of t:content discouraged?

Attributes are duplicated multiple nodes

There is very specific case when attributes from two nodes are merged together. Interesting is that if you remove div with class xxx, it will start working again.

My code:

$twigLoader = new Goetas\Twital\TwitalLoader(new \Twig_Loader_String()); //new \TwitalLoader(new \Twig_Loader_String());
$twigLoader->addSourceAdapter('/.*/', new Goetas\Twital\SourceAdapter\HTML5Adapter());
$twig = new Twig_Environment($twigLoader, ['cache' => false, 'autoescape' => true]);

$source = <<<EOT
                   <t:omit> <ol style="opc">
            <li t:attr="true ? style='display:none'"></li>
        </ol>
        <div class="xxx"> <span class="abc">yyy</span></div>

        <div class='qqq'>
            <input type='checkbox' t:attr="true ? checked='checked'">

        </div>
        </t:omit>
EOT;

print_r($twig->loadTemplate($source)->render([]));

Expected result:

<ol style="opc">
            <li style="display:none"></li>
        </ol>
        <div class="xxx"> <span class="abc">yyy</span></div>

        <div class="qqq">
            <input type="checkbox" checked="checked">

        </div>

Actual result:

<ol style="opc">
            <li style="display:none"></li>
        </ol>
        <div class="xxx"> <span class="abc">yyy</span></div>

        <div class="qqq">
            <input type="checkbox" style="display:none" checked="checked">

        </div>

Both LI and INPUT have display:none but it was defined only for LI.

I looked into php cache of template file a there is the same key used for both nodes (__a9000000006d37f06100007f887925bc9c). My guess is that problem is in spl_object_hash which is used for keys:
When an object is destroyed, its hash may be reused for other objects.
https://php.net/spl_object_hash

Support for Twig 3.x

The documentation does not say whether Twig 3.x is supported.

Therefore: Is Twig 3.x supported in Twital?

Question: own twig-functions don´t work

<div t:for="i in range(0, 3)">
{{ i }},
</div>

This code runs perfectly, but my own twig-functions over twig extensions not.
At twig self my functions works also perfectly.

<small>
	{{ Datetime(activity.created_date) }}
</small>

This code makes under twital the follow error:
Fatal error: Uncaught Twig_Error_Syntax: Unknown "Datetime" function.

<small>
	Datetime(activity.created_date)
</small>

This code runs, but without any output.

What can i do to solve this problem ?

How to make an child template be valid XHTML

I'm looking at using Twital to implement the "page decorator"/layout pattern, as can be done in Thymeleaf with the Thymeleaf Layout Dialect.

"Template Inheritence" looks very similar to what I want (and at first glance I mistakenly thought it was exactly what I want.) What I'm looking for is for both the base template and the child template to be valid XHTML (or better yet valid HTML, as in Thymeleaf 3's Full HTML5 markup support

Is there a way to make a child template that is valid XHTML?

The <t:omit> node sometimes removes children (but not their children) with t:block=

The simplest way I can explain this is with the following tests (intended for CoreNodesTest.php around line 135-137):

// Passes, as you'd expect
array('<t:omit><div>foo</div><div>bar</div></t:omit>', '<div>foo</div><div>bar</div>'),
// Fails
array('<t:omit><div t:block="aaa">foo</div><div t:block="bbb">bar</div></t:omit>', '<div>{% block aaa %}foo{% endblock %}</div><div>{% block bbb %}bar{% endblock %}</div>'),
// Fails
array('<t:omit><div t:block="aaa"><h1>Hello, World!</h1><p>foo <em>bar</em></p></div><div t:block="bbb">bar</div></t:omit>', '<div>{% block aaa %}<h1>Hello, World!</h1><p>foo <em>bar</em></p>{% endblock %}</div><div>{% block bbb %}bar{% endblock %}</div>'),

The second test will fail when by all means it should pass. The third test/line input above, formatted:

<t:omit>
    <div t:block="aaa">
        <h1>Hello, World!</h1>
        <p>foo <em>bar</em></p>
    </div>
    <div t:block="bbb">
        bar
    </div>
</t:omit>

You would expect to be compiled to:

    <div>
    {% block aaa %}
        <h1>Hello, World!</h1>
        <p>foo <em>bar</em></p>
    {% endblock %}
    </div>
    <div>
    {% block bbb %}
        bar
    {% endblock% }
    </div>

Yet, instead, it results in something like:

    {% block aaa %}
        <h1>Hello, World!</h1>
        <p>foo <em>bar</em></p>
    {% endblock %}
    {% block bbb %}
        bar
    {% endblock% }

Basically, the tags directly below the <t:omit> is mysteriously removed when it also contains a t:block attribute (and, possibly others). In this example, it is of course the two <div> tags.

I am attempting to fix this --- wrapping it in an additional <t:omit> is a quick-fix/hack, but it's quite perplexing as to why it occurs in the first place.

From the other tests/examples, it certainly seems like this was not the intended behavior.

Any suggestions/hints?

Still cannot add attribute with no value.

As mentioned in #41 :

I configured the source adapter to use HTML5 as you suggested. However I still receive this error if I do not add a value to the "selected" attribute:
Type: Goetas\Twital\Exception Message: Goetas\Twital\Attribute\AttrAttribute::findAttrParts error in 'selected' File: /var/www/commlog_dev/vendor/goetas/twital/src/Goetas/Twital/Attribute/AttrAttribute.php Line: 108

This crashes: t:attr="language['code'] == userLang ? selected">
But this doesn't: t:attr="language['code'] == userLang ? selected='' ">
But I don't want the empty string.
Thank you for your time.

Error in HTML5Adapter?

For this template

{% block title "title" %}
<div>{% block title "title" %}</div>
<div name="{% block title "title" %}"></div>

only a HTML5Adapter returns partially wrong result

{% block title "title" %}
<div>{% block title &quot;title&quot; %}</div>
<div name="{% block title "title" %}"></div>

Add support fo JSX syntax and React components

We could make a listener for the HTML5 tags that start with an upper-case letter. For example

<CommentList />

should be replaced with

<div className="commentList">
    <Comment author="Pete Hunt">This is one comment</Comment>
    <Comment author="Jordan Walke">This is *another* comment</Comment>
</div>

and <Comment> with

<div className="comment">
    <h2 className="commentAuthor">{{ author }}</h2>
    {{ ... }}
</div>

Symfony 3 support

Is Symfony 3 supported? Is there any documentation on how to use Twital with Symfony 3?

Add attribute with no value?

I ran into an issue here:
<option t:for="language in languages" value="{{language['code']}}" t:attr="language['code'] == userLang ? selected='' ">{{language['name']}}</option>

How does one conditionally add a 'selected' attribute with no attribute value? Since that's how it's usually defined, by just existing, and not having any particular value.

If I use this:
t:attr="language['code'] == userLang ? selected
(no equals sign or value)
it crashes

and if I give it a null value selected=Null, it ends up giving it a zero length string in the tag like this:
selected=''

This is nit picky but I want to know if it's possible with just using Twital.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.