Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 7647d46a

Von Moritz Bunkus vor fast 12 Jahren hinzugefügt

  • ID 7647d46acbc2a8253c0afeac5c706c3eb76995d5
  • Vorgänger 42dfa9a7
  • Nachfolger ec27f677

Refactoring: Parameterredesign SL::Controller::Base::render und SL::Presenter::render

Conflicts:
SL/Controller/FinancialControllingReport.pm
SL/Controller/ProjectType.pm

Unterschiede anzeigen:

SL/Controller/Base.pm
60 60
  my $template           = shift;
61 61
  my ($options, %locals) = (@_ && ref($_[0])) ? @_ : ({ }, @_);
62 62

  
63
  $options->{type}       = lc($options->{type} || 'html');
64
  $options->{no_layout}  = 1 if $options->{type} eq 'js';
63
  # Set defaults for all available options.
64
  my %defaults = (
65
    type       => 'html',
66
    output     => 1,
67
    header     => 1,
68
    layout     => 1,
69
    process    => 1,
70
  );
71
  $options->{$_} //= $defaults{$_} for keys %defaults;
72
  $options->{type} = lc $options->{type};
73

  
74
  # Check supplied options for validity.
75
  foreach (keys %{ $options }) {
76
    croak "Unsupported option: $_" unless $defaults{$_};
77
  }
78

  
79
  # Only certain types are supported.
80
  croak "Unsupported type: " . $options->{type} unless $options->{type} =~ m/^(?:html|js|json)$/;
81

  
82
  # The "template" argument must be a string or a reference to one.
83
  croak "Unsupported 'template' reference type: " . ref($template) if ref($template) && (ref($template) !~ m/^(?:SCALAR|SL::Presenter::EscapedText)$/);
84

  
85
  # If all output is turned off then don't output the header either.
86
  if (!$options->{output}) {
87
    $options->{header} = 0;
88
    $options->{layout} = 0;
89

  
90
  } else {
91
    # Layout only makes sense if we're outputting HTML.
92
    $options->{layout} = 0 if $options->{type} ne 'html';
93
  }
94

  
95
  if ($options->{header}) {
96
    # Output the HTTP response and the layout in case of HTML output.
65 97

  
66
  if (!$options->{partial} && !$options->{inline} && !$::form->{header}) {
67
    if ($options->{no_layout}) {
98
    if ($options->{layout}) {
99
      $::form->{title} = $locals{title} if $locals{title};
100
      $::form->header;
101

  
102
    } else {
103
      # No layout: just the standard HTTP response. Also notify
104
      # $::form that the header has already been output so that
105
      # $::form->header() won't output it again.
68 106
      $::form->{header} = 1;
69
      my $content_type  = $options->{type} eq 'js' ? 'text/javascript' : 'text/html';
107
      my $content_type  = $options->{type} eq 'html' ? 'text/html'
108
                        : $options->{type} eq 'js'   ? 'text/javascript'
109
                        :                              'application/json';
70 110

  
71 111
      print $::form->create_http_response(content_type => $content_type,
72 112
                                          charset      => $::lx_office_conf{system}->{dbcharset} || Common::DEFAULT_CHARSET());
73

  
74
    } else {
75
      $::form->{title} = $locals{title} if $locals{title};
76
      $::form->header(no_menu => $options->{no_menu});
77 113
    }
78 114
  }
79 115

  
80
  my $output;
81
  if ($options->{raw}) {
82
    $output = $$template;
83
  } else {
84
    $output = $self->presenter->render(
85
      $template, $options,
86
      %locals,
87
      SELF => $self,
88
    );
89
  }
116
  # Let the presenter do the rest of the work.
117
  my $output = $self->presenter->render(
118
    $template,
119
    { type => $options->{type}, process => $options->{process} },
120
    %locals,
121
    SELF => $self,
122
  );
90 123

  
91
  print $output unless $options->{inline} || $options->{no_output};
124
  # Print the output if wanted.
125
  print $output if $options->{output};
92 126

  
93 127
  return $output;
94 128
}
......
334 368
C<$options>, if present, must be a hash reference. All remaining
335 369
parameters are slurped into C<%locals>.
336 370

  
337
What is rendered and how C<$template> is interpreted is determined by
338
the options I<type>, I<inline>, I<partial> and I<no_layout>. The
371
What is rendered and how C<$template> is interpreted is determined
372
both by C<$template>'s reference type and by the supplied options. The
339 373
actual rendering is handled by L<SL::Presenter/render>.
340 374

  
341
If C<< $options->{inline} >> is trueish then C<$template> is a string
342
containing the template code to interprete. Additionally the output
343
will not be sent to the browser. Instead it is only returned to the
344
caller.
375
If C<$template> is a normal scalar (not a reference) then it is meant
376
to be a template file name relative to the C<templates/webpages>
377
directory. The file name to use is determined by the C<type> option.
378

  
379
If C<$template> is a reference to a scalar then the referenced
380
scalar's content is used as the content to process. The C<type> option
381
is not considered in this case.
382

  
383
Other reference types, unknown options and unknown arguments to the
384
C<type> option cause the function to L<croak>.
385

  
386
The following options are available (defaults: C<type> = 'html',
387
C<process> = 1, C<output> = 1, C<header> = 1, C<layout> = 1):
388

  
389
=over 2
390

  
391
=item C<type>
345 392

  
346
If C<< $options->{raw} >> is trueish, the function will treat the
347
input as already parsed, and will not filter the input through
348
Template. This also means that L<SL::Presenter/render> is not
349
called either. Unlike C<inline>, the input is taken as a reference.
393
The template type. Can be C<html> (the default), C<js> for JavaScript
394
or C<json> for JSON content. Affects the extension that's added to the
395
file name given with a non-reference C<$template> argument, the
396
content type HTTP header that is output and whether or not the layout
397
will be output as well (see description of C<layout> below).
350 398

  
351
If C<< $options->{inline} >> is falsish then C<$template> is
352
interpreted as the name of a template file. It is prefixed with
353
"templates/webpages/" and postfixed with a file extension based on
354
C<< $options->{type} >>. C<< $options->{type} >> can be either C<html>
355
or C<js> and defaults to C<html>. An exception will be thrown if that
356
file does not exist.
399
=item C<process>
357 400

  
358
If C<< $options->{partial} >> or C<< $options->{inline} >> is trueish
359
then neither the HTTP response header nor the standard HTML header is
360
generated.
401
If trueish (which is also the default) it causes the template/content
402
to be processed by the Template toolkit. Otherwise the
403
template/content is output as-is.
361 404

  
362
Otherwise at least the HTTP response header will be generated based on
363
the template type (C<< $options->{type} >>).
405
=item C<output>
364 406

  
365
If the template type is C<html> then the standard HTML header will be
366
output via C<< $::form->header >> with C<< $::form->{title} >> set to
367
C<$locals{title}> (the latter only if C<$locals{title}> is
368
trueish). Setting C<< $options->{no_layout} >> to trueish will prevent
369
this.
407
If trueish (the default) then the generated output will be sent to the
408
browser in addition to being returned. If falsish then the options
409
C<header> and C<layout> are set to 0 as well.
410

  
411
=item C<header>
412

  
413
Determines whether or not to output the HTTP response
414
headers. Defaults to the same value that C<output> is set to. If set
415
to falsish then the layout is not output either.
416

  
417
=item C<layout>
418

  
419
Determines whether or not the basic HTML layout structure should be
420
output (HTML header, common JavaScript and stylesheet inclusions, menu
421
etc.). Defaults to 0 if C<type> is not C<html> and to the same value
422
C<header> is set to otherwise.
423

  
424
=back
370 425

  
371 426
The template itself has access to several variables. These are listed
372 427
in the documentation to L<SL::Presenter/render>.
373 428

  
374
Unless C<< $options->{inline} >> is trueish the function will send the
375
output to the browser.
376

  
377 429
The function will always return the output.
378 430

  
379 431
Example: Render a HTML template with a certain title and a few locals
......
383 435
                TODO_ITEMS => SL::DB::Manager::Todo->get_all_sorted);
384 436

  
385 437
Example: Render a string and return its content for further processing
386
by the calling function. No header is generated due to C<inline>.
438
by the calling function. No header is generated due to C<output>.
387 439

  
388
  my $content = $self->render('[% USE JavaScript %][% JavaScript.replace_with("#someid", "js/something") %]',
389
                              { type => 'js', inline => 1 });
440
  my $content = $self->render(\'[% USE JavaScript %][% JavaScript.replace_with("#someid", "js/something") %]',
441
                              { output => 0 });
390 442

  
391
Example: Render a JavaScript template and send it to the
443
Example: Render a JavaScript template
444
"templates/webpages/todo/single_item.js" and send it to the
392 445
browser. Typical use for actions called via AJAX:
393 446

  
394 447
  $self->render('todo/single_item', { type => 'js' },
SL/Controller/CustomVariableConfig.pm
17 17

  
18 18
  SL::DB::CustomVariableConfig->reorder_list(@{ $::form->{cvarcfg_id} || [] });
19 19

  
20
  $self->render('1;', { type => 'js', inline => 1 });
20
  $self->render(\'', { type => 'json' });
21 21
}
22 22

  
23 23
#
SL/Controller/Customer.pm
22 22
  $self->{customers} = SL::DB::Manager::Customer->get_all(query => [ @filter ], limit => $limit);
23 23
  $self->{value} = $::form->{column} || 'name';
24 24

  
25
  $self->render('ct/ajax_autocomplete2', { no_layout => 1 });
25
  $self->render('ct/ajax_autocomplete2', { layout => 0, type => 'json' });
26 26
}
27

  
SL/Controller/DeliveryPlan.pm
177 177
    controller_class      => 'DeliveryPlan',
178 178
    output_format         => 'HTML',
179 179
    top_info_text         => $::locale->text('Delivery Plan for currently outstanding sales orders'),
180
    raw_top_info_text     => $self->render('delivery_plan/report_top',    { no_output => 1, partial => 1 }),
181
    raw_bottom_info_text  => $self->render('delivery_plan/report_bottom', { no_output => 1, partial => 1 }),
180
    raw_top_info_text     => $self->render('delivery_plan/report_top',    { output => 0 }),
181
    raw_bottom_info_text  => $self->render('delivery_plan/report_bottom', { output => 0 }),
182 182
    title                 => $::locale->text('Delivery Plan'),
183 183
    allow_pdf_export      => 1,
184 184
    allow_csv_export      => 1,
SL/Controller/Layout.pm
3 3
use strict;
4 4
use parent qw(SL::Controller::Base);
5 5

  
6
use JSON ();
6
use SL::JSON ();
7 7

  
8 8
sub action_empty {
9 9
  my ($self) = @_;
......
20 20
      stylesheets_inline => [ $::request->{layout}->stylesheets_inline ],
21 21
    };
22 22

  
23
    $self->render(\ JSON::to_json($layout), { type => 'js', raw => 1 });
23
    $self->render(\ SL::JSON::to_json($layout), { type => 'json', process => 0 });
24 24
  }
25 25
}
26 26

  
SL/Controller/LoginScreen.pm
20 20
  return if $self->_redirect_to_main_script_if_already_logged_in;
21 21

  
22 22
  # Otherwise show the login form.
23
  $self->render('login_screen/user_login', { no_menu => 1 }, error => error_state($::form->{error}));
23
  $self->render('login_screen/user_login', error => error_state($::form->{error}));
24 24
}
25 25

  
26 26
sub action_logout {
......
28 28

  
29 29
  $::auth->destroy_session;
30 30
  $::auth->create_or_refresh_session;
31
  $self->render('login_screen/user_login', { no_menu => 1 }, error => $::locale->text('You are logged out!'));
31
  $self->render('login_screen/user_login', error => $::locale->text('You are logged out!'));
32 32
}
33 33

  
34 34
sub action_login {
......
57 57
  # Other login errors.
58 58
  if (0 > $result) {
59 59
    $::auth->punish_wrong_login;
60
    return $self->render('login_screen/user_login', { no_menu => 1 }, error => $::locale->text('Incorrect username or password!'));
60
    return $self->render('login_screen/user_login', error => $::locale->text('Incorrect username or password!'));
61 61
  }
62 62

  
63 63
  # Everything is fine.
SL/Controller/Part.pm
23 23
  $self->{parts} = SL::DB::Manager::Part->get_all(query => [ @filter ], limit => $limit);
24 24
  $self->{value} = $::form->{column} || 'description';
25 25

  
26
  $self->render('part/ajax_autocomplete', { no_layout => 1 });
26
  $self->render('part/ajax_autocomplete', { layout => 0, type => 'json' });
27 27
}
28 28

  
29 29

  
SL/Controller/PaymentTerm.pm
70 70

  
71 71
  SL::DB::PaymentTerm->reorder_list(@{ $::form->{payment_term_id} || [] });
72 72

  
73
  $self->render('1;', { type => 'js', inline => 1 });
73
  $self->render(\'', { type => 'json' });
74 74
}
75 75

  
76 76
#
SL/Controller/PriceFactor.pm
17 17

  
18 18
  SL::DB::PriceFactor->reorder_list(@{ $::form->{price_factor_id} || [] });
19 19

  
20
  $self->render('1;', { type => 'js', inline => 1 });
20
  $self->render(\'', { type => 'json' });
21 21
}
22 22

  
23 23
#
SL/Controller/Project.pm
262 262
    controller_class      => 'Project',
263 263
    output_format         => 'HTML',
264 264
    top_info_text         => $::locale->text('Projects'),
265
    raw_bottom_info_text  => $self->render('project/report_bottom', { no_output => 1, partial => 1 }),
265
    raw_bottom_info_text  => $self->render('project/report_bottom', { output => 0 }),
266 266
    title                 => $::locale->text('Projects'),
267 267
    allow_pdf_export      => 1,
268 268
    allow_csv_export      => 1,
SL/Controller/Unit.pm
17 17

  
18 18
  SL::DB::Unit->reorder_list(@{ $::form->{unit_id} || [] });
19 19

  
20
  $self->render('1;', { type => 'js', inline => 1 });
20
  $self->render(\'', { type => 'json' });
21 21
}
22 22

  
23 23
#
SL/Controller/Warehouse.pm
17 17

  
18 18
  SL::DB::Warehouse->reorder_list(@{ $::form->{warehouse_id} || [] });
19 19

  
20
  $self->render('1;', { type => 'js', inline => 1 });
20
  $self->render(\'', { type => 'json' });
21 21
}
22 22

  
23 23
#
SL/Dispatcher.pm
82 82
  $::form->{error}         = $::locale->text('The session is invalid or has expired.') if ($error_type eq 'session');
83 83
  $::form->{error}         = $::locale->text('Incorrect password!')                    if ($error_type eq 'password');
84 84

  
85
  $::form->header(no_menu => 1);
85
  $::form->header;
86 86
  print $::form->parse_html_template($template, \%params);
87 87
  $::lxdebug->leave_sub;
88 88

  
SL/JSON.pm
1
package SL::JSON;
2

  
3
use strict;
4

  
5
use JSON ();
6

  
7
use parent qw(Exporter);
8
our @EXPORT = qw(encode_json decode_json to_json from_json);
9

  
10
sub new {
11
  shift;
12
  return JSON->new(@_)->convert_blessed(1);
13
}
14

  
15
sub encode_json {
16
  return JSON->new->convert_blessed(1)->encode(@_);
17
}
18

  
19
sub decode_json {
20
  goto &JSON::decode_json;
21
}
22

  
23
sub to_json {
24
  my ($object, $options)      = @_;
25
  $options                  ||= {};
26
  $options->{convert_blessed} = 1;
27
  return JSON::to_json($object, $options);
28
}
29

  
30
sub from_json {
31
  goto &JSON::decode_json;
32
}
33

  
34
1;
35
__END__
36

  
37
=pod
38

  
39
=encoding utf8
40

  
41
=head1 NAME
42

  
43
SL::JSON - Thin wrapper around the JSON module that provides default options
44

  
45
=head1 SYNOPSIS
46

  
47
  use SL::JSON;
48

  
49
  my $escaped_text_object = SL::Presenter->get->render('some/template');
50
  my $json = encode_json($escaped_text_object);
51

  
52
=head1 OVERVIEW
53

  
54
JSON by default does not dump or stringify blessed
55
objects. kivitendo's rendering infrastructure always returns thin
56
proxy objects as instances of L<SL::Presenter::EscapedText>. This
57
module provides the same functions that L<JSON> does but changes their
58
default regarding converting blessed arguments.
59

  
60
=head1 FUNCTIONS
61

  
62
=over 4
63

  
64
=item C<decode_json $json>
65

  
66
Same as L<JSON/decode_json>.
67

  
68
=item C<encode_json $object>
69

  
70
Same as L<JSON/encode_json> but sets C<convert_blessed> first.
71

  
72
=item C<from_json $object [, $options]>
73

  
74
Same as L<JSON/from_json>.
75

  
76
=item C<to_json $object [, $options ]>
77

  
78
Same as L<JSON/to_json> but sets C<convert_blessed> first.
79

  
80
=back
81

  
82
=head1 BUGS
83

  
84
Nothing here yet.
85

  
86
=head1 AUTHOR
87

  
88
Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
89

  
90
=cut
SL/Layout/Javascript.pm
47 47
  $callback               = URI->new($callback)->rel($callback) if $callback;
48 48
  $callback               = "login.pl?action=company_logo"      if $callback =~ /^(\.\/)?$/;
49 49

  
50
  $self->render("menu/menunew", { partial => 1, no_output => 1 },
50
  $self->render("menu/menunew", { output => 0 },
51 51
    force_ul_width  => 1,
52 52
    date            => $self->clock_line,
53 53
    menu_items      => $self->acc_menu,
SL/Layout/MenuLeft.pm
14 14
sub javascripts_inline {
15 15
  my $self = shift;
16 16
  my $sections = [ section_menu($self->menu) ];
17
  $self->render('menu/menu', { partial => 1, no_output => 1 },
17
  $self->render('menu/menu', { output => 0 },
18 18
    sections  => $sections,
19 19
  )
20 20
}
SL/Layout/Top.pm
6 6
sub pre_content {
7 7
  my ($self) = @_;
8 8

  
9
  $self->SUPER::render('menu/header', { partial => 1, no_output => 1 },
9
  $self->SUPER::render('menu/header', { output => 0 },
10 10
                now        => DateTime->now_local,
11 11
                is_fastcgi => scalar($::dispatcher->interface_type =~ /fastcgi/i),
12 12
                is_links   => scalar($ENV{HTTP_USER_AGENT}         =~ /links/i));
SL/Layout/V3.pm
164 164
  $callback               = URI->new($callback)->rel($callback) if $callback;
165 165
  $callback               = "login.pl?action=company_logo"      if $callback =~ /^(\.\/)?$/;
166 166

  
167
  $self->SUPER::render('menu/menuv3', { no_menu => 1, no_output => 1 },
167
  $self->SUPER::render('menu/menuv3', { output => 0 },
168 168
    force_ul_width => 1,
169 169
    date           => $self->clock_line,
170 170
    menu           => $self->print_menu,
SL/Presenter.pm
25 25
  my $template           = shift;
26 26
  my ($options, %locals) = (@_ && ref($_[0])) ? @_ : ({ }, @_);
27 27

  
28
  $options->{type}       = lc($options->{type} || 'html');
28
  # Set defaults for all available options.
29
  my %defaults = (
30
    type       => 'html',
31
    process    => 1,
32
  );
33
  $options->{$_} //= $defaults{$_} for keys %defaults;
34
  $options->{type} = lc $options->{type};
29 35

  
30
  my $source;
31
  if ($options->{inline}) {
32
    $source = \$template;
36
  # Check supplied options for validity.
37
  foreach (keys %{ $options }) {
38
    croak "Unsupported option: $_" unless $defaults{$_};
39
  }
33 40

  
34
  } else {
41
  # Only certain types are supported.
42
  croak "Unsupported type: " . $options->{type} unless $options->{type} =~ m/^(?:html|js|json)$/;
43

  
44
  # The "template" argument must be a string or a reference to one.
45
  croak "Unsupported 'template' reference type: " . ref($template) if ref($template) && (ref($template) !~ m/^(?:SCALAR|SL::Presenter::EscapedText)$/);
46

  
47
  # Look for the file given by $template if $template is not a reference.
48
  my $source;
49
  if (!ref $template) {
35 50
    $source = "templates/webpages/${template}." . $options->{type};
36 51
    croak "Template file ${source} not found" unless -f $source;
52

  
53
  } elsif (ref($template) eq 'SCALAR') {
54
    # Normal scalar reference: hand over to Template
55
    $source = $template;
56

  
57
  } else {
58
    # Instance of SL::Presenter::EscapedText. Get reference to its content.
59
    $source = \$template->{text};
60
  }
61

  
62
  # If no processing is requested then return the content.
63
  if (!$options->{process}) {
64
    # If $template is a reference then don't try to read a file.
65
    return SL::Presenter::EscapedText->new(text => ${ $template }, is_escaped => 1) if ref $template;
66

  
67
    # Otherwise return the file's content.
68
    my $file    = IO::File->new($source, "r") || croak("Template file ${source} could not be read");
69
    my $content = do { local $/ = ''; <$file> };
70
    $file->close;
71

  
72
    return SL::Presenter::EscapedText->new(text => $content, is_escaped => 1);
37 73
  }
38 74

  
75
  # Processing was requested. Set up all variables.
39 76
  my %params = ( %locals,
40 77
                 AUTH          => $::auth,
41 78
                 FLASH         => $::form->{FLASH},
......
147 184
all of the parameters for controlling the output that the controller's
148 185
function does.
149 186

  
150
What is rendered and how C<$template> is interpreted is determined by
151
the options I<type> and I<inline>.
187
What is rendered and how C<$template> is interpreted is determined
188
both by C<$template>'s reference type and by the supplied options.
189

  
190
If C<$template> is a normal scalar (not a reference) then it is meant
191
to be a template file name relative to the C<templates/webpages>
192
directory. The file name to use is determined by the C<type> option.
152 193

  
153
If C<< $options->{inline} >> is trueish then C<$template> is a string
154
containing the template code to interprete.
194
If C<$template> is a reference to a scalar then the referenced
195
scalar's content is used as the content to process. The C<type> option
196
is not considered in this case.
155 197

  
156
If C<< $options->{inline} >> is falsish then C<$template> is
157
interpreted as the name of a template file. It is prefixed with
158
"templates/webpages/" and postfixed with a file extension based on
159
C<< $options->{type} >>. C<< $options->{type} >> can be either C<html>
160
or C<js> and defaults to C<html>. An exception will be thrown if that
161
file does not exist.
198
Other reference types, unknown options and unknown arguments to the
199
C<type> option cause the function to L<croak>.
162 200

  
163
The template itself has access to the following variables:
201
The following options are available:
202

  
203
=over 2
204

  
205
=item C<type>
206

  
207
The template type. Can be C<html> (the default), C<js> for JavaScript
208
or C<json> for JSON content. Affects only the extension that's added
209
to the file name given with a non-reference C<$template> argument.
210

  
211
=item C<process>
212

  
213
If trueish (which is also the default) it causes the template/content
214
to be processed by the Template toolkit. Otherwise the
215
template/content is returned as-is.
216

  
217
=back
218

  
219
If template processing is requested then the template has access to
220
the following variables:
164 221

  
165 222
=over 2
166 223

  
......
197 254
Example: Render a string and return its content for further processing
198 255
by the calling function.
199 256

  
200
  my $content = $presenter->render(
201
    '[% USE JavaScript %][% JavaScript.replace_with("#someid", "js/something") %]',
202
    { type => 'js', inline => 1 }
257
  my $content = $presenter->render(\'[% USE JavaScript %][% JavaScript.replace_with("#someid", "js/something") %]');
258

  
259
Example: Return the content of a JSON template file without processing
260
it at all:
261

  
262
  my $template_content = $presenter->render(
263
    'customer/contact',
264
    { type => 'json', process => 0 }
203 265
  );
204 266

  
205 267
=item C<escape $text>
SL/Presenter/EscapedText.pm
2 2

  
3 3
use strict;
4 4

  
5
use JSON ();
6

  
5 7
use overload '""' => \&escaped;
6 8

  
7 9
sub new {
......
20 22
  return $self->{text};
21 23
}
22 24

  
25
sub TO_JSON {
26
  goto &escaped;
27
}
28

  
23 29
1;
24 30
__END__
25 31

  
SL/Template/Plugin/JSON.pm
21 21
  my ($self, %params) = @_;
22 22

  
23 23
  if (!$self->{json}) {
24
    $self->{json} = JSON->new->allow_nonref(1);
24
    $self->{json} = JSON->new->allow_nonref(1)->convert_blessed(1);
25 25

  
26 26
    my $args = $self->{json_args};
27 27

  
t/controllers/base/render.t
1
use strict;
2
use Test::Exception;
3
use Test::More;
4
use Test::Output;
5

  
6
use lib 't';
7
use Support::TestSetup;
8

  
9
use SL::Presenter;
10

  
11
no warnings 'uninitialized';
12

  
13
Support::TestSetup::login();
14

  
15
sub reset_test_env {
16
  $ENV{HTTP_USER_AGENT} = 'Perl Tests';
17

  
18
  $::request       = {
19
    cgi => CGI->new({}),
20
    layout => SL::Layout::Javascript->new,
21
  };
22

  
23
  $::myconfig{stylesheet} = 'javascript';
24

  
25
  delete @{ $::form }{qw(header footer)};
26
}
27

  
28
my $ctrl = SL::Controller::Base->new;
29

  
30
# Passing invalid parameters:
31
throws_ok { $ctrl->render(\'dummy', { unknown => 1 }) }    qr/unsupported option/i,                     'string ref, unknown parameter';
32
throws_ok { $ctrl->render(\'dummy', { type => "excel" }) } qr/unsupported type/i,                       'string ref, unsupported "type"';
33
throws_ok { $ctrl->render({}) }                            qr/unsupported.*template.*reference.*type/i, 'string ref, unsupported template argument reference type';
34
throws_ok { $ctrl->render('does/not/exist') }              qr/template.*file.*not.*found/i,             'non-existing template file name';
35

  
36
# No output:
37
stdout_is { $ctrl->render(\'Hallo', { output => 0 }) } '', 'no output';
38

  
39
# Type of return value:
40
is(ref($ctrl->render(\'Hallo', { output => 0 })), 'SL::Presenter::EscapedText', 'render returns SL::Presenter::EscapedText');
41

  
42
# Actual return value for string ref parameters (enforce stringification from SL::Presenter::EscapedText before comparison):
43
is("" . $ctrl->render(\'Hallo [% world %]', { output => 0 }, world => 'Welt'),               'Hallo Welt',        'render string ref, no output');
44
is("" . $ctrl->render(\'Hallo [% world %]', { output => 0, process => 0 }, world => 'Welt'), 'Hallo [% world %]', 'render string ref, no output, no processing');
45
is("" . $ctrl->render(\'Hallo [% world %]', { output => 0, type => 'js' }, world => 'Welt'), 'Hallo Welt',        'render string ref, no output, different type');
46

  
47
# Actual return value for template file name parameters (enforce stringification from SL::Presenter::EscapedText before comparison):
48
is("" . $ctrl->render('t/render', { output => 0 }, world => 'Welt'),                      "Hallo Welt\n",                                       'render template file, no args');
49
is("" . $ctrl->render('t/render', { output => 0, process => 0 }, world  => 'Welt'),   "[\% USE HTML \%]Hallo [\% HTML.escape(world) \%]\n", 'render template file, no processing');
50
is("" . $ctrl->render('t/render', { output => 0, type => 'js' }, thingy => 'jungle'), "Welcome to the jungle\n",                            'render template file, different type');
51

  
52
# No HTTP header in screen output:
53
reset_test_env();
54
stdout_unlike { $ctrl->render(\'Hallo [% world %]', { header => 0 }, world => 'Welt') } qr/content-type/i, 'no HTTP header with header=0';
55

  
56
reset_test_env();
57
stdout_unlike { $ctrl->render(\'Hallo [% world %]', { header => 0 }, world => 'Welt') } qr/<html>/i,       'no HTML header with header=0';
58

  
59
# With HTTP header in screen output:
60
reset_test_env();
61
stdout_like { $ctrl->render(\'Hallo [% world %]', world => 'Welt') } qr/content-type/i, 'HTTP header with header=1';
62

  
63
reset_test_env();
64
stdout_like { $ctrl->render(\'Hallo [% world %]', world => 'Welt') } qr/<html>/i,       'HTML header with header=1';
65

  
66
# Menu yes/no:
67
reset_test_env();
68
stdout_like { $ctrl->render(\'Hallo [% world %]', world => 'Welt') } qr/<table.*class=.*menunew/i, 'HTML header & menu with header=1';
69

  
70
reset_test_env();
71
stdout_unlike { $ctrl->render(\'Hallo [% world %]', { header => 0 }, world => 'Welt') } qr/<table.*class=.*menunew/i, 'HTML header & menu with header=0';
72

  
73
reset_test_env();
74
stdout_unlike { $ctrl->render(\'Hallo [% world %]', { layout => 0 }, world => 'Welt') } qr/<table.*class=.*menunew/i, 'HTML header & menu with layout=0';
75

  
76
done_testing;
77

  
78
1;
t/presenter/base/render.t
1
use strict;
2
use Test::Exception;
3
use Test::More;
4

  
5
use lib 't';
6
use Support::TestSetup;
7

  
8
use SL::Presenter;
9

  
10
Support::TestSetup::login();
11

  
12
my $pr = SL::Presenter->get;
13

  
14
# Passing invalid parameters:
15
throws_ok { $pr->render(\'dummy', { unknown => 1 }) }    qr/unsupported option/i,                     'string ref, unknown parameter';
16
throws_ok { $pr->render(\'dummy', { type => "excel" }) } qr/unsupported type/i,                       'string ref, unsupported "type"';
17
throws_ok { $pr->render({}) }                            qr/unsupported.*template.*reference.*type/i, 'string ref, unsupported template argument reference type';
18
throws_ok { $pr->render('does/not/exist') }              qr/template.*file.*not.*found/i,             'non-existing template file name';
19

  
20
# Type of return value:
21
is(ref($pr->render(\'Hallo')), 'SL::Presenter::EscapedText', 'render returns SL::Presenter::EscapedText');
22

  
23
# Actual return value for string ref parameters (enforce stringification from SL::Presenter::EscapedText before comparison):
24
is("" . $pr->render(\'Hallo [% world %]', world => 'Welt'),                   'Hallo Welt',        'render string ref, no args');
25
is("" . $pr->render(\'Hallo [% world %]', { process => 0 }, world => 'Welt'), 'Hallo [% world %]', 'render string ref, no processing');
26
is("" . $pr->render(\'Hallo [% world %]', { type => 'js' }, world => 'Welt'), 'Hallo Welt',        'render string ref, different type');
27

  
28
# Actual return value for template file name parameters (enforce stringification from SL::Presenter::EscapedText before comparison):
29
is("" . $pr->render('t/render', world => 'Welt'),                      "Hallo Welt\n",                                       'render template file, no args');
30
is("" . $pr->render('t/render', { process => 0 }, world  => 'Welt'),   "[\% USE HTML \%]Hallo [\% HTML.escape(world) \%]\n", 'render template file, no processing');
31
is("" . $pr->render('t/render', { type => 'js' }, thingy => 'jungle'), "Welcome to the jungle\n",                            'render template file, different type');
32

  
33
done_testing;
34

  
35
1;
t/test.sh
6 6
  else
7 7
    echo -- "$@"
8 8
  fi
9
} | HARNESS_OPTIONS=j:c xargs perl -Imodules/override -MTest::Harness -e 'BEGIN { push @INC, "modules/fallback" } runtests(@ARGV)'
9
} | HARNESS_OPTIONS=j:c xargs perl -X -Imodules/override -MTest::Harness -e 'BEGIN { push @INC, "modules/fallback" } runtests(@ARGV)'
templates/webpages/ct/ajax_autocomplete2.html
1
[%- USE HTML %][% USE JSON %][
2
[%- FOREACH customer = SELF.customers %]
3
 {
4
   "value": [% customer.${SELF.value}.json %],
5
   "label": [% customer.displayable_name.json %],
6
   "id": [% customer.id.json %],
7
   "customernumber": [% customer.customernumber.json %],
8
   "name": [% customer.name.json %]
9
  }[% ',' UNLESS loop.last %]
10
[%- END %]
11
]
templates/webpages/ct/ajax_autocomplete2.json
1
[%- USE HTML %][% USE JSON %][
2
[%- FOREACH customer = SELF.customers %]
3
 {
4
   "value": [% customer.${SELF.value}.json %],
5
   "label": [% customer.displayable_name.json %],
6
   "id": [% customer.id.json %],
7
   "customernumber": [% customer.customernumber.json %],
8
   "name": [% customer.name.json %]
9
  }[% ',' UNLESS loop.last %]
10
[%- END %]
11
]
templates/webpages/part/ajax_autocomplete.html
1
[%- USE HTML %][% USE JSON %][
2
[%- FOREACH part = SELF.parts %]
3
[%- ajax_autocomplete__label = part.partnumber _ " " _ part.description %]
4
 {
5
   "value": [% part.${SELF.value}.json %],
6
   "label": [% ajax_autocomplete__label.json %],
7
   "id": [% part.id.json %],
8
   "partnumber": [% part.partnumber.json %],
9
   "description": [% part.description.json %],
10
   "type": [% part.type.json %]
11
  }[% ',' UNLESS loop.last %]
12
[%- END %]
13
]
templates/webpages/part/ajax_autocomplete.json
1
[%- USE HTML %][% USE JSON %][
2
[%- FOREACH part = SELF.parts %]
3
[%- ajax_autocomplete__label = part.partnumber _ " " _ part.description %]
4
 {
5
   "value": [% part.${SELF.value}.json %],
6
   "label": [% ajax_autocomplete__label.json %],
7
   "id": [% part.id.json %],
8
   "partnumber": [% part.partnumber.json %],
9
   "description": [% part.description.json %],
10
   "type": [% part.type.json %]
11
  }[% ',' UNLESS loop.last %]
12
[%- END %]
13
]
templates/webpages/t/render.html
1
[% USE HTML %]Hallo [% HTML.escape(world) %]
templates/webpages/t/render.js
1
Welcome to the [% thingy %]

Auch abrufbar als: Unified diff