diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt
index 11ed462a1..b1a409a37 100644
--- a/docs/changelog/7.x.x.txt
+++ b/docs/changelog/7.x.x.txt
@@ -1,4 +1,5 @@
7.10.7
+ - Added a Preview button the the Template asset's edit page
- fixed #12009: Export JS errors in IE7
- added #11968: use the language override in the registration form (Jukka Raimovaara / Mentalhouse Oy)
- Changed Carousel to use TinyMCE with WebGUI plugins
diff --git a/lib/WebGUI/Asset/Template.pm b/lib/WebGUI/Asset/Template.pm
index d5e0c9102..8c969a71f 100644
--- a/lib/WebGUI/Asset/Template.pm
+++ b/lib/WebGUI/Asset/Template.pm
@@ -25,7 +25,8 @@ use List::MoreUtils qw{ any };
use Tie::IxHash;
use Clone qw/clone/;
use HTML::Packer;
-use JSON qw{ to_json };
+use JSON qw{ to_json from_json };
+use Try::Tiny;
=head1 NAME
@@ -284,60 +285,134 @@ Returns the TabForm object that will be used in generating the edit page for thi
sub getEditForm {
my $self = shift;
+ my $session = $self->session;
+
+ my ( $db, $url, $style, $form, $config )
+ = $session->quick(qw( db url style form config ));
+
my $tabform = $self->SUPER::getEditForm();
- my $i18n = WebGUI::International->new($self->session, 'Asset_Template');
+ my $i18n = WebGUI::International->new($session, 'Asset_Template');
+
+ my ( $properties, $meta, $display ) =
+ map { $tabform->getTab($_) } qw( properties meta display );
+
+ my $returnUrl = $form->get('returnUrl');
$tabform->hidden({
name=>"returnUrl",
- value=>$self->session->form->get("returnUrl")
+ value=>$returnUrl,
});
if ($self->getValue("namespace") eq "") {
- my $namespaces = $self->session->dbSlave->buildHashRef("select distinct(namespace) from template order by namespace");
- $tabform->getTab("properties")->combo(
+ my $namespaces = $db->buildHashRef("select distinct(namespace) from template order by namespace");
+ $properties->combo(
-name=>"namespace",
-options=>$namespaces,
-label=>$i18n->get('namespace'),
-hoverHelp=>$i18n->get('namespace description'),
- -value=>[$self->session->form->get("namespace")]
+ -value=>[$form->get("namespace")]
);
} else {
- $tabform->getTab("meta")->readOnly(
+ $meta->readOnly(
-label=>$i18n->get('namespace'),
-hoverHelp=>$i18n->get('namespace description'),
-value=>$self->getValue("namespace")
- );
- $tabform->getTab("meta")->hidden(
+ );
+ $meta->hidden(
-name=>"namespace",
-value=>$self->getValue("namespace")
);
}
- $tabform->getTab("display")->yesNo(
+ $display->yesNo(
-name=>"showInForms",
-value=>$self->getValue("showInForms"),
-label=>$i18n->get('show in forms'),
-hoverHelp=>$i18n->get('show in forms description'),
);
- $tabform->getTab("properties")->codearea(
+ $properties->codearea(
-name=>"template",
-label=>$i18n->get('assetName'),
-hoverHelp=>$i18n->get('template description'),
-syntax => "html",
-value=>$self->getValue("template")
);
- $tabform->getTab('properties')->yesNo(
- name => "usePacked",
- label => $i18n->get('usePacked label'),
- hoverHelp => $i18n->get('usePacked description'),
- value => $self->getValue("usePacked"),
- );
- if($self->session->config->get("templateParsers")){
- my @temparray = @{$self->session->config->get("templateParsers")};
+ $properties->raw(qq(
+
+ |
+ ${\ $i18n->get('Preview') }
+ |
+
+
+
+ |
+
+ ));
+ my $cform = WebGUI::HTMLForm->new($session);
+ $cform->yesNo(
+ id => 'previewRaw',
+ name => 'previewRaw',
+ label => $i18n->get('Plain Text?'),
+ hoverHelp => $i18n->get('Plain Text hoverHelp'),
+ );
+ $cform->text(
+ id => 'previewFetchUrl',
+ label => $i18n->get('URL'),
+ hoverHelp => $i18n->get('URL hoverHelp'),
+ defaultValue => $returnUrl,
+ );
+ $cform->button(
+ id => 'previewFetch',
+ label => $i18n->get('Fetch Variables'),
+ hoverHelp => $i18n->get('Fetch Variables hoverHelp'),
+ value => $i18n->get('Fetch'),
+ );
+ $cform->codearea(
+ id => 'previewVars',
+ label => $i18n->get('Variables'),
+ hoverHelp => $i18n->get('Variables hoverHelp'),
+ );
+
+ $cform->hidden(id => 'previewId', value => $self->getId);
+ $cform->hidden(id => 'previewGateway', value => $url->gateway);
+ $properties->raw(qq(
+
+ |
+
+
+ |
+
+ ));
+
+ $properties->yesNo(
+ name => "usePacked",
+ label => $i18n->get('usePacked label'),
+ hoverHelp => $i18n->get('usePacked description'),
+ value => $self->getValue("usePacked"),
+ );
+
+ $style->setScript($url->extras($_)) for qw(
+ yui/build/json/json-min.js
+ yui/build/container/container-min.js
+ templatePreview.js
+ );
+
+ if($config->get("templateParsers")){
+ my @temparray = @{$config->get("templateParsers")};
tie my %parsers, 'Tie::IxHash';
while(my $a = shift @temparray){
- $parsers{$a} = $self->getParser($self->session, $a)->getName();
+ $parsers{$a} = $self->getParser($session, $a)->getName();
}
my $value = [$self->getValue("parser")];
- $value = \[$self->session->config->get("defaultTemplateParser")] if(!$self->getValue("parser"));
- $tabform->getTab("properties")->selectBox(
+ $value = \[$config->get("defaultTemplateParser")] if(!$self->getValue("parser"));
+ $properties->selectBox(
-name=>"parser",
-options=>\%parsers,
-value=>$value,
@@ -346,36 +421,36 @@ sub getEditForm {
);
}
- $tabform->getTab('properties')->jsonTable(
- name => 'attachmentsJson',
- value => $self->get('attachmentsJson'),
- label => $i18n->get("attachment display label"),
- fields => [
- {
- type => "text",
- name => "url",
- label => $i18n->get('attachment header url'),
- size => '48',
- },
- {
- type => "select",
- name => "type",
- label => $i18n->get('attachment header type'),
- options => [
- stylesheet => $i18n->get('css label'),
- headScript => $i18n->get('js head label'),
- bodyScript => $i18n->get('js body label'),
- ],
- },
- ],
- );
+ $properties->jsonTable(
+ name => 'attachmentsJson',
+ value => $self->get('attachmentsJson'),
+ label => $i18n->get("attachment display label"),
+ fields => [
+ {
+ type => "text",
+ name => "url",
+ label => $i18n->get('attachment header url'),
+ size => '48',
+ },
+ {
+ type => "select",
+ name => "type",
+ label => $i18n->get('attachment header type'),
+ options => [
+ stylesheet => $i18n->get('css label'),
+ headScript => $i18n->get('js head label'),
+ bodyScript => $i18n->get('js body label'),
+ ],
+ },
+ ],
+ );
- $tabform->getTab('properties')->image(
- name => 'storageIdExample',
- value => $self->getValue('storageIdExample'),
- label => $i18n->get('field storageIdExample'),
- hoverHelp => $i18n->get('field storageIdExample description'),
- );
+ $properties->image(
+ name => 'storageIdExample',
+ value => $self->getValue('storageIdExample'),
+ label => $i18n->get('field storageIdExample'),
+ hoverHelp => $i18n->get('field storageIdExample description'),
+ );
return $tabform;
}
@@ -623,6 +698,44 @@ sub process {
return to_json( $vars );
}
+ my $extra = '';
+ if ($self->canEdit) {
+ # Used for debugging and the template test renderer.
+
+ # WARNING: Please do not rely on this behavior. It's a bit of a hack,
+ # and should not be considered part of the core API. Eventually, we
+ # will have introspectable template objects so that you can more
+ # easily (and efficiently) get this kind of information.
+
+ # If the first value for the 'X-Webgui-Template-Variables' header is
+ # our assetId, then in addition to processing the template, we'll add
+ # a json representation of our template variables. The headers
+ # "X-Webgui-Template-Variables-Start" and
+ # "X-Webgui-Template-Variables-End" will contain the delimiters for
+ # the start and end of this content so that the user agent (who had to
+ # have stuck the header in in the first place) can parse it out. The
+ # delimiters will make the whole thing look like an xml comment () just in case.
+
+ # We would just send the vars in the header, but different webservers
+ # have different limits on header field size and it's impossible to
+ # say whether our data will fit inside them or not.
+ my $r = $session->request;
+ my $head = 'X-Webgui-Template-Variables';
+ if ($self->getId eq $r->headers_in->{$head}) {
+ if (my $json = eval { to_json($vars) }) {
+ my @chr = ('0'..'9', 'a'..'z', 'A'..'Z');
+ my $rnd = join('', map { $chr[int(rand($#chr))] } (1..32));
+ my $out = $r->headers_out;
+ my $st = "";
+ $out->{"$head-Start"} = $st;
+ $out->{"$head-End"} = $end;
+ $extra = $st . $json . $end;
+ }
+ }
+ }
+
$self->prepare unless ($self->{_prepared});
my $parser = $self->getParser($session, $self->get("parser"));
my $template = $self->get('usePacked')
@@ -636,7 +749,7 @@ sub process {
my $i18n = WebGUI::International->new($session, 'Asset_Template');
$output = sprintf $i18n->get('template error').$e->error, $self->getUrl, $self->getId;
}
- return $output;
+ return $output . $extra;
}
@@ -1174,6 +1287,42 @@ sub www_styleWizard {
#-------------------------------------------------------------------
+=head2 www_preview
+
+Rendes this template with the given variables (posted as JSON)
+
+=cut
+
+sub www_preview {
+ my $self = shift;
+ my $session = $self->session;
+ return $session->privilege->insufficient unless $self->canEdit;
+
+ my $form = $session->form;
+ my $http = $session->http;
+
+ try {
+ my $output = $self->processRaw(
+ $session,
+ $form->get('template'),
+ from_json($form->get('variables')),
+ $form->get('parser'),
+ );
+ if ($form->get('plainText')) {
+ $http->setMimeType('text/plain');
+ }
+ elsif ($output !~ //) {
+ $output = $session->style->userStyle($output);
+ }
+ return $output;
+ } catch {
+ $http->setMimeType('text/plain');
+ $_[0];
+ }
+}
+
+#-------------------------------------------------------------------
+
=head2 www_view
Override the default behavior. When a template is viewed, it redirects you
diff --git a/lib/WebGUI/Asset/Template/TemplateToolkit.pm b/lib/WebGUI/Asset/Template/TemplateToolkit.pm
index 3474dedda..55c41250d 100644
--- a/lib/WebGUI/Asset/Template/TemplateToolkit.pm
+++ b/lib/WebGUI/Asset/Template/TemplateToolkit.pm
@@ -81,7 +81,11 @@ sub process {
POST_CHOMP => 1, # cleanup whitespace
EVAL_PERL => 0, # evaluate Perl code blocks
});
- $t->process( \$template, _rewriteVars($vars),\$output) || $self->session->errorHandler->error($t->error());
+ unless ($t->process( \$template, _rewriteVars($vars),\$output)) {
+ my $e = $t->error;
+ $self->session->log->error($e);
+ die $e;
+ }
};
if ($@) {
WebGUI::Error::Template->throw( error => $@ );
diff --git a/lib/WebGUI/i18n/English/Asset_Template.pm b/lib/WebGUI/i18n/English/Asset_Template.pm
index 1e4d3bc7b..5aa1ef3b9 100644
--- a/lib/WebGUI/i18n/English/Asset_Template.pm
+++ b/lib/WebGUI/i18n/English/Asset_Template.pm
@@ -399,7 +399,54 @@ Any scratch variables will be available in the template with this syntax:
message => 'An example image to show what the template looks like before the user selects it',
lastUpdated => 0,
},
-
+ 'Configure' => {
+ message => 'Configure',
+ lastUpdated => 1294247160,
+ },
+ 'Fetch Variables' => {
+ message => 'Fetch Variables',
+ lastUpdated => 1294165643,
+ },
+ 'Fetch Variables hoverHelp' => {
+ message => 'Try to guess variables from a url that uses this template.',
+ lastUpdated => 1294165643,
+ },
+ 'Fetch' => {
+ message => 'Fetch',
+ lastUpdated => 1294165643,
+ },
+ 'URL' => {
+ message => 'URL',
+ lastUpdated => 1294165643,
+ },
+ 'URL hoverHelp' => {
+ message => 'URL used by the fetch button.',
+ lastUpdated => 1294165643,
+ },
+ 'Plain Text?' => {
+ message => 'Preview as Plain Text?',
+ lastUpdated => 1294165643,
+ },
+ 'Plain Text hoverHelp' => {
+ message => 'If you mark yes, you will get a plain-text response (useful for seeing the raw output of a template). Otherwise, the output will be rendered as html.',
+ lastUpdated => 1294165643,
+ },
+ 'Preview' => {
+ message => 'Preview',
+ lastUpdated => 1294247388,
+ },
+ 'Variables' => {
+ message => 'Variables',
+ lastUpdated => 1294165651,
+ },
+ 'Variables hoverHelp' => {
+ message => 'Variables used by the render button (in JSON).',
+ lastUpdated => 1294165652,
+ },
+ 'Configure Preview' => {
+ message => 'Configure Preview',
+ lastUpdated => 1294251507,
+ },
};
1;
diff --git a/t/Asset/Template.t b/t/Asset/Template.t
index da42347c4..9fe94e201 100644
--- a/t/Asset/Template.t
+++ b/t/Asset/Template.t
@@ -16,7 +16,7 @@ use WebGUI::Test;
use WebGUI::Session;
use WebGUI::Asset::Template;
use Exception::Class;
-use Test::More tests => 57; # increment this value for each test you create
+use Test::More tests => 58; # increment this value for each test you create
use Test::Deep;
use Data::Dumper;
use Test::Exception;
@@ -51,7 +51,10 @@ ok($output =~ m/true/, "process() - conditionals");
ok($output =~ m/\b(?:XY){5}\b/, "process() - loops");
# See if template listens the Accept header
-$session->request->headers_in->{Accept} = 'application/json';
+my $request = $session->request;
+my $in = $request->headers_in;
+my $out = $request->headers_out;
+$in->{Accept} = 'application/json';
my $json = $template->process(\%var);
my $andNowItsAPerlHashRef = eval { from_json( $json ) };
@@ -61,6 +64,29 @@ cmp_deeply( \%var, $andNowItsAPerlHashRef, 'Accept = json, The correct JSON is r
# Done, so remove the json Accept header.
delete $session->request->headers_in->{Accept};
+# Testing the stuff-your-variables-into-the-body-with-delimiters header
+my $oldUser = $session->user;
+
+# log in as admin so we pass canEdit
+$session->user({ userId => 3 });
+my $hname = 'X-Webgui-Template-Variables';
+$in->{$hname} = $template->getId;
+
+# processRaw sets some session variables (including username), so we need to
+# re-do it.
+WebGUI::Asset::Template->processRaw($session,$tmplText,\%var);
+my $output = $template->process(\%var);
+delete $in->{$hname};
+my $start = delete $out->{"$hname-Start"};
+my $end = delete $out->{"$hname-End"};
+my ($json) = $output =~ /\Q$start\E(.*)\Q$end\E/;
+$andNowItsAPerlHashRef = eval { from_json( $json ) };
+cmp_deeply( $andNowItsAPerlHashRef, \%var, "$hname: json returned correctly" )
+ or diag "output: $output";
+
+$session->user({ user => $oldUser });
+
+# done testing the header stuff
my $newList = WebGUI::Asset::Template->getList($session, 'WebGUI Test Template');
ok(exists $newList->{$template->getId}, 'Uncommitted template exists returned from getList');