Skip to content

Instantly share code, notes, and snippets.

@jshirley
Created January 27, 2012 14:23
Show Gist options
  • Save jshirley/1689003 to your computer and use it in GitHub Desktop.
Save jshirley/1689003 to your computer and use it in GitHub Desktop.
Our macro.tt file for handling inputs consistently. Requires YUI3 grids to look proper.
sub guide : Local {
my ( $self, $c ) = @_;
unless ( $c->debug ) {
$c->detach('/error/not_found');
}
my $template = 'index.tt';
if ( @{ $c->req->args } ) {
$template = $c->req->args->[0];
if ( $template =~ /^\d{3}/ ) {
$c->detach('/error/_error', [ $template ]);
}
$template .= '.tt';
}
unless ( -f $c->path_to('root', 'guide', $template) ) {
$template = 'index.tt';
}
if ( $c->req->method eq 'POST' ) {
my $result = $c->model('DataManager')->verify('guide', $c->req->params);
if ( $result->success ) {
$c->message(q{Victory!});
} else {
$c->message({ type => 'error', message => $c->loc('FORM VALIDATION ERROR') });
}
$c->res->redirect( $c->req->uri );
$c->detach;
}
$c->stash->{template} = 'guide/' . $template;
}
[%~
# Some illustrious documentation to get you started:
#
# The macros defined are to generate markup to save people from copy and pasting
# markup. They copy and paste hashes instead, which should be safer (in theory)
#
# The macros for forms are:
# * text_field - A text field
# * textarea_field - A textarea field
# * password_field - A password field, text_field({ type => 'password', ... })
# * checkbox_field - A single checkbox, like an active checkbox
# * display_field - A display-only field, no hidden input for the display
# * readonly_field - A display-only field, with a hidden input
# * checkboxes_field - A group of fields, displayed in nice fashion. If a
# radio is needed, pass type => 'radio'.
#
# These use the YUI3 grids for rendering the markup. Without that CSS, things
# will not look correct.
#
# The basic structure is a containing div and the label and input is in a
# separate div.
#
MACRO submit_button(info) BLOCK;
DEFAULT info.label_column_size = "1-4";
DEFAULT info.input_column_size = "3-4";
DEFAULT info.button_class = "orange submit_button";
IF info.no_extra;
info.label_column_size = "1-3";
info.input_column_size = "2-3";
END %]
<div class="field yui3-g submit-group
[%= info.field_classes.join(' ') ~%]
">
<div class="yui3-u-[% info.label_column_size %]">[% info.more || "&nbsp;" %]</div>
<div class="yui3-u-[% info.input_column_size %]">
[% IF info.with_reset %]
<input type="reset" value="[% c.loc('Cancel') %]">
[% END %]
<input class="[% info.button_class %]" type="[% info.type || 'submit' %]" value="[% info.label || 'Submit' %]"[% IF info.defined('name') %] name="[% info.name %]"[% END %][% IF info.disabled %] disabled="disabled"[% END %]>
</div>
</div>
[% IF info.extra %]
<div class="yui3-g extra">
<div class="yui3-u-[% info.label_column_size %]">&nbsp;</div>
<div class="yui3-u-[% info.input_column_size %]">[% info.extra %]</div>
</div>
[% END; END;
MACRO label_field(info) BLOCK;
DEFAULT info.label_column_size = "1-4";
IF info.no_extra;
info.label_column_size = "1-3";
info.input_column_size = "2-3";
END;
IF !info.error && stack && stack.count;
error_name = info.name;
IF context.scope;
error_name = error_name.remove("^${context.scope}\\.");
END;
info.error = c.loc( stack.for_subject(error_name).for_level('error').first_message.id );
END %]
<label class="yui3-u-[% info.label_column_size %][% IF info.error %] error[% END; IF info.important %] important[% END %]" id="form_[% info.name %]_label" for="[% info.id %]"><span>[% c.loc(info.label, info.params) ~%]
[%~ IF info.tooltip %]<script type="text/javascript">new YAHOO.widget.Tooltip('tt_[% info.name %]_label', { context: 'form_[% info.name %]_label', text: "[% info.tooltip | replace('"', '\"') %]" } );</script>[?][% END ~%][% IF info.label %]:[% END %]</span>
</label>
[% END ~%]
[%~
MACRO error_block(info) BLOCK;
DEFAULT info.label_column_size = '1-4';
DEFAULT info.input_column_size = '3-4';
IF info.error || info.extra %]
<div class="yui3-g [% =%]
[%= IF info.error =%]error[%= END =%]
[%= IF info.extra =%]extra[%= END ~%]
">
<div class="yui3-u-1-4">&nbsp;</div>
<div class="yui3-u-3-4 message">
[% IF info.error %]
<div class="rmessage"><p>[% c.loc(info.error, info.error_message.params) %]</p></div>
[% END;
IF info.extra %]
<div class="gmessage"><p>[% c.loc(info.extra) %]</p></div>
[% END %]
</div>
</div>
[% END;
END ~%]
[%~ MACRO display_field(info) BLOCK;
IF info.filter && info.value;
f = info.filter;
IF f == "join";
info.value = info.value.join(', ');
ELSIF f.match("^date_");
info.value = format_date(info.value, f.substr(5));
ELSE;
TRY; info.value = FILTER $f; info.value; END; CATCH; "Error!"; END;
END;
END;
%]
<div class="field yui3-g
[%= info.field_classes.join(' ') ~%]
[%~ ~%]">
[% label_field(info) %]
<div class="yui3-u-1-2 ro [%~ IF info.extra || info.error %] message [% END ~%][%~ IF info.error %] error[% END %]">
<span>
[%~ IF info.link %]<a href="[% info.link %]">[%~ END ~%]
[% info.value %]
[%~ IF info.link ~%]</a>[%~ END ~%]</span>
</div>
[% IF info.more %]<div class="yui3-u-1-4 more">[% c.loc(info.more) %]</div>[% END %]
[% error_block(info) %]
</div>
[% END ~%]
[%~ MACRO readonly_field(info) BLOCK;
IF info.filter && info.value;
f = info.filter;
IF f == "join";
info.value = info.value.join(', ');
ELSIF f.match("^date_");
info.value = format_date(info.value, f.substr(5));
ELSE;
TRY; info.value = FILTER $f; info.value; END; CATCH; "Error!"; END;
END;
END;
%]
<div class="field yui3-g
[%= info.field_classes.join(' ') ~%]
[%~ ~%]">
[% label_field(info) %]
<div class="yui3-u-1-2 ro [%~ IF info.extra || info.error %] message [% END ~%][%~ IF info.error %] error[% END %]">
<input type="hidden" id="form_[% info.name %]" name="[% info.name %]" value="[% info.value | html %]"/><span>
[%~ IF info.link %]<a href="[% info.link %]">[%~ END ~%]
[% info.value %]
[%~ IF info.link ~%]</a>[%~ END ~%]</span>
</div>
[% IF info.more %]<div class="yui3-u-1-4 more">[% c.loc(info.more) %]</div>[% END %]
[% error_block(info) %]
</div>
[% END ~%]
[%~ MACRO select_field(info) BLOCK;
IF !info.value && results.${context.scope};
value_name = info.name;
IF context.scope; value_name = value_name.remove("^${context.scope}\\."); END;
IF info.filter;
info.value = results.${context.scope}.get_value(value_name);
ELSE;
info.value = results.${context.scope}.get_original_value(value_name);
END;
END;
IF !info.error && messages.for_scope(context.scope);
value_name = info.name;
IF context.scope; value_name = value_name.remove("^${context.scope}\\."); END;
info.error = messages.for_scope(context.scope).for_subject(value_name).first_message.id;
info.error_message = messages.for_scope(context.scope).for_subject(value_name).first_message;
END;
DEFAULT info.id = "form_" _ info.name.replace('\\.', '_');
%]
<div class="field yui3-g
[%= info.field_classes.join(' ') ~%]
[%~ ~%]">
[% label_field(info); DEFAULT info.input_column_size = "1-2"; %]
<div class="yui3-u-[% info.input_column_size %] select [%~ IF info.extra || info.error %] [% END ~%][%~ IF info.error %] error[% END %][% IF info.input_classes %] [% info.input_classes.join(' ') %][% END %]">
<[% IF info.type == 'radio'; "div"; ELSE; "select"; END %] id="form_[% info.name %]" name="[% info.name %]"
[% IF info.classes %] class="[% info.classes.join(' ') %]"[%~ END ~%]
[% IF info.disabled %] disabled="disabled"[%~ END ~%]
[% FOREACH datum IN info.data.pairs %] data-[% datum.key %]="[% datum.value %]"[%~ END ~%]>
[% IF info.type != "radio" && info.default_option %]
[% IF info.type == 'radio' %]
[% ELSE %]
<option value="[% info.default_option.0 | html %]">[% info.default_option.1 %]</option>
[% END %]
[% END %]
[% IF info.optgroups;
info.array = [];
DEFAULT info.children = 'children';
FOREACH parent IN info.optgroups;
info.array.push({ optgroup => parent.${info.label_method} });
FOREACH child IN parent.children;
info.array.push(child);
END;
END;
END %]
[% has_optgroup = 0;
FOREACH item = info.array;
IF item.optgroup; has_optgroup = 1;
IF !loop.first %]</optgroup>[% END;
%]<optgroup label="[% item.optgroup | html %]">[%
ELSE;
IF info.defined('value_method');
SET this_value = item.${info.value_method};
ELSE;
SET this_value = item;
END;
IF info.defined('label_method');
SET this_name = item.${info.label_method};
ELSE;
SET this_name = item;
END;
IF info.defined('elide');
this_name = string_trunc.elide(this_name, info.elide);
END;
%][% IF info.type == "radio" %]<label><input type="radio" name="[% info.name %]" value="[% this_value | html %]"[% IF info.value == this_value %] checked="checked"[% END %]> [% c.loc(this_name) %]</label>
[% ELSE %]<option value="[% this_value | html %]" [% IF this_value == info.value %]selected="selected"[% END %]>[% c.loc(this_name) %]</option>[% END %]
[% END; # Not an optgroup %]
[% END;
IF has_optgroup %]</optgroup>[% END %]
[% IF info.type != 'radio' %]</select>[% END %]
[% IF info.required %]<span class="req">[% c.loc('FIELD REQUIRED SPLAT') %]</span>[% END %]
[% IF info.type == 'radio' %]</div>[% END %]
</div>
[% IF info.more %]<div class="yui3-u-1-4 more">[% c.loc(info.more) %]</div>[% END %]
[% error_block(info) %]
</div>
[% END ~%]
[%~
MACRO password_field(info) BLOCK;
info.type = 'password';
text_field(info);
END;
~%]
[%~
MACRO text_field(info) BLOCK;
IF !info.defined('value') && results.${context.scope};
value_name = info.name;
IF context.scope; value_name = value_name.remove("^${context.scope}\\."); END;
IF info.filter;
info.value = results.${context.scope}.get_value(value_name);
ELSE;
info.value = results.${context.scope}.get_original_value(value_name);
END;
END;
IF !info.error && messages.for_scope(context.scope);
value_name = info.name;
IF context.scope; value_name = value_name.remove("^${context.scope}\\."); END;
info.error = messages.for_scope(context.scope).for_subject(value_name).first_message.id;
END;
IF info.filter && info.value;
f = info.filter;
IF f == "join";
info.value = info.value.join(', ');
ELSIF f.match("^date_");
info.value = format_date(info.value, f.substr(5), info.timezone);
ELSE;
TRY; info.value = FILTER $f; info.value; END; CATCH; "Error!"; END;
END;
END;
DEFAULT info.id = "form_" _ info.name.replace('\\.', '_');
%]
<div class="field yui3-g
[%= info.field_classes.join(' ') ~%]
[%~ ~%]">
[% label_field(info);
# Default this here because label_field can set it.
DEFAULT info.input_column_size = "1-2";
-%]
<div class="[% info.type || 'text' %] [%~ IF info.extra || info.error %] [% END ~%][%~ IF info.error %] error[% END %] yui3-u-[% info.input_column_size %]">
<input type="[% info.type || 'text' %]" id="[% info.id %]" name="[% info.name %]" [% IF info.size %]size="[% info.size %]"[% END %]
[% IF info.pattern %] pattern="[% info.pattern %]" [% END %]
value="[% info.value | html %]"
[%~ IF info.classes %] class="[% info.classes.join(" ") %]"[% END ~%]
[% # The unicode char below is purely to make the placeholder junk work. %]
[%~ IF info.hint %] placeholder="&#x25E6; [% c.loc(info.hint) %]"[% END ~%]
[%~ IF info.autocomplete == 0 %] autocomplete="false"[% END ~%]
[%~ IF info.disabled == 1 %] disabled="disabled"[% END ~%]
[%~ IF info.tabindex %] tabindex="[% info.tabindex %]"[% END ~%]
[%~ IF info.maxlength %] maxlength="[% info.maxlength %]"[% END ~%]
[%~ FOREACH datum IN info.data.pairs %] data-[% datum.key %]="[% datum.value %]"[% END ~%]>
[% IF info.required %]<span class="req">[% c.loc('FIELD REQUIRED SPLAT') %]</span>[% END %]
</div>
[% IF info.more %]<div class="yui3-u-1-4 more">[% c.loc(info.more) %]</div>
[% ELSIF info.helptext %]<div class="yui3-u-1-4 more helptext"><a href="#[% info.id %]" class="helptext">[% c.loc(info.helptext) %]</a></div>[% END %]
[% error_block(info) %]
</div>
[% END ~%]
[%~
MACRO textarea_field(info) BLOCK;
IF !info.value && results.${context.scope};
value_name = info.name;
IF context.scope; value_name = value_name.remove("^${context.scope}\\."); END;
info.value = results.${context.scope}.get_original_value(value_name);
END;
IF !info.error && messages.for_scope(context.scope);
value_name = info.name;
IF context.scope; value_name = value_name.remove("^${context.scope}\\."); END;
info.error = messages.for_scope(context.scope).for_subject(value_name).first_message.id;
END;
%]
<div class="field yui3-g">
[% label_field(info) %]
<div class="yui3-u-[% info.input_column_size %] textarea [%~ IF info.extra || info.error %] message [% END ~%][%~ IF info.error %] error[% END %]">
<textarea [%= ~%]
id="form_[% info.name %]" name="[% info.name %]"
[% IF info.hint %] placeholder="[% c.loc(info.hint) %]"[% END %]
[%~ IF info.classes %] class="[% info.classes.join(' ') %]"[% END ~%]
[%~ IF info.disabled == 1 %] disabled="disabled"[% END ~%]
[%~ IF info.autocomplete == 0 %] autocomplete="false"[% END ~%]
[%~ IF info.tabindex %] tabindex="[% info.tabindex %]"[% END ~%]
[%~ IF info.rows %] rows="[% info.rows %]"[% END ~%]
[%~ IF info.cols %] cols="[% info.cols %]"[% END ~%]
[%~ FOREACH datum IN info.data.pairs %] data-[% datum.key %]="[% datum.value %]"[% END ~%]
>
[%~ info.value | html ~%]
</textarea>
[% IF info.required %]<span class="req">[% c.loc('FIELD REQUIRED SPLAT') %]</span>[% END %]
</div>
[% IF info.more %]<div class="yui3-u-1-4 more">[% c.loc(info.more) %]</div>[% END %]
[% error_block(info) %]
</div>
[% END ~%]
[%~
MACRO checkboxes_field(info) BLOCK;
IF !info.value && results.${context.scope};
value_name = info.name;
IF context.scope; value_name = value_name.remove("^${context.scope}\\."); END;
IF info.filter;
info.value = results.${context.scope}.get_value(value_name);
ELSE;
info.value = results.${context.scope}.get_original_value(value_name);
END;
END;
IF !info.error && messages && messages.count;
error_name = info.name;
IF context.scope;
error_name = error_name.remove("^${context.scope}\\.");
END;
info.error = c.loc( messages.for_subject(error_name).for_level('error').first_message.id );
END;
%]
<div class="field yui3-g submit-group
[%= info.field_classes.join(' ') ~%]
">
[% label_field(info);
# Default this here because label_field can set it.
DEFAULT info.input_column_size = "1-2";
-%]
<div class="yui3-u-[% info.input_column_size %] checkboxes [%~ IF info.extra || info.error %] message [% END ~%][%~ IF info.error %] error[% END %]">
<fieldset class="cwrap[% IF info.fieldset_classes %] [% info.fieldset_classes.join(' '); END %]">
[% FOREACH item = info.array;
IF info.defined('value_method');
SET this_value = item.${info.value_method};
ELSE;
SET this_value = item;
END;
IF info.defined('label_method');
SET this_name = item.${info.label_method};
ELSE;
SET this_name = item;
END;
%]<label><input type="[% info.type || 'checkbox' %]" name="[% info.name %]" value="[% this_value | html %]"[% IF info.value == this_value || info.selected.defined(this_value) %] checked="checked"[% END %]> [% this_name %]</label>
[% END %]
</fieldset>
[% IF info.required %]<span class="req">[% c.loc('FIELD REQUIRED SPLAT') %]</span>[% END %]
</div>
[% IF info.more %]<div class="yui3-u-1-4 more">[% c.loc(info.more) %]</div>[% END %]
[% error_block(info) %]
</div>
[% END; %]
[%~
MACRO checkbox_field(info) BLOCK;
DEFAULT info.label_column_size = "1-4";
DEFAULT info.input_column_size = "1-2";
IF info.no_extra;
info.label_column_size = "1-3";
info.input_column_size = "2-3";
END;
IF !info.checked && results.${context.scope};
value_name = info.name;
IF context.scope; value_name = value_name.remove("^${context.scope}\\."); END;
info.checked = results.${context.scope}.get_original_value(value_name);
END;
IF !info.error && messages && messages.count;
error_name = info.name;
IF context.scope;
error_name = error_name.remove("^${context.scope}\\.");
END;
info.error = c.loc( messages.for_subject(error_name).for_level('error').first_message.id );
END;
%]
<div class="field yui3-g">
<div class="yui3-u-[% info.label_column_size %]">&nbsp;</div>
<div class="yui3-u-[% info.input_column_size %] checkbox [%~ IF info.extra || info.error %] message [% END ~%][%~ IF info.error %] error[% END %]">
<label><input type="checkbox" name="[% info.name %]"
[%~ IF info.value =%] value="[% info.value %]"[% END ~%]
[%~ IF info.checked =%] checked="checked"[% END ~%]
> [% c.loc(info.label, info.params) %]</label>
</div>
[% IF info.more %]<div class="yui3-u-1-4 more">[% c.loc(info.more) %]</div>[% END %]
[% error_block(info) %]
</div>
[%~ END ~%]
[%~
MACRO datetime_field(info) BLOCK;
IF !info.defined('value') && results.${context.scope};
value_name = info.name;
IF context.scope; value_name = value_name.remove("^${context.scope}\\."); END;
info.value = results.${context.scope}.get_value(value_name);
END;
IF !info.error && messages.for_scope(context.scope);
value_name = info.name;
IF context.scope; value_name = value_name.remove("^${context.scope}\\."); END;
info.error = messages.for_scope(context.scope).for_subject(value_name).first_message.id;
END;
DEFAULT info.id = "form_" _ info.name.replace('\\.', '_');
IF info.value && info.timezone;
info.value = set_timezone(info.value, info.timezone);
END;
%]
<div class="field yui3-g
[%= info.field_classes.join(' ') ~%]
[%~ ~%]">
[% label_field(info);
# Default this here because label_field can set it.
DEFAULT info.input_column_size = "1-2";
-%]
<div class="[% info.type || 'datetime' %] [%~ IF info.extra || info.error %] [% END ~%][%~ IF info.error %] error[% END %] yui3-u-[% info.input_column_size %]">
<input type="[% info.type || 'text' %]" id="[% info.id %]" name="[% info.name %].date"
[% IF info.pattern %] pattern="[% info.pattern %]" [% END %]
value="[% FILTER html; info.value.ymd || info.value; END %]"
[%~ IF info.classes %] class="[% info.classes.join(" ") %]"[% END ~%]
[% # The unicode char below is purely to make the placeholder junk work. %]
[%~ IF info.hint %] placeholder="&#x25E6; [% c.loc(info.hint) %]"[% END ~%]
[%~ IF info.autocomplete == 0 %] autocomplete="false"[% END ~%]
[%~ IF info.disabled == 1 %] disabled="disabled"[% END ~%]
[%~ IF info.tabindex %] tabindex="[% info.tabindex %]"[% END ~%]
[%~ IF info.maxlength %] maxlength="[% info.maxlength %]"[% END ~%]
[%~ FOREACH datum IN info.data.pairs %] data-[% datum.key %]="[% datum.value %]"[% END ~%]>
[% IF info.required %]<span class="req">[% c.loc('FIELD REQUIRED SPLAT') %]</span>[% END %]
<select name="[% info.name %].hour">
[% FOREACH i IN [0..23] %]
<option value="[% i | format("%02d") %]"[% IF info.value.hour && info.value.hour == i %] selected="selected"[% END %]>[% i | format("%02d") %]</option>
[% END %]
</select>
<select name="[% info.name %].minute">
[% FOR i IN [0, 15, 30, 45] %]
<option value="[% i | format("%02d") %]"[% IF info.value.minute && info.value.minute >= i && info.value.minute < i + 15 %] selected="selected"[% END %]>[% i | format("%02d") %]</option>
[% END %]
</select>
</div>
[% IF info.more %]<div class="yui3-u-1-4 more">[% c.loc(info.more) %]</div>
[% ELSIF info.helptext %]<div class="yui3-u-1-4 more helptext"><a href="#[% info.id %]" class="helptext">[% c.loc(info.helptext) %]</a></div>[% END %]
[% error_block(info) %]
</div>
[% END ~%]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment