[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