Search

A new XSLT utility, “Form Controls” is now available for download. Comments and feedback can be left here but if you discover any issues, please post it on the issue tracker.

I just posted a select box issue.

Not certain this is a bug, but I’ve just discovered that when using Form Controls in conjunction with either Can of Spam or Answer Me, the persisted values are duplicated when the result is an error. Presumably, this is due to the post-values node being duplicated when either of these filters is added to an event.

Form Controls updated to version 1.3 on 22nd of February 2010

Form Controls updated to version 1.4 on 22nd of February 2010

Hey nick,

How can I show inline errors? Is that possible?

Presently no, but it’s a good idea. I’ll add a new template for this purpose.

My input doesn’t show the value string

<label for="fields[username]">Username</label>                                  
<xsl:call-template name="form:input">
<xsl:with-param name="handle" select="'username'"/>
<xsl:with-param name="type" select="'text'"/>
<xsl:with-param name="title" select="'Username'"/>
<xsl:with-param name="value" select="'Username'"/>
</xsl:call-template>

output looks like this:

<label for="fields[username]">Username</label>
<input name="fields[username]" id="fields-username" title="Username" type="text" value="" />

Thanks for this, Nick. This is really very useful.

I finally got around to looking at how I could use Form Controls and Section Schemas to automatically build front end forms that emulate the Symphony admin interface. I noticed that building forms automatically using Section Schemas is on your to do list. Do you have anything in the works?

If not, I’ve given this a go, and I’ve got it working well for text inputs and select fields.

I’ve got a master utility that looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml"
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
    omit-xml-declaration="yes"
    encoding="UTF-8"
    indent="yes" />

<xsl:template match="/">
    <html lang="en">
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
            <title>Symphony</title>
            <link rel="stylesheet" type="text/css" media="screen" href="{$root}/symphony/assets/forms.css" />
            &lt;script type="text/javascript" src="{$root}/symphony/assets/jquery.js">&lt;/script>
            &lt;script type="text/javascript" src="{$root}/symphony/assets/admin.js">&lt;/script>
        </head>
        <body>
            <xsl:apply-templates />
        </body>
    </html>
</xsl:template>

</xsl:stylesheet>

And a page template that looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exsl="http://exslt.org/common"
    xmlns:form="http://nick-dunn.co.uk/xslt/form-controls"
    extension-element-prefixes="exsl form">

<xsl:import href="../utilities/master.xsl"/>
<xsl:import href="../utilities/form-controls.xsl"/>

<!-- Define a global variable pointing to your Event -->
<xsl:variable name="form:event" select="/data/events/save-user"/>

<xsl:template match="data">

    <form action="" method="post">
        <h1>
            <a href="{$root}/">Symphony CMS</a>
        </h1>
        <ul id="nav">
            <li>Projects
                <ul>
                    <li>
                        <a href="{$root}/symphony/publish/projects/">Projects</a>
                    </li>
                </ul>
            </li>
            <li class="active">Users
                <ul>
                    <li>
                        <a href="{$root}/symphony/publish/users/">Users</a>
                    </li>
                </ul>
            </li>
        </ul>

        <h2>Create a user</h2>
        <xsl:call-template name="form:validation-summary"/>
        <fieldset class="primary">
            <xsl:for-each select="/data/section-schema[@handle = 'users']/*[@location = 'main']">
                <xsl:call-template name="symphony-field" />
            </xsl:for-each>
        </fieldset>
        <fieldset class="secondary">
            <xsl:for-each select="/data/section-schema[@handle = 'users']/*[@location = 'sidebar']">
                <xsl:call-template name="symphony-field" />
            </xsl:for-each>
        </fieldset>

        <div class="actions">
            <input name="action[save-user]" accesskey="s" type="submit" value="Save User" />
        </div>
        <ul id="usr">
            <li>
                <a href="{$root}/symphony/system/authors/edit/1/">Stephen Bau</a>
            </li>
            <li>
                <a href="{$root}/symphony/logout/">Logout</a>
            </li>
        </ul>
    </form>

</xsl:template>

<xsl:template name="symphony-field">
    <div>
        <xsl:attribute name="class">
            <xsl:text>field </xsl:text>
            <xsl:value-of select="concat('field-', @type)" />
            <xsl:if test="@required = 'yes'"><xsl:text> </xsl:text>required</xsl:if>
        </xsl:attribute>
        <label><xsl:value-of select="@label" />
            <xsl:choose>
                <xsl:when test="@type = 'input'">
                    <xsl:call-template name="form:input">
                        <xsl:with-param name="handle" select="name(current())"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:when test="@type = 'select'">
                    <xsl:call-template name="form:select">
                        <xsl:with-param name="handle" select="name(current())"/>
                        <xsl:with-param name="options" select="options/option"/>
                        <xsl:with-param name="value" select="options/option[1]"/>
                    </xsl:call-template>
                </xsl:when>
            </xsl:choose>
        </label>
    </div>
</xsl:template>

</xsl:stylesheet>

This does a pretty decent job of reproducing a Symphony admin page. I was wondering whether something like this would be possible:

<xsl:call-template name="form:{@type}">

But there are a couple issues with that approach. First, this causes an error:

XSLTProcessor::importStylesheet(): The value ‘form:{@type}’ of the attribute ‘name’ is not a valid QName.

And each field type will need to be fed different parameter values, anyway. Is there another approach that might work better than a set of conditionals for every field type?

I noticed that building forms automatically using Section Schemas is on your to do list. Do you have anything in the works?

I did write something yes, but quite where this is I don’t know. Let me have a root around this week and I’ll let you know! From memory it was very similar to yours.

Thankfully I had archived it on Gist before my hard drive died a while back.

http://gist.github.com/95047

Note that I needed to check the type of the field to render the appropriate control. Also note that this was written against an earlier version of Form Controls (probably pre 1.0) — it should still work with the latest Form Controls release though, but you’ll need to tweak it a little. Especially the lack of the form: namespace!

This builds a new entry form, but would need some work to get it to render existing entries too. By using a Data Source to return the XML for an entry you could probably use the field handle name to set the control values. But that was beyond the scope of my experiment at the time. I wanted to keep it simple, educational and generic.

<xsl:call-template name="form:{@type}">

What you want here is almost like a mode. You can pass a mode on both apply and call templates:

<xsl:call-template name="create-control" mode="@type">

But this won’t work since modes cannot be dynamic. In my example above I get around this by using a single template match to keep the XML flow which I felt was cleaner.

But what this has reminded me of is that myself and a colleague had the same discussion when we tried this initially — how to call a template and pass a dynamic mode. We came up with a pretty neat solution which I hope to document at some point… when time permits :-)

Thanks, Nick. That’s great! This definitely deserves a home in XSLT Utilities in the Downloads section. I’m looking forward to your clever solution for passing a dynamic mode.

I was wondering how you dealt with the Sections Schemas providing a string value for the allow-multiple-selection node, as in the following XML:

<section-schema id="2" handle="projects" total-entries="0" total-fields="4">
    <title required="yes" id="5" label="Title" type="input" sortorder="0" location="main" />
    <description required="no" id="6" label="Description" type="textarea" sortorder="1" location="main">
        <size>15</size>
    </description>
    <status required="no" id="7" label="Status" type="select" sortorder="2" location="main">
        <allow-multiple-selection>no</allow-multiple-selection>
        <options>
            <option value="Active" handle="active">Active</option>
            <option value="Inactive" handle="inactive">Inactive</option>
            <option value="Finished" handle="finished">Finished</option>
        </options>
    </status>
    <contributors required="no" id="8" label="Contributors" type="selectbox_link" sortorder="3" location="sidebar">
        <allow-multiple-selection>yes</allow-multiple-selection>
        <options>
            <optgroup label="Users">
                <option value="4">Jane Doe</option>
                <option value="3">John Smith</option>
                <option value="2">Bob Loblaw</option>
                <option value="1">Stephen Bau</option>
            </optgroup>
        </options>
    </contributors>
</section-schema>

When building a select box field with this, the $allow-multiple parameter returns a string value:

<xsl:call-template name="form:select">
    <xsl:with-param name="handle" select="name(current())"/>
    <xsl:with-param name="options" select="options/option"/>
    <xsl:with-param name="value" select="options/option[1]"/>
    <xsl:with-param name="allow-multiple" select="allow-multiple-selection"/>
</xsl:call-template>

However, Form Controls is expecting a boolean value:

    <xsl:if test="$allow-multiple">
        <xsl:attribute name="multiple">multiple</xsl:attribute>
        ...
    </xsl:if>

I could not find a way to return a boolean value with a conditional. This logic returns a string value, rather than a boolean.

<xsl:choose>
    <xsl:when test="allow-multiple-selection = 'yes'">1</xsl:when>
    <xsl:otherwise>0</xsl:otherwise>
</xsl:choose>

Unless there is another way for me to do this, I think I’ll need to modify the type of value that Form Controls is expecting for the $allow-multiple parameter. Or I’ll have to do something ugly, like this:

<xsl:choose>
    <xsl:when test="allow-multiple-selection = 'yes'">
        <xsl:call-template name="form:select">
            <xsl:with-param name="handle" select="name(current())"/>
            <xsl:with-param name="options" select="options/option"/>
            <xsl:with-param name="allow-multiple" select="1"/>
        </xsl:call-template>
    </when>
    <xsl:otherwise>
        <xsl:call-template name="form:select">
            <xsl:with-param name="handle" select="name(current())"/>
            <xsl:with-param name="options" select="options/option"/>
            <xsl:with-param name="allow-multiple" select="0"/>
        </xsl:call-template>
    </xsl:otherwise>
</xsl:choose>

Ok. This is very cool! I was able to get a select box with multiple values working properly by changing the conditional to test for a string value instead of a boolean value in Form Controls (line 628):

<xsl:if test="$allow-multiple='yes'">

However, there is an issue with postback-values for multiple select box values. It’s a mystery to me how these values are being returned, so I’m not sure how I can include these values in the event XML post-values.

<events>
    <save-project id="10" result="success" type="created">
        <message>Entry created successfully.</message>
        <post-values>
            <title>Testing the form when saving multiple contributors</title>
            <description>A test of the Form Controls for saving multiple select box values. </description>
            <status>Active</status>
        </post-values>
    </save-project>
</events>

The contributors field is missing from the event XML.

<xsl:if test="$allow-multiple='yes'">

That’s a good point and is more likely a bug/oversight in Form Controls. The original I think checks for a boolean or existence of the parameter itself. Therefore even passing a string value of no would still yield a positive from the condition. So I’ll roll your change into the next release, thanks!

I’m guessing you can now simply pass the value as:

<xsl:with-param name="allow-multiple" select="allow-multiple-selection"/>

As an aside, if you needed to use a choose/when, you can actually put this inside the with-param to save code duplication.

<xsl:call-template name="form:select">
    <xsl:with-param name="handle" select="name(current())"/>
    <xsl:with-param name="options" select="options/option"/>
    <xsl:with-param name="allow-multiple">
        <xsl:choose>
            <xsl:when test="allow-multiple-selection='yes'">yes</xsl:when>
            <xsl:otherwise>no</xsl:otherwise>
        </xsl:choose>
    </xsl:with-param>
</xsl:call-template>

Obviously the above is an unecessarily trivial example, but you get the idea.

The contributors field is missing from the event XML.

This sounds like a Symphony bug than Form Controls. I can’t remember how well Form Controls deals with allow-multiple values (or whether it does at all!). Would you be able to send over an Ensemble of your example that I can poke around with?

I’m having problems editing and entry on the frontend. Maybe I’m doing something wrong with form-controls.

my XML: http://pastie.org/1444112

my XSL: http://pastie.org/1444116 - Form-Controls utility is imported on page_master.xsl

I have an Event called Editar Usuário attached to the page getting data from Usuários section generating the following Example Front-end Form Markup: http://pastie.org/1444123

When I hit the submit button it gives me the error message: Entry encountered errors when saving.

EDIT: Solved - It was Members permissions issues.

I’m having an issue with checkboxes, I have a few check boxes with a bunch of emails set to each one ( one for each member role )

The problem is that each check boxes value cannot be larger then 255 characters or it gets cropped.

Im combining all the emails into a recipients list like so..

<input type="checkbox" name="fields[recipient][]" value="{$values} " />

and grabbing the selected values

<input name="send-email[recipient]" value="fields[recipient]" type="hidden" />

Is there another way to do this so the character length isnt cropped?

I’m not convinced this is Form Controls doing the cropping. 255 characters sounds like the limit of a varchar field, and I recall seeing this bug reported on the forum in recent weeks.

Yes, the database is set to VARCHAR(255).

I’ve changed the database to longtext for the recipients field for the email template filter and more then 255 characters are in there, however for each input over 255 characters they get cropped in the email but are not cropped in the html when i view source, so i figured they are getting cropped in the transition from the initial check box form field and the send mail recipient field.

If im wrong please point me in the right direction if possible.

if this isnt clear let me know ill try to describe it better.

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details