[wellwell-devel] [wellwell/zoom] Add [zoom] tag for more sensible templating.
Stefan Hornburg
wellwell-devel at rt.icdevgroup.org
Sat Aug 14 07:10:16 UTC 2010
commit 8a5100c1c8d07763df8f43ff3ade010376cb9aa5
Author: Stefan Hornburg (Racke) <racke at linuxia.de>
Date: Sat Aug 14 09:06:30 2010 +0200
Add [zoom] tag for more sensible templating.
lib/WellWell/Zoom.pm | 209 +++++++++++++++++++++++++++++++++++
plugins/wishlists/code/wishlist.tag | 11 ++
2 files changed, 220 insertions(+), 0 deletions(-)
---
diff --git a/lib/WellWell/Zoom.pm b/lib/WellWell/Zoom.pm
new file mode 100644
index 0000000..eb645ad
--- /dev/null
+++ b/lib/WellWell/Zoom.pm
@@ -0,0 +1,209 @@
+# WellWell::Zoom - WellWell template parsing routines
+#
+# Copyright (C) 2010 Stefan Hornburg (Racke) <racke at linuxia.de>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package WellWell::Zoom;
+
+use strict;
+use warnings;
+
+use XML::Twig;
+use Rose::DB::Object::QueryBuilder qw(build_select);
+
+use Vend::Config;
+use Vend::Data;
+use Vend::Tags;
+
+Vend::Config::parse_tag('UserTag', 'zoom MapRoutine WellWell::Zoom::zoom');
+Vend::Config::parse_tag('UserTag', 'zoom Order function name');
+Vend::Config::parse_tag('UserTag', 'zoom AddAttr');
+Vend::Config::parse_tag('UserTag', 'zoom HasEndTag');
+
+# zoom - [zoom] tag
+
+sub zoom {
+ my ($function, $name, $opt, $body) = @_;
+
+ if ($function eq 'init') {
+ unless (exists $::Scratch->{zoom}) {
+ Vend::Tags->tmp('zoom', {});
+ }
+
+ $::Scratch->{zoom}->{$name}->{html} = $body;
+ $::Scratch->{zoom}->{$name}->{object} = parse_template($body, $opt->{specs});
+ }
+
+ if ($function eq 'display') {
+ my ($sref, $bref, $sql, $sth, $bind, %columns, $row, $key, $value, $lel, %paste_pos, $rep_str);
+
+ unless ($sref = $::Scratch->{zoom}->{$name}->{object}) {
+ die "Missing template $name\n";
+ }
+
+ $bref = $opt->{build};
+ $bref->{dbh} = database_exists_ref('products')->dbh();
+ $bref->{query_is_sql} = 1;
+
+ # now determine which fields are needed
+ while (($key, $value) = each %{$sref->{params}->{$name}->{hash}}) {
+ push @{$bref->{columns}->{$value->{table}}}, $key;
+ }
+
+ ($sql, $bind) = build_select(%$bref);
+
+ $sth = $bref->{dbh}->prepare($sql);
+ $sth->execute(@$bind);
+
+ $lel = $sref->{lists}->{$name}->[0]->{elts}->[0];
+
+ if ($lel->is_last_child()) {
+ %paste_pos = (last_child => $lel->parent());
+ }
+ else {
+ %paste_pos = (before => $lel->next_sibling());
+ }
+
+ $lel->cut();
+
+ while ($row = $sth->fetchrow_hashref) {
+ # now fill in params
+ while (($key, $value) = each %{$sref->{params}->{$name}->{hash}}) {
+ $rep_str = $row->{$key};
+
+ if ($value->{subref}) {
+ $rep_str = $value->{subref}->($row);
+ }
+
+ if ($value->{filter}) {
+ $rep_str = Vend::Tags->filter({op => $value->{filter}, body => $rep_str});
+ }
+
+ for my $elt (@{$value->{elts}}) {
+ if ($elt->{zoom_rep_att}) {
+ # replace attribute instead of embedded text (e.g. for <input>)
+ $elt->set_att($elt->{zoom_rep_att}, $rep_str);
+ }
+ elsif ($elt->{zoom_rep_elt}) {
+ # use provided text element for replacement
+ $elt->{zoom_rep_elt}->set_text($rep_str);
+ }
+ else {
+ $elt->set_text($rep_str);
+ }
+ }
+ }
+
+ # now add to the template
+ my $subtree = $lel->copy();
+
+ $subtree->paste(%paste_pos);
+ }
+
+ # replacements for simple values
+ while (($key, $value) = each %{$sref->{values}}) {
+ for my $elt (@{$value->{elts}}) {
+ if ($value->{scope} eq 'scratch') {
+ $rep_str = $::Scratch->{$key};
+ }
+
+ if ($value->{filter}) {
+ $rep_str = Vend::Tags->filter({op => $value->{filter}, body => $rep_str});
+ }
+
+ $elt->set_text($rep_str);
+ }
+ }
+
+ return $sref->{xml}->sprint;
+ }
+}
+
+# parse_template - Parse (HTML) template according to specifications
+
+sub parse_template {
+ my ($template, $specs) = @_;
+ my ($twig, $xml, $object);
+
+ $object = {specs => $specs, lists => {}, params => {}};
+
+ $twig = new XML::Twig (twig_handlers => {_all_ => sub {parse_handler($_[1], $object)}});
+ $xml = $twig->safe_parse($template);
+
+ unless ($xml) {
+ die "Invalid HTML template: $template\n";
+ }
+
+ $object->{xml} = $xml;
+ return $object;
+}
+
+# parse_handler - Callback for HTML elements
+
+sub parse_handler {
+ my ($elt, $sref) = @_;
+ my ($gi, $class, $name, $sob, $elt_text);
+
+ $gi = $elt->gi();
+ $class = $elt->att('class');
+
+ if (defined $class && exists $sref->{specs}->{class}->{$class}) {
+ $sob = $sref->{specs}->{class}->{$class};
+ $name = $sob->{name} || $class;
+
+ if ($sob->{type} eq 'list') {
+ $sob->{elts} = [$elt];
+
+ $sref->{lists}->{$name} = [$sob];
+ }
+ elsif ($sob->{type} eq 'param') {
+ push (@{$sob->{elts}}, $elt);
+
+ if ($gi eq 'input') {
+ # replace value attribute instead of text
+ $elt->{zoom_rep_att} = 'value';
+ }
+ elsif (! $elt->contains_only_text()) {
+ # contains real elements, so we have to be careful with
+ # set text and apply it only to the first PCDATA element
+ if ($elt_text = $elt->first_child('#PCDATA')) {
+ $elt->{zoom_rep_elt} = $elt_text;
+ }
+ }
+
+ if ($sob->{sub}) {
+ # determine code reference for named function
+ $sob->{subref} = $Vend::Cfg->{Sub}{$sob->{sub}} || $Global::GlobalSub->{$sob->{sub}};
+ }
+
+ $sref->{params}->{$sob->{list}}->{hash}->{$name} = $sob;
+ push(@{$sref->{params}->{$sob->{list}}->{array}}, $sob);
+ }
+ elsif ($sob->{type} eq 'value') {
+ push (@{$sob->{elts}}, $elt);
+ $sref->{values}->{$name} = $sob;
+ }
+ else {
+ next;
+ }
+ }
+
+ return $sref;
+}
+
+
+1;
diff --git a/plugins/wishlists/code/wishlist.tag b/plugins/wishlists/code/wishlist.tag
index a8f40c5..d660c62 100644
--- a/plugins/wishlists/code/wishlist.tag
+++ b/plugins/wishlists/code/wishlist.tag
@@ -233,6 +233,17 @@ sub {
my $sql = qq{select sku$fields from cart_products where cart = $wishlist_code order by position};
+ if ($opt->{zoom}) {
+ my %build;
+
+ %build = (tables => ['cart_products', 'products'],
+ columns => {cart_products => ['cart']},
+ clauses => ['T1.sku = T2.sku'],
+ query => [cart => $wishlist_code]);
+
+ return $Tag->zoom({function => 'display', name => 'wishlist', build => \%build});
+ }
+
return $Tag->query ({sql => $sql, list => 1, prefix => 'item',
body => $body});
}
More information about the wellwell-devel
mailing list