NAME
App::ZofCMS::Plugin::PreferentialOrder - Display HTML snippets in user-controllable, savable order
EXTRA RESOURCES (BEYOND PERL)
This plugin was designed to be used in conjunction with JavaScript (JS) code that controls the order of items on the page and submits that information to the server.
If you wish to use a different, your own front-end, please study JS code provided at the end of this documentation to understand what is required.
SYNOPSIS
In your HTML::Template template:
<tmpl_var name='plug_pref_order_form'>
<tmpl_var name='plug_pref_order_list'>
<tmpl_var name='plug_pref_order_disabled_list'>
In your ZofCMS template:
plugins => [ qw/PreferentialOrder/, ],
# except for the mandatory argument `items`, the default values are shown
plug_preferential_order => {
items => [ # four value type variations shown here
forum3 => '<a href="#">Forum3</a>',
forum4 => [ 'Last forum ":)"', \'forum-template.tmpl', ],
forum => [ 'First forum ":)"', '<a href="#">Forum</a>', ],
forum2 => [
'Second forum ":)"',
sub {
my ( $t, $q, $config ) = @_;
return '$value_for_the_second_element_in_the_arrayref';
},
],
],
dsn => "DBI:mysql:database=test;host=localhost",
user => '',
pass => undef,
opt => { RaiseError => 1, AutoCommit => 1 },
users_table => 'users',
order_col => 'plug_pref_order',
login_col => 'login',
order_login => sub { $_[0]->{d}{user}{login} },
separator => ',',
has_disabled => 1,
enabled_label => q|<p class="ppof_label">Enabled items</p>|,
disabled_label => q|<p class="ppof_label">Disabled items</p>|,
submit_button => q|<input type="submit" class="input_submit"|
. q| value="Save">|,
},
DESCRIPTION
The module is a plugin for App::ZofCMS that provides means to have a sortable list of custom HTML snippets. The order can be defined by each individual user to suit their needs. The order is defined using a form provided by the plugin, the actual sorting is done by MooTools (http://mootools.net) JS framework. Use of this framework is not a necessity; it's up to you what you'll use as a front-end. An example of MooTools front-end is provided at the end of this documentation.
The plugin provides two modes: single sortable list, and double lists, where the second list represents "disabled" items, although that can well be used for having two lists with items being sorted between each of them (e.g. primary and secondary navigations).
This documentation assumes you've read App::ZofCMS, App::ZofCMS::Config and App::ZofCMS::Template
FIRST-LEVEL ZofCMS TEMPLATE AND MAIN CONFIG FILE KEYS
plugins
plugins => [ qw/PreferentialOrder/ ],
Mandatory. You need to include the plugin in the list of plugins to execute.
plug_preferential_order
# except for the mandatory argument `items`, the default values are shown
plug_preferential_order => {
items => [ # four value type variations shown here
forum3 => '<a href="#">Forum3</a>',
forum4 => [ 'Last forum ":)"', \'forum-template.tmpl', ],
forum => [ 'First forum ":)"', '<a href="#">Forum</a>', ],
forum2 => [
'Second forum ":)"',
sub {
my ( $t, $q, $config ) = @_;
return '$value_for_the_second_element_in_the_arrayref';
},
],
],
dsn => "DBI:mysql:database=test;host=localhost",
user => '',
pass => undef,
opt => { RaiseError => 1, AutoCommit => 1 },
users_table => 'users',
order_col => 'plug_pref_order',
login_col => 'login',
order_login => sub { $_[0]->{d}{user}{login} },
separator => ',',
has_disabled => 1,
enabled_label => q|<p class="ppof_label">Enabled items</p>|,
disabled_label => q|<p class="ppof_label">Disabled items</p>|,
submit_button => q|<input type="submit" class="input_submit"|
. q| value="Save">|,
},
# or
plug_preferential_order => sub {
my ( $t, $q, $config ) = @_;
return $hashref_to_assign_to_the_plug_key;
},
Mandatory. Takes either an undef
, a hashref or a subref as a value. If subref is specified, its return value will be assigned to plug_preferential_order
as if it was already there. If undef
is specified or the sub returns one, then plugin will stop further processing. The @_
of the subref will contain $t
, $q
, and $config
(in that order), where $t
is ZofCMS Tempalate hashref, $q
is query parameter hashref and $config
is App::ZofCMS::Config object. Possible keys/values for the hashref are as follows:
items
plug_preferential_order => {
items => [ # four value type variations shown here
forum3 => '<a href="#">Forum3</a>',
forum4 => [ 'Last forum ":)"', \'forum-template.tmpl', ],
forum => [ 'First forum ":)"', '<a href="#">Forum</a>', ],
forum2 => [
'Second forum ":)"',
sub {
my ( $t, $q, $config ) = @_;
return '$value_for_the_second_element_in_the_arrayref';
},
],
],
...
plug_preferential_order => {
items => sub {
my ( $t, $q, $config ) = @_;
return $items_arrayref;
},
...
Mandatory. Takes an arrayref, a subref or undef
as a value. If set to undef
(i.e. not specified), plugin will not execute. If a subref is specified, its return value will be assigned to items
as if it was already there. The @_
of the subref will contain $t
, $q
, and $config
(in that order), where $t
is ZofCMS Tempalate hashref, $q
is query parameter hashref and $config
is App::ZofCMS::Config object. This argument tells the plugin the items on the list you want the user to sort and use.
The insides of the arrayref are best to be thought as keys/values of a hashref; the reason for the arrayref is to preserve the original order. The "keys" of the arrayref must NOT contain separator
(see below) and need to conform to HTML/Your-markup-language id
attribute (http://xrl.us/bicips). These keys are used by the plugin to label the items in the form that the user uses to sort their lists, the labels for the actual list items when they are displayed, as well as labels stored in the SQL table for each user.
The "value" of the "key" in the arrayref can be a scalar, a scalarref, a subref, as well as an arrayref with two items, first being a scalar and the second one being either a scalar, a scalarref, or a subref.
When the value is a scalar, scalarref or subref, it will be internally converted to an arrayref with the value being the second item, and the first item being the "key" of this "value" in the arrayref. In other words, these two codes are equivalent:
items => [ foo => 'bar', ],
items => [ foo => [ 'foo', 'bar', ], ],
The first item in the inner arrayref specifies the human readable name of the HTML snippet. This will be presented to the user in the sorting form. The second item represents the actual snippet and it can be specified using one of the following three ways:
a subref
items => [
foo => [
bar => sub {
my ( $t, $q, $config ) = @_;
return 'scalar or scalarref to represent the actual snippet';
},
],
],
If the second item is a subref, its @_
will contain $t
, $q
, and $config
(in that order) where $t
is ZofCMS Template hashref, $q
is query parameter hashref, and $config
is App::ZofCMS::Config object. The sub must return either a scalar or a scalarref that will be assigned to the "key" instead of this subref.
a scalar
items => [
foo => [
bar => [ bez => '<a href="#"><tmpl_var name="meow"></a>', ],
],
],
If the second item is a scalar, it will be interpreted as a snippet of HTML::Template template. The parameters will be set into this snippet from {t}
ZofCMS Template special key.
a scalarref
items => [
foo => [
bar => [ bez => \'template.tmpl', ],
],
],
If the second item is a scalaref, its meaning and function is the same as for the scalar value, except the HTML::Template template snippet will be read from the filename specified by the scalarref. Relative paths here will be relative to index.pl
file.
dsn
plug_preferential_order => {
dsn => "DBI:mysql:database=test;host=localhost",
...
Optional, but with useless default value. The dsn key will be passed to DBI's connect_cached()
method, see documentation for DBI and DBD::your_database
for the correct syntax for this one. The example above uses MySQL database called test
that is located on localhost
. Defaults to: DBI:mysql:database=test;host=localhost
user
plug_preferential_order => {
user => '',
...
Optional. Specifies the user name (login) for the database. This can be an empty string if, for example, you are connecting using SQLite driver. Defaults to: empty string
pass
plug_preferential_order => {
pass => undef,
...
Optional. Same as user
except specifies the password for the database. Defaults to: undef
(no password)
opt
plug_preferential_order => {
opt => { RaiseError => 1, AutoCommit => 1 },
...
Optional. Will be passed directly to DBI's connect_cached()
method as "options". Defaults to: { RaiseError => 1, AutoCommit => 1 }
users_table
plug_preferential_order => {
users_table => 'users',
...
# This is the minimal SQL table needed by the plugin:
CREATE TABLE `users` (
`login` TEXT,
`plug_pref_order` TEXT
);
Optional. Takes a scalar as a value that represents the table into which to store users' sort orders. The table can be anything you want, but must at least contain two columns (see order_col
and login_col
below). Defaults to: users
order_col
plug_preferential_order => {
order_col => 'plug_pref_order',
...
Optional. Takes a scalar as a value. Specifies the name of the column in the users_table
table into which to store users' sort orders. The orders will be stored as strings, so the column must have appropriate type. Defaults to: plug_pref_order
login_col
plug_preferential_order => {
login_col => 'login',
...
Optional. Takes a scalar as a value. Specifies the name of the column in the users_table
table in which users' logins are stored. The plugin will use the values in this column only to look up appropriate order_col
columns, thus the data type can be anything you want. Defaults to: login
order_login
plug_preferential_order => {
order_login => sub {
my ( $t, $q, $config ) = @_;
return $t->{d}{user}{login};
},
...
plug_preferential_order => {
order_login => 'zoffix',
...
Optional. Takes a scalar, undef
, or a subref as a value. If set to undef
(not specified) the plugin will not run. If subref is specified, its return value will be assigned to order_login
as it was already there. The @_
will contain $t
, $q
, and $config
(in that order) where $t
is ZofCMS Template hashref, $q
is query parameter hashref, and $config
is App::ZofCMS::Config object. The scalar value specifies the "login" of the current user; this will be used to get and store the order_col
value based on the order_login
present in the login_col
column in the users_table
table. Defaults to: sub { $_[0]->{d}{user}{login} }
separator
plug_preferential_order => {
separator => ',',
...
Optional. Specifies the separator that will be used to join together sort order before sticking it into the database. IMPORTANT: your JS code must use the same separator to join together the sort order items when user submits the sorting form. Defaults to: ,
(a comma)
has_disabled
plug_preferential_order => {
has_disabled => 1,
...
Optional. Takes either true or false values as a value. When set to a true value, the plugin will present the user with two lists, with the items movable between the two. When set to a false value, the plugin will show the user only one sortable list.
If the order was stored between the two lists, but then the second list becomes disabled, the previously disabled items will be appended to the end of the first list (both in the display list, and in the sorting form). If the second list becomes enabled before the user saves the single-list order, the divisions between the two lists will be preserved.
Originally, this was designed to have "enabled" and "disabled" groups of items, hence the naming of this and few other options; the "enabled" represents the list that is always shown, and the "disabled" represents the list that is toggleable with has_disabled
argument. Defaults to: 1
(second list is enabled)
enabled_label
plug_preferential_order => {
enabled_label => q|<p class="ppof_label">Enabled items</p>|,
...
Optional. Applies only when has_disabled
is set to a true value. Takes HTML code as a value that will be shown above the "enabled" list of items inside the sorting form. Defaults to: <p class="ppof_label">Enabled items</p>
disabled_label
plug_preferential_order => {
disabled_label => q|<p class="ppof_label">Disabled items</p>|,
...
Optional. Applies only when has_disabled
is set to a true value. Takes HTML code as a value that will be shown above the "disabled" list of items inside the sorting form. Defaults to: <p class="ppof_label">Disabled items</p>
submit_button
plug_preferential_order => {
submit_button => q|<input type="submit" class="input_submit"|
. q| value="Save">|,
...
Optional. Takes HTML code as a value that represents the submit button on the sorting form. This was designed with the idea to allow image button use; however, feel free to insert here any extra HTML code you require in your form. Defaults to: <input type="submit" class="input_submit" value="Save">
HTML::Template TEMPLATE VARIABLES
<tmpl_var name='plug_pref_order_form'>
<tmpl_var name='plug_pref_order_list'>
<tmpl_var name='plug_pref_order_disabled_list'>
The plugin operates through three HTML::Template variables that you can use in any combination. These are as follows:
plug_pref_order_form
<tmpl_var name='plug_pref_order_form'>
This variable contains the sorting form.
plug_pref_order_list
<tmpl_var name='plug_pref_order_list'>
This variable contains the "enabled" list. If has_disabled
is turned off while the user has some items in their "disabled" list; all of them will be appended to the "enabled" list.
plug_pref_order_disabled_list
<tmpl_var name='plug_pref_order_disabled_list'>
This variable contains the "disabled" list. If has_disabled
is turned off while the user has some items in their "disabled" list; all of them will be appended to the "enabled" list, and this ("disabled") list will be empty.
SAMPLE JavaScript CODE TO USED WITH THE PLUGIN
This code relies on MooTools (http://mootools.net) JS framework to operate. (Note: this code also includes non-essential bit to make the enabled and disabled lists of constant size)
window.onload = function() {
setup_sortables();
}
function setup_sortables() {
var els_list = $$('.ppof_list li');
var total_height = 0;
for ( var i = 0, l = els_list.length; i < l; i++ ) {
total_height += els_list[i].getSize().y;
}
$$('.ppof_list').set({'styles': {'min-height': total_height}});
var mySortables = new Sortables('#ppof_order, #ppof_order_disabled', {
'constraint': true,
'clone': true,
'opacity': 0.3
});
mySortables.attach();
$('ppof_order').zof_sortables = mySortables;
$('plug_preferential_order_form').onsubmit = add_sorted_list_input;
}
function add_sorted_list_input() {
var result = $('ppof_order').zof_sortables.serialize(
0,
function(element, index){
return element.getProperty('id').replace('ppof_order_item_','');
}
).join(',');
var result_el = new Element ('input', {
'type': 'hidden',
'name': 'ppof_order',
'value': result
});
result_el.inject(this);
var result_disabled = $('ppof_order').zof_sortables.serialize(
1,
function(element, index){
return element.getProperty('id').replace('ppof_order_item_','');
}
).join(',');
var result_el_disabled = new Element ('input', {
'type': 'hidden',
'name': 'ppof_order_disabled',
'value': result_disabled
});
result_el_disabled.inject(this);
return true;
}
SAMPLE CSS CODE USED BY THE PLUGIN
This is just a quick and ugly sample CSS code to give your lists some structure for you to quickly play with the plugin to decide if you need it:
#ppof_enabled_container,
#ppof_disabled_container {
width: 400px;
float: left;
}
.ppof_label {
text-align: center;
font-size: 90%;
font-weight: bold;
letter-spacing: -1px;
padding: 0;
margin: 0;
}
.success-message {
color: #aa0;
font-weight: bold;
font-size: 90%;
}
.ppof_list {
list-style: none;
border: 1px solid #ccc;
min-height: 20px;
padding: 0;
margin: 0 0 7px;
background: #ffd;
}
.ppof_list li {
padding: 10px;
background: #ddd;
border: 1px solid #aaa;
position: relative;
}
#plug_preferential_order_form .input_submit {
clear: both;
display: block;
}
HTML CODE GENERATED BY THE PLUGIN
Sorting Form
<!-- Double list (has_disabled is set to a true value) -->
<form action="" method="POST" id="plug_preferential_order_form">
<div>
<input type="hidden" name="page" value="/index">
<input type="hidden" name="ppof_save_order" value="1">
<div id="ppof_enabled_container">
<p class="ppof_label">Enabled items</p>
<ul id="ppof_order" class="ppof_list">
<li id="ppof_order_item_forum4">Last forum ":)"</li>
<li id="ppof_order_item_forum">First forum ":)"</li>
</ul>
</div>
<div id="ppof_enabled_container">
<p class="ppof_label">Disabled items</p>
<ul id="ppof_order_disabled" class="ppof_list">
<li id="ppof_order_item_forum2">Second forum ":)"</li>
<li id="ppof_order_item_forum3">forum3</li>
</ul>
</div>
<input type="submit" class="input_submit" value="Save">
</div>
</form>
<!-- Single list (has_disabled is set to a false value) -->
<form action="" method="POST" id="plug_preferential_order_form">
<div>
<input type="hidden" name="page" value="/index">
<input type="hidden" name="ppof_save_order" value="1">
<div id="ppof_enabled_container">
<ul id="ppof_order" class="ppof_list">
<li id="ppof_order_item_forum4">Last forum ":)"</li>
<li id="ppof_order_item_forum">First forum ":)"</li>
<li id="ppof_order_item_forum2">Second forum ":)"</li>
<li id="ppof_order_item_forum3">forum3</li>
</ul>
</div>
<input type="submit" class="input_submit" value="Save">
</div>
</form>
This form shows the default arguments for enabled_label
, disabled_label
and submit_button
. Note that id=""
attributes on the list items are partially made out of the "keys" set in items
argument. The value for page
hidden input
is derived by the plugin automagically.
"Enabled" Sorted List
<ul class="plug_list_html_template">
<li id="ppof_order_list_item_forum4">Foo:</li>
<li id="ppof_order_list_item_forum"><a href="#">Forum</a></li>
</ul>
The end parts of id=""
attributes on the list items are derived from the "keys" in items
arrayref. Note that HTML in the values are not escaped.
"Disabled" Sorted List
<ul class="plug_list_html_template_disabled">
<li id="ppof_order_list_disabled_item_forum2">Bar</li>
<li id="ppof_order_list_disabled_item_forum3">Meow</li>
</ul>
The end parts of id=""
attributes on the list items are derived from the "keys" in items
arrayref. HTML in the values (innards of <li>
s) are not escaped.
REQUIRED MODULES
This plugins lives on these modules:
App::ZofCMS::Plugin::Base => 0.0106,
DBI => 1.607,
HTML::Template => 2.9,
REPOSITORY
Fork this module on GitHub: https://github.com/zoffixznet/App-ZofCMS
BUGS
To report bugs or request features, please use https://github.com/zoffixznet/App-ZofCMS/issues
If you can't access GitHub, you can email your request to bug-App-ZofCMS at rt.cpan.org
AUTHOR
Zoffix Znet <zoffix at cpan.org> (http://zoffix.com/, http://haslayout.net/)
LICENSE
You can use and distribute this module under the same terms as Perl itself. See the LICENSE
file included in this distribution for complete details.