The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Reaction::Manual::Widgets - Creating and extending Reaction Widgets

WHAT IS A WIDGET

A widget represents the Perl code used by the layout. Which widget to use can be set with the =widget directive. For more on templates, look at Reaction::Manual::Templates.

The widget that is used defaults to a name built by the controller class and the name of the action. E.g. the action MyApp::Controller::Foo->bar would assume a widget named Foo::Bar and look for it in the widget_search_path defined in the share/skin/$skin_name/skin.conf or the share/skin/defaults.conf.

A SIMPLE WIDGET

The simplest widget would be this:

  package MyApp::Widget::Foo;
  use Reaction::UI::WidgetClass;

  use namespace::autoclean;
  
  __PACKAGE__->meta->make_immutable;
  
  1;

The use of Reaction::UI::WidgetClass will import strict, warnings, Moose and Reaction::Class. It will also set Reaction::UI::Widget as the base class of the widget. If you want to extend an existing widget rather than create a new one, use "extends" in Moose.

FRAGMENTS

Layouts can use the =for layout $fragment POD syntax to define fragments and use them like usual Template variables.

But sometimes it is desirable to have a fragment that invokes Perl code in the widget to render certain outputs. For this, the widget has its own mechanisms to handle fragments.

Implementing a fragment

A layout fragment can access the widgets attributes and other fragments like normal Template variables. But if a widget implements a fragment, that implementation will be used to provide the data and some additional control over the rendering of the layout.

This abstracts the data manipulation view logic from the layouting view logic.

A widget can implement a new fragment like this:

  package MyApp::Widget::Foo;
  use Reaction::UI::WidgetClass;
  
  use namespace::autoclean;
  
  implements fragment now {
      arg timestamp => time();
  };
  
  __PACKAGE__->meta->make_immutable;
  
  1;

Now we can layout the provided data like this:

  =widget Foo
  
  =for layout widget
  
  <h1>Info:</h1>
  
  [% now %]
  
  =for layout now
  
  <p>Timestamp: [% timestamp %]</p>
  
  =cut

The widget fragment is the root fragment of every widget. The widget directive sets the desired widget to Foo. One of our widget_search_paths should contain MyApp::Widget, so the widget class defined above can be found.

The widget fragment defined here will render the now fragment implemented by the widget and layed out by the layout template. Assuming the current timestamp is 1234567890, the rendered output will look like this:

  <h1>Info:</h1>
  
  <p>Timestamp: 1234567890</p>

Let us take a closer look at the fragment implementation in the widget:

  implements fragment now {
      arg timestamp => time();
  };

This syntax might look a bit unusual, but it's not a source filter. The declarative style is provided by Devel::Declare. This implements a fragment named now in the current widget. The body uses the arg keyword to provide a new argument timestamp to the template with the value of the current return value of time().

Extending a fragment

Sometimes you don't want to redefine how a fragment is implemented, but merely extend on the current definition. An example would be adding the total number of entries in a collection below the listing of the entries.

Fortunately, Reaction is based on Moose and trying to stay as flexible as possible. In this case, Reaction allows us to use Moose method modifiers with fragments:

  package MyApp::Widget::Bar;
  use Reaction::UI::WidgetClass;
  
  use namespace::autoclean;
  
  extends 'MyApp::Widget::Foo';
  
  around fragment now {
      call_next;
      arg timestamp => sprintf '"%s"', $_{timestamp};
  };
  
  __PACKAGE__->meta->make_immutable;
  
  1;

The call_next keyword will call the next implementation in the inheritance tree, just like it would call the next fragment when used in the layout template.

The global hash %_ is used to provide the fragment arguments to the code block implementing it. For example, the viewport would be available in $_{viewport}.

Besides around, you can also use before and after.

Iterating over a fragment

Many fragments are intended to be iterated over a collection of items. An example implementation of this is listed below:

  package MyApp::Widget::Baz
  use Reaction::UI::WidgetClass;
  
  use DateTime;
  
  use namespace::autoclean;
  
  my @Fields = qw( year month day hour minute second );
  
  implements fragment now {
      arg dt_obj => DateTime->now;
      render datetime_field => over [@Fields];
  };
  
  implements fragment datetime_field {
      arg field_name  => $_;
      arg field_value => $_{dt_obj}->$_();
  };
  
  __PACKAGE__->meta->make_immutable;
  
  1;

Which could have a layout template like this:

  =widget Baz
  
  =for layout widget
  
  <h1>Now:</h1>
  
  [% now %]
  
  =for layout now
  
  <ul>
  [% content %]
  </ul>
  
  =for layout datetime_field
  
  <li>[% field_name | ucfirst %]: [% field_value %]</li>
  
  =cut

The widget fragment defined in the layout template will render the now fragment implemented in the widget class. It is setting the dt_obj argument to a DateTime object representing the current date and time. Then it will render the fragment datetime_field once for every item in the @Fields array.

The global topic variable $_ will be set to each corresponding value in the arguments to over. The datetime_field fragment will then for each field name set field_name to the aforementioned value, and store the result of the method of that name on the dt_obj in the field_value argument.

The layout simply formats and puts the components in place.

WIDGETS PROVIDED BY REACTION

Reaction::UI::Widget::SiteLayout

The common wrapper around the fully rendered site.

Reaction::UI::Widget::ListView

Extends Reaction::UI::Widget::Grid to provide actions and paging.

Reaction::UI::Widget::Object

Rendering of a single object by a collection of viewports.

Reaction::UI::Widget::Container

A base class that automatically provides callbacks to render attributes containing viewports on the current viewport.

Reaction::UI::Widget::Collection

Renders a collection of member viewports in the current viewport.

Reaction::UI::Widget::Grid

A subclass of Reaction::UI::Widget::Collection providing header and footer as well as member actions. The default skin contains layout sets to output this widget as a HTML table.

Reaction::UI::Widget::Image

An image with optional width and height properties.

Reaction::UI::Widget::Field

Base widget for fields. Contains a list of subclasses.

Reaction::UI::Widget::Action

A widget representing a mutation of an object.

Object mutation widget rendering a hyperlink.

Reaction::UI::Widget::Data

Renders the data stored in the viewport's args attribute.

Reaction::UI::Widget::Value

Will take the value_string or value viewport method return value and provide it as argument value to the widget fragment. It also contains a list of subclasses.

Reaction::UI::Widget::URI

A hyperlink reference via an URI stored in the viewport.

SEE ALSO

AUTHORS

See Reaction::Class for authors.

LICENSE

See Reaction::Class for the license.