Perl templates with inheritance - perl

Exists in the Perl world any template system with template inheritance?
Just checked in the wikipedia Comparison_of_web_template_engines (really incomplete list) - and here isn't listed any.
Inheritance = Supports the ability to inherit a layout from a parent
template, separately overriding arbitrary sections of the parent
template's content.
Mean something like python's Jinja2:
#body.html
<body>
{% block content %}
<!-- the content go here -->
{% endblock %}
</body>
#hi.html
{% extends "body.html" %}
{% block content %}
<h1>Hi!</h1>
{% endblock %}
rendering hi.html gives
<body>
<h1>Hi!</h1>
</body>
Don't looking for exact Jinja2 syntax, simply looking for any template engine from the perl world what supports inheritance. (not only plain includes - like Template::Toolkit)
Asking here because searching CPAN is a pain for words like "template inheritance" - shows thousands modules what not related to this question.
Ps: ... and it shouldn't be something like embedded perl - should be "user editable" allowing users builds own templates without compromise a whole system - therefore can't use Mason or HTML::Mason)

I'll second the suggestion for Text::Xslate. Its syntax is even quite similar to your Jinja2 examples:
In layouts/main.tx:
...
<div id="page">
: block sidebar -> { }
<div id="content">
: block header-> { <h1>Default Title</h1> }
: block content -> { }
</div>
</div>
...
In another template:
: cascade layouts::main
: override header -> {
<div id="header">
...
</div>
: }
: override content -> {
<div id="content-body">
...
</div>
: }

A colleague recently started using Text::Xslate.

Template::Jade, a port of Jade to perl.
parent.jade
doctype html
html
head
title Jade template
body.class
p#id_name
block content
child.jade
extends parent
block content
p.
This is a test.
This is a test.
This is a test.

DTL::Fast Is my Perl implementation of Django templates with inheritance and other stuff.

Related

How to order Wagtail tags

I tried to create tags for my Posts as described in doc (tutorial My first website). But i need to show these tags in specific order. Is there some simple way or i just need to create own class with Orderable?
I have assumed you have gotten to this point in the docs - Tagging Posts and want to present the view of your BlogPage with the tags in a special order (eg. alphabetical). Orderable is if you want to do more complex admin interaction with InlinePanels and ordering of related models, where you are asking the page editor to order related items themselves.
The tutorial has this code for your template blog_page.html:
{% if page.tags.all.count %}
<div class="tags">
<h3>Tags</h3>
{% for tag in page.tags.all %}
<button type="button">{{ tag }}</button>
{% endfor %}
</div>
{% endif %}
To work with a custom ordering of your tags, you will need to set up a way to send your ordered tags to the template context. The easiest way to do this is to have a method added to your BlogPage model, we will call this get_ordered_tags.
class BlogPage(Page):
date = models.DateField("Post date")
# other fields...
def get_ordered_tags(self):
"""Specific ordered list of tags."""
# ordered_tags = self.tags.order_by('?') # order randomly
ordered_tags = self.tags.order_by('name') # order by tag name
return ordered_tags
Further up the page you would have seen the docs on Overriding Context, we will do something similar to add ordered_tags to our Page's context.
We can then easily make one minor change to our template, just replace:
{% for tag in page.tags.all %}
With:
{% for tag in page.get_ordered_tags %}
So instead of getting the tags in their default order, we are getting them in our specific order.

symfony2 twig form theme for different subsites

I've got a symfony2 application with multiple styles. All 3 have their own html + css for rendering.
Something like "frontsite", "user dashboard" and "admin backend".
Now there is a difference in form theme to be used in all 3 subsites, so there is a (slightly) different theme for all of them.
Because of this I can set the theme in the symfony configuration, but for 2 of the 3 subsites it will be wrong.
I can set a theme manually using:
{% form_theme form 'MyUberCoolBundle:Form:theme.html.twig' %}
But I don't really want to do that for every form.
I could set that in a base-template, but then my form would always need to be called "form".
Is there a way to set the theme to be used in a base template so it will be used for all forms?
I was looking for something like that. Something to use a theme for FrontOffice and another one to use in the back office.
I got it. I use a normal configuration in the config.yml as normal for the FrontOffice like that:
twig:
globals:
frontend_form_theme: 'form/fields.html.twig'
And then I use in the main BackOffice themplate like layout.html.twig:
{% if oForm is defined %} {% form_theme oForm 'bootstrap_3_layout.html.twig' %} {% endif %}
So, bootstrap defined for all the forms with the name oForm.
So the other answers here work great when your pages only have one form and it's always named something constant, like form. In my scenario, however, I often have multiple forms with different names, so that approach doesn't work. Instead, what I did was create a custom twig function that applies the desired form theme to all forms passed into to the view:
Inside your WhateverTwigExtension.php: (see here for info on writing twig extensions)
class WhateverTwigExtension extends AbstractExtension
{
private $formRenderer;
public function __construct(FormRendererInterface $formRenderer)
{
$this->formRenderer = $formRenderer;
}
public function getFunctions()
{
return [
new TwigFunction('applyFormThemes', [$this, 'applyFormThemes']),
];
}
public function applyFormThemes(array $context, $themes)
{
foreach ($context as $variable) {
if ($variable instanceof FormView) {
$this->formRenderer->setTheme($variable, $themes);
}
}
}
}
Note that for symfony's autowiring to be able to inject the renderer into this extension, you'll have to alias it, so put something like this in your services.yml:
services:
Symfony\Component\Form\FormRendererInterface: '#twig.form.renderer'
Finally, in the base twig for your subsite, simply add:
{{ applyFormThemes(_context, 'my_form_theme.html.twig') }}
Also works for multiple themes:
{{ applyFormThemes(_context, ['my_form_theme.html.twig', 'other_form_theme.html.twig']) }}
And now all forms passed to that view will have your theme applied!
You can also still use the normal form_theme tag to override specific forms, as long as it comes after the applyFormThemes
to set a theme global for your application you can set it in the config
twig:
form_themes:
# Default:
- form_div_layout.html.twig
# Bootstrap:
- bootstrap_3_layout.html.twig
- bootstrap_3_horizontal_layout.html.twig
# Example:
- MyBundle::form.html.twig
See the full Twig config reference here
After looking around for an answer I came to the conclusion it is not possible to do this only in configuration.
We resorted to the following solution
in config.yml we configured a global twig variable:
twig:
globals:
frontend_form_theme: 'MyUberCoolBundle:Form:theme.html.twig'
Then we set the correct theme on the form itself just prior to rendering using the global variable.
This even allows us to use something different when desired.
{% form_theme form frontend_form_theme %}
{{ form_start(form) }}
This is possible, and works well. It assumes you are consistent with naming your root forms however.
First, setup a default form theme like described in the standard docs.
# twig.yaml
twig:
form_themes: ['form.html.twig'] # Default theme and front-end
Override the form theme for the primary form in your admin layout template.
# admin/layout.html.twig
{% if form is defined %}
{% form_theme form "admin/_form.html.twig" %}
{% endif %}
{% block content %}{% endblock %}
...
Optionally override the admin form theme in your final templates, by setting the form theme in the form block. It won't work if you define form theme outside the block. Your custom form theme should probably extend the admin form theme too.
# admin/user/edit.html.twig
{% extends "admin/layout.html.twig" %}
{% block content %}
{% form_theme form "admin/user/_form.html.twig" %}
{{ form(form) }}
{% endblock %}

symfony2 twig form registration included from external template

Be patient is my first question and my english is also poor ;P
Btw... im using fos for my website and all work fine, actually my problem is that i have the "pages" template made with twig and it have, at the bottom, a call to action button that slideDown an hidden div where i want to put my registration form.
I setup the hidden div and try to put inside my include:
{% block fos_user_content %}
{% include "FOSUserBundle:Registration:register_content.html.twig" %}
{% endblock fos_user_content %}
obviously it dosn't work:
Variable "form" does not exist in kernel.root_dir/Resources/JuliusUserBundle/views/Registration/register_content.html.twig at line 2
probably for some reasons related to routing or firewall or security?
anyone have a solutions, suggestions or ideas for that?
thanks and cheers!
As error said, you need to define 'form' variable in your action, or you could try to render FOSUser registration action instead of this.
For example:
{% render(controller(FOSUserBundle:Registration:register")) %}
If you need to use include then you have to pass the form variable to your included template. Optionally you can render that template also from its corresponding controller.
So for the first case you have:
{% include("FOSUserBundle:Registration:register_content.html.twig") with {'form':form} %}
Where form here is the variable you pass from your own controller. Your second choice would be to render the FOSUB template like so:
{% render(controller("FOSUserBundle:Registration:register")) %}
Apparently i found a good solution using Edge Side Includes (ESI) includes that give me also additional benefits in cache control:
<esi:include src="http://localhost:8004/login" />

Formatting a blog post in Flask / WTForms / Google App Engine

Here's the question in brief:
My blog posts at...
http://www.seanbradley.biz/blog
...totally lacks formatting. They're just a big block of plaintext. Any code or HTML tags such as /n or < br / > ...let alone h1, h2, etc...have no demonstrable effect on the way text appears on the page.
I'm running Flask with WTForms deployed on GAE. How can I fix this? Is there a way to implement a WYSGIWYG editor--like TinyMCE--into the form field for new blog post entries?
I'm going for a look as simple and elegant as...
http://www.quietwrite.com
or
http://lucumr.pocoo.org/
...or at a minimum something akin to Stackoverflow's own editor.
Formatting is rendered in the posts in all of the above upon publication (rather than via the grody overblown toolbar of an editor).
I'm not sure if what's prohibiting HTML tags from rendering in my posts is related to customization of a class in WTForms, or something which must be treated specially in GAE's datastore, or something I need to fix within Flask (e.g., the model for posts). Any clear solution on how I--as a relatively junior dev--can incorporate formatting into these blog posts earns the bounty. Specific code from the app below...
Note: there's also a Flask-Markdown extension, but I'm equally unsure as to how to integrate it to achieve the effect I want.
The question in detail, plus snippets from the code base
I'm running Flask (with Jinja templates / Werkzeug routing, of course) on Google App Engine, and confused about how to integrate a WYSIWYG editor into the page I have dedicated for blog posts...
I'm assuming, if incorporating TinyMCE, the call for the JavaScript goes in the header of the template...like so:
<script type="text/javascript" src="/static/js/tiny_mce/tiny_mce.js">
But, then--because, per se, there's no within the template or the rendered page itself, it's not merely--per TinyMCE's install docs--a matter of also adding the following block of code into the template...
<textarea cols="80" rows="10" id="articleContent" name="articleContent">
<h1>Article Title</h1>
<p>Here's some sample text</p>
</textarea>
<script type="text/javascript">
tinyMCE.init({
theme : "advanced",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
mode : "exact",
elements : "articleContent"
});
</script>
Presently, within the tags of the template file...
<label for="title">{{ form.title.label }}</label>
{{ form.title|safe }}
{% if form.title.errors %}
<ul class="errors">
{% for error in form.title.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<label for="prose">{{ form.prose.label }}</label>
{{ form.prose|safe }}
...more WTForm validation / error handling...
I suspect the problem is in the way the form is constructed / managed via WTForms. WTForms resides in my /packages/flaskext directory. Is something like the following required somewhere...?
class wtforms.fields.TextAreaField(default field arguments, choices=[], coerce=????????, option_widget=????????)
But TextAreaField is imported from (I don't know where)...and don't know if that's even the right place / thing to tweak. Is the answer in the init.py, file.py, and/or html5.py of the WTForm module?
Again, I'd be happy if just HTML tags I include in the post are rendered upon publication...but slick way to make it easy for someone who is not accustomed to HTML to likewise format their posts would be doubly appreciated. Any help pointing me in the right direction is super appreciated!
Add'l code, if needed, follows...
I have the following class in my models.py...
class PostModel(db.Model):
"""New Post Model"""
title = db.StringProperty(required = True)
prose = db.TextProperty(required = True)
when = db.DateTimeProperty(auto_now_add = True)
author = db.UserProperty(required = True)
And the following class in my forms.py...
class PostForm(wtf.Form):
title = wtf.TextField('Title: something buzz-worthy...', validators=[validators.Required()])
prose = wtf.TextAreaField('Content: something beautiful...', validators=[validators.Required()])
The issue of having your HTML be HTML-encoded is most likely an issue that happens at render time rather than at writing time. When you receive the data back and persist it in the datastore if your HTML is still HTML and not <tag> then you need to mark your rendering as safe:
{% for post in posts %}
<h2>{{ post.title | safe }}<h2>
<article>{{ post.content | safe }}</article>
{% endfor %}
Also, in WTForms, Field.Label (as in form.prose.label) actually renders a full label (no need to wrap the call to it in pre-rendered labels.)

Get global form errors from the FormView in twig template

For rendering form errors in a twig template, you just have to use the form_errors twig macro without difference if it is a global form error or a field error.
But in my case, a global error is not rendered like a field error, so I can't use the form_errors twig macro for the two cases. I decide to use the macro for the field error & I would like to get the global form errors from the Symfony\Component\Form\FormView object. The goal is to iterate the global errors in the twig template & render them like I want.
Actually, I don't find any ressources on the symfony2 documentation which can help me.
Finally, I found the solution by myself. For the people who want to do the same thing, the solution is to call $formView->get("errors") which gives you an array of FormError
I'm using symfony 2.5 and it worked perfect for me in this way.
MyController
$error = new FormError(ErrorMessages::USER_NOT_AUTHENTICATED);
$form->addError($error);
MyView
{% for error in form.vars.errors %}
<div class="alert alert-danger" role="alert">
{{ error.messageTemplate|trans(error.messageParameters, 'validators')~'' }}
</div>
{% endfor %}
hope this will save someones time.
in symfony 2.3 all accessor methods have been removed in favor of public properties to increase performance.
$formView->get("errors");
is now:
$formView->vars["errors"];
Visit UPGRADE-2.1.md and refer to section "Deprecations" for more information.