Changeset 2973
- Timestamp:
- 08/25/08 23:05:34 (3 months ago)
- Files:
-
- trunk/lib/MT/Builder.pm (modified) (12 diffs)
- trunk/lib/MT/CMS/Template.pm (modified) (2 diffs)
- trunk/lib/MT/Template.pm (modified) (11 diffs)
- trunk/lib/MT/Template/Node.pm (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/lib/MT/Builder.pm
r2212 r2973 9 9 use strict; 10 10 use base qw( MT::ErrorHandler ); 11 use MT:: Util qw( weaken );11 use MT::Template::Node; 12 12 13 13 sub NODE () { 'MT::Template::Node' } … … 80 80 # tag name, attribute hashref, contained tokens, template text, 81 81 # attributes arrayref, parent array reference 82 my $rec = bless [ $tag, \my %args, undef, undef, \my @args ], NODE;82 my $rec = NODE->new(tag => $tag, attributes => \my %args, attribute_list => \my @args); 83 83 while ($args =~ / 84 84 (?: … … 153 153 : substr $text, $sec_start, $sec_end - $sec_start; 154 154 if ($sec !~ m/<\$?MT/i) { 155 $rec-> [2] = [ ($sec ne '' ? ['TEXT', $sec ] : ()) ];155 $rec->childNodes([ ($sec ne '' ? NODE->new(tag => 'TEXT', nodeValue => $sec) : ()) ]); 156 156 } 157 157 else { 158 158 local $opt->{depth} = $opt->{depth} + 1; 159 159 local $opt->{parent} = $rec; 160 $rec-> [2] = $build->compile($ctx, $sec, $opt);160 $rec->childNodes($build->compile($ctx, $sec, $opt)); 161 161 if ( @$errors ) { 162 162 my $pre_error = substr($text, 0, $sec_start); … … 185 185 # } 186 186 } 187 $rec-> [3] = $secif $opt->{uncompiled};187 $rec->nodeValue($sec) if $opt->{uncompiled}; 188 188 } 189 189 else { … … 206 206 } 207 207 else { 208 $rec-> [3] = '';209 } 210 } 211 weaken($rec->[5] =$opt->{parent} || $tmpl);212 weaken($rec->[6] =$tmpl);208 $rec->nodeValue(''); 209 } 210 } 211 $rec->parentNode($opt->{parent} || $tmpl); 212 $rec->template($tmpl); 213 213 push @{ $state->{tokens} }, $rec; 214 214 $pos = pos $text; … … 257 257 my $text = substr ${ $_[0]->{text} }, $_[1], $_[2] - $_[1]; 258 258 if ((defined $text) && ($text ne '')) { 259 my $rec = bless [ 'TEXT', $text, undef, undef, undef, $_[0]->{tokens}, $_[0]->{tmpl} ], NODE; 260 # Avoids circular reference between NODE and TOKENS, MT::Template. 261 weaken($rec->[5]); 262 weaken($rec->[6]); 259 my $rec = NODE->new(tag => 'TEXT', nodeValue => $text, parentNode => $_[0]->{tokens}, template => $_[0]->{tmpl}); 263 260 push @{ $_[0]->{tokens} }, $rec; 264 261 } … … 269 266 my $string = ''; 270 267 foreach my $t (@$tokens) { 271 my ($name, $args, $tokens, $uncompiled) = @$t;268 my ($name, $args, $tokens, $uncompiled) = ($t->tag, $t->attributes, $t->childNodes, $t->nodeValue); 272 269 $string .= (" " x $depth) . $name; 273 270 if (ref $args eq 'HASH') { … … 305 302 306 303 for my $t (@$tokens) { 307 if ($t-> [0]eq 'TEXT') {308 $res .= $t-> [1];304 if ($t->tag eq 'TEXT') { 305 $res .= $t->nodeValue; 309 306 } else { 310 307 my($tokens, $tokens_else, $uncompiled); 311 my $tag = lc $t-> [0];308 my $tag = lc $t->tag; 312 309 if ($cond && (exists $cond->{ $tag } && !$cond->{ $tag })) { 313 310 # if there's a cond for this tag and it's false, 314 311 # walk the children and look for an MTElse. 315 312 # the children of the MTElse will become $tokens 316 for my $tok (@{ $t->[2] }) { 317 if (lc $tok->[0] eq 'else' || lc $tok->[0] eq 'elseif') { 318 $tokens = $tok->[2]; 319 $uncompiled = $tok->[3]; 313 for my $tok (@{ $t->childNodes }) { 314 my $tag = lc $tok->tag; 315 if ($tag eq 'else' || $tag eq 'elseif') { 316 $tokens = $tok->childNodes; 317 $uncompiled = $tok->nodeValue; 320 318 last; 321 319 } … … 323 321 next unless $tokens; 324 322 } else { 325 if ($t->[2] && ref($t->[2])) { 323 my $childNodes = $t->childNodes; 324 if ($childNodes && ref($childNodes)) { 326 325 # either there is no cond for this tag, or it's true, 327 326 # so we want to partition the children into 328 327 # those which are inside an else and those which are not. 329 328 ($tokens, $tokens_else) = ([], []); 330 for my $sub (@{ $t->[2] }) { 331 if (lc $sub->[0] eq 'else' || lc $sub->[0] eq 'elseif') { 329 for my $sub (@$childNodes) { 330 my $tag = lc $sub->tag; 331 if ($tag eq 'else' || $tag eq 'elseif') { 332 332 push @$tokens_else, $sub; 333 333 } else { … … 336 336 } 337 337 } 338 $uncompiled = $t-> [3];339 } 340 my($h, $type) = $ctx->handler_for($t-> [0]);338 $uncompiled = $t->nodeValue; 339 } 340 my($h, $type) = $ctx->handler_for($t->tag); 341 341 if ($h) { 342 342 $timer->pause_partial if $timer; 343 local($ctx->{__stash}{tag}) = $t-> [0];343 local($ctx->{__stash}{tag}) = $t->tag; 344 344 local($ctx->{__stash}{tokens}) = ref($tokens) ? bless $tokens, 'MT::Template::Tokens' : undef; 345 345 local($ctx->{__stash}{tokens_else}) = ref($tokens_else) ? bless $tokens_else, 'MT::Template::Tokens' : undef; 346 346 local($ctx->{__stash}{uncompiled}) = $uncompiled; 347 my %args = %{$t-> [1]} if defined $t->[1];348 my @args = @{$t-> [4]} if defined $t->[4];347 my %args = %{$t->attributes} if defined $t->attributes; 348 my @args = @{$t->attribute_list} if defined $t->attribute_list; 349 349 350 350 # process variables … … 387 387 my $err = $ctx->errstr; 388 388 if (defined $err) { 389 return $build->error(MT->translate("Error in <mt[_1]> tag: [_2]", $t-> [0], $ctx->errstr));389 return $build->error(MT->translate("Error in <mt[_1]> tag: [_2]", $t->tag, $ctx->errstr)); 390 390 } 391 391 else { … … 414 414 if ($timer) { 415 415 $timer->mark("tag_" 416 . lc($t-> [0]) . args_to_string(\%args));416 . lc($t->tag) . args_to_string(\%args)); 417 417 } 418 418 } else { 419 if ($t-> [0]!~ m/^_/) { # placeholder tag. just ignore420 return $build->error(MT->translate("Unknown tag found: [_1]", $t-> [0]));419 if ($t->tag !~ m/^_/) { # placeholder tag. just ignore 420 return $build->error(MT->translate("Unknown tag found: [_1]", $t->tag)); 421 421 } 422 422 } trunk/lib/MT/CMS/Template.pm
r2887 r2973 145 145 foreach my $tag (@$includes) { 146 146 my $include = {}; 147 my $mod = $include->{include_module} = $tag->[1]->{module} || $tag->[1]->{widget}; 147 my $attr = $tag->attributes; 148 my $mod = $include->{include_module} = $attr->{module} || $attr->{widget}; 148 149 next unless $mod; 149 my $type = $ tag->[1]->{widget} ? 'widget' : 'custom';150 my $type = $attr->{widget} ? 'widget' : 'custom'; 150 151 next if exists $seen{$type}{$mod}; 151 152 $seen{$type}{$mod} = 1; … … 208 209 my %seen; 209 210 foreach my $set (@sets) { 210 my $name = $set-> [1]->{name};211 my $name = $set->attributes->{name}; 211 212 next unless $name; 212 213 next if $seen{$name}; trunk/lib/MT/Template.pm
r2882 r2973 11 11 use MT::Util qw( weaken ); 12 12 13 use MT::Template::Node; 13 14 sub NODE () { 'MT::Template::Node' } 14 15 sub NODE_TEXT () { 1 }16 sub NODE_BLOCK () { 2 }17 sub NODE_FUNCTION () { 3 }18 15 19 16 my $resync_to_db; … … 188 185 my $str = ''; 189 186 foreach my $token (@$tokens) { 190 if ($token->[0] eq 'TEXT') { 191 $str .= $token->[1]; 187 my $tag = $token->tag; 188 if ($tag eq 'TEXT') { 189 $str .= $token->nodeValue; 192 190 } else { 193 my $tag = $token->[0];194 191 $str .= '<mt' . $tag; 195 if (my $attrs = $token-> [4]) {196 my $attrh = $token-> [1];192 if (my $attrs = $token->attribute_list) { 193 my $attrh = $token->attributes; 197 194 foreach my $a (@$attrs) { 198 195 delete $attrh->{$a->[0]}; … … 208 205 } 209 206 $str .= '>'; 210 if ( $token->[2]) {207 if (my $childNodes = $token->childNodes) { 211 208 # container tag 212 $str .= $tmpl->reflow( $token->[2]);209 $str .= $tmpl->reflow($childNodes); 213 210 $str .= '</mt' . $tag . '>'; 214 211 } … … 552 549 return unless $tokens; 553 550 foreach my $t (@$tokens) { 554 if ($t-> [0]ne 'TEXT') {555 if ( $t->[1]->{id}) {551 if ($t->tag ne 'TEXT') { 552 if (my $id = $t->getAttribute('id')) { 556 553 my $ids = $tmpl->{__ids} ||= {}; 557 $ids->{lc $ t->[1]->{id}} = $t;554 $ids->{lc $id} = $t; 558 555 } 559 elsif ( $t->[1]->{class}) {556 elsif (my $class = $t->getAttribute('class')) { 560 557 my $classes = $tmpl->{__classes} ||= {}; 561 push @{ $classes->{lc $ t->[1]->{class}} ||= [] }, $t;558 push @{ $classes->{lc $class} ||= [] }, $t; 562 559 } 563 $tmpl->rescan($t->[2]) if $t->[2]; 560 if (my $childNodes = $t->childNodes) { 561 $tmpl->rescan($childNodes); 562 } 564 563 } 565 564 } … … 712 711 my ($id) = @_; 713 712 if (my $node = $tmpl->token_ids->{$id}) { 714 return bless $node, NODE;713 return $node; 715 714 } 716 715 undef; … … 720 719 my $tmpl = shift; 721 720 my ($tag, $attr) = @_; 722 my $node = bless [ $tag, $attr, undef, undef, undef, undef, $tmpl ], NODE; 723 weaken($node->[6]); 724 return $node; 721 return NODE->new(tag => $tag, attributes => $attr, template => $tmpl); 725 722 } 726 723 … … 728 725 my $tmpl = shift; 729 726 my ($text) = @_; 730 my $node = bless [ 'TEXT', $text, undef, undef, undef, undef, $tmpl ], NODE; 731 weaken($node->[6]); 732 return $node; 727 return NODE->new(tag => 'TEXT', nodeValue => $text, template => $tmpl); 733 728 } 734 729 … … 809 804 810 805 use strict; 811 sub NODE_TEXT () { 1 }812 sub NODE_BLOCK () { 2 }813 sub NODE_FUNCTION () { 3 }814 806 815 807 sub getElementsByTagName { … … 818 810 $name = lc $name; 819 811 foreach my $t (@$tokens) { 820 if (lc $t-> [0]eq $name) {812 if (lc $t->tag eq $name) { 821 813 push @list, $t; 822 814 } 823 if ( $t->[2]) {824 my $subt = getElementsByTagName($ t->[2], $name);815 if (my $childNodes = $t->childNodes) { 816 my $subt = getElementsByTagName($childNodes, $name); 825 817 push @list, @$subt if $subt; 826 818 } … … 834 826 $name = lc $name; 835 827 foreach my $t (@$tokens) { 836 if ( (ref($t->[1]) eq 'HASH') && (lc ($t->[1]{'name'} || '') eq $name)) {828 if (lc ($t->getAttribute('name') || '') eq $name) { 837 829 push @list, $t; 838 830 } 839 if ( $t->[2]) {840 my $subt = getElementsByName($ t->[2], $name);831 if (my $childNodes = $t->childNodes) { 832 my $subt = getElementsByName($childNodes, $name); 841 833 push @list, @$subt if $subt; 842 834 } … … 844 836 scalar @list ? \@list : undef; 845 837 } 846 847 package MT::Template::Node;848 849 use strict;850 use MT::Util qw( weaken );851 852 sub setAttribute {853 my $node = shift;854 my ($attr, $val) = @_;855 if ($attr eq 'id') {856 # assign into ids857 my $tmpl = $node->template;858 my $ids = $tmpl->token_ids;859 my $old_id = $node->getAttribute("id");860 if ($old_id && $ids) {861 delete $ids->{$old_id};862 }863 }864 elsif ($attr eq 'class') {865 # assign into classes866 my $tmpl = $node->template;867 my $classes = $tmpl->token_classes;868 my $old_class = $node->getAttribute("class");869 if ($old_class && $classes->{$old_class}) {870 @{$classes->{$old_class}} = grep { $_ != $node }871 @{$classes->{$old_class}};872 }873 push @{$classes->{$val} ||= []}, $node;874 }875 ($node->[1] ||= {})->{$attr} = $val;876 }877 878 sub template {879 my $node = shift;880 return $node->[6];881 }882 883 sub getAttribute {884 my $node = shift;885 my ($attr) = @_;886 ($node->[1] || {})->{$attr};887 }888 889 # sub attributes {890 # my $node = shift;891 # return $node->[1] ||= {};892 # }893 894 sub nextSibling {895 my $node = shift;896 my $parent = $node->parentNode->childNodes;897 my $max = (scalar @$parent) - 1;898 return undef unless $max;899 my $last = $parent->[0];900 foreach my $n ($parent->[1..$max]) {901 return $n if $node == $last;902 $last = $n;903 }904 return $parent->[$max] if $node == $last;905 return undef;906 }907 908 sub lastChild {909 my $node = shift;910 my $children = $node->childNodes or return undef;911 @$children ? $children->[scalar @$children - 1] : undef;912 }913 914 sub firstChild {915 my $node = shift;916 my $children = $node->[2] or return undef;917 @$children ? $children->[0] : undef;918 }919 920 sub previousSibling {921 my $node = shift;922 my $parent = $node->parentNode->childNodes;923 my $last;924 foreach my $n (@$parent) {925 return $last if $node == $n;926 $last = $n;927 }928 return undef;929 }930 931 sub parentNode {932 my $node = shift;933 weaken($node->[5] = shift) if @_;934 $node->[5];935 }936 937 sub childNodes {938 my $node = shift;939 $node->[2] = shift if @_;940 $node->[2];941 }942 943 sub ownerDocument { #template944 my $node = shift;945 return $node->template;946 }947 948 sub hasChildNodes {949 my $node = shift;950 $node->[2] && (@{$node->[2]}) ? 1 : 0;951 }952 953 sub nodeType {954 my $node = shift;955 if ($node->[0] eq 'TEXT') {956 return NODE_TEXT();957 } elsif (defined $node->[2]) {958 return NODE_BLOCK();959 } else {960 return NODE_FUNCTION();961 }962 }963 964 sub nodeName {965 my $node = shift;966 if ($node->[0] eq 'TEXT') {967 return undef;968 }969 # normalize:970 # MTEntry => mt:entry971 # MTAPP:WIDGET => mtapp:widget972 my $tag = lc $node->[0];973 if (($tag !~ m/:/) && ($tag =~ m/^mt/)) {974 $tag =~ s/^mt/mt:/;975 }976 return $tag;977 }978 979 # Returns text of a text node; inner text for a block tag, or undef980 # for a function tag.981 sub nodeValue {982 my $node = shift;983 if ($node->[0] eq 'TEXT') {984 return $node->[1];985 } else {986 if (defined $node->[3]) {987 return $node->[3];988 }989 }990 return undef;991 }992 993 sub innerHTML {994 my $node = shift;995 if (@_) {996 my ($text) = @_;997 $node->[3] = $text;998 my $builder = new MT::Builder;999 my $ctx = MT::Template::Context->new;1000 $node->[2] = $builder->compile($ctx, $text);1001 my $tmpl = $node->ownerDocument;1002 if ($tmpl) {1003 $tmpl->reset_markers;1004 $tmpl->{reflow_flag} = 1;1005 }1006 }1007 return $node->[3];1008 }1009 1010 # TBD: what about new nodes that are added with id elements?1011 sub appendChild {1012 my $node = shift;1013 my ($new_node) = @_;1014 my $nodes = $node->childNodes;1015 push @$nodes, $new_node;1016 my $tmpl = $node->ownerDocument;1017 if ($tmpl) {1018 $tmpl->{reflow_flag} = 1;1019 }1020 }1021 1022 sub removeChild {1023 my $node = shift;1024 }1025 1026 *inner_html = \&innerHTML;1027 *append_child = \&appendChild;1028 *insert_before = \&insertBefore;1029 *remove_child = \&removeChild;1030 838 1031 839 # trans('Index')
