HTML-EditableTable
view release on metacpan or search on metacpan
lib/HTML/EditableTable.pm view on Meta::CPAN
'catalog_id' => 'ZX42AT',
'addition_date' => '2009-03-01',
'part_name' => 'power regulator',
'vendor' => 'Armscor',
'description' => 'Minature power supply with redundant relays',
'qa_results' => '2ppm confirmed',
'qoh' => '32',
'rohs_category' => 2,
'reorder_class' => 'A',
'last_order_date' => '2009-12-17',
},
{
'part_id' => 8055,
'catalog_id' => 'UX24AT',
'addition_date' => '2007-04-08',
'part_name' => 'control module',
'vendor' => 'Subarashii',
'description' => 'Obsolete control module for A45 overthruster. Requires UX27AZ conditioner and 3F buffering caps if the overthruster runs >18psi',
'qa_results' => 'see http://yoururl.com/index.cgi?context=qa',
'qoh' => '2',
'rohs_category' => 4,
'reorder_class' => 'A',
'last_order_date' => '2005-08-19',
},
);
my @tableFields =
(
{
'editOnly' => 1,
'formElement' => 'deleteRowButton',
},
{
'dbfield' => 'part_id',
'label' => 'Part Id',
'viewOnly' => 1,
},
{
'dbfield' => 'catalog_id',
'label' => 'Catalog Id',
'formElement' => 'textfield',
'size' => 15,
'uniquifierField' => 'part_id',
},
{
'dbfield' => 'addition_date',
'label' => 'Available From',
'formElement' => 'calendar',
'uniquifierField' => 'part_id',
},
{
'dbfield' => 'part_name',
'label' => 'Part Name',
'formElement' => 'textfield',
'size' => 20,
'uniquifierField' => 'part_id',
},
{
'dbfield' => 'vendor',
'label' => 'Vendor',
'formElement' => 'popup',
'selectionList' => ['', 'Amexx', 'Armscor', 'Consolidated', 'Gentine', 'Oroco', 'Praxis', 'Shellalco', 'Subarashii',],
'uniquifierField' => 'part_id',
},
{
'dbfield' => 'description',
'label' => 'Part Description',
'formElement' => 'textarea',
'subBr' => 1,
'drillDownTruncate' => 60,
'uniquifierField' => 'part_id',
},
{
'dbfield' => 'qa_results',
'label' => 'QA Results',
'formElement' => 'textfield',
'linkifyContentOnView' => 1,
'uniquifierField' => 'part_id',
},
{
'dbfield' => 'qoh',
'label' => 'Quantity',
'formElement' => 'textfield',
'size' => 5,
'uniquifierField' => 'part_id',
},
{
'dbfield' => 'rohs_category',
'label' => 'RoHS',
'formElement' => 'popup',
'selectionList' => ['',1..10],
'selectionLabels' => {
1 => 'Large and small household appliances',
2 => 'IT equipment',
3 => 'Telecommunications equipment',
4 => 'Consumer equipment',
5 => 'Lighting equipment',
6 => 'Electronic and electrical tools',
7 => 'Toys, leisure, and sports equipment',
8 => 'Medical devices',
9 => 'Monitoring and control instruments',
10 => 'Automatic dispensers',
},
'uniquifierField' => 'part_id',
},
{
'dbfield' => 'reorder_class',
'label' => 'Reorder Class',
'formElement' => 'popup',
'selectionList' => ['', 'A', 'B', 'C'],
'uniquifierField' => 'part_id',
},
{
'dbfield' => 'last_order_date',
'label' => 'Last Ordered',
'formElement' => 'calendar',
'uniquifierField' => 'part_id',
},
);
######## CGI Controller ##########
my $t = CGI->new();
print $t->header();
my $context = $t->param('context') || 'view';
my $table = HTML::EditableTable::Horizontal->new
(
{
'tableFields' => \@tableFields,
'width' => '100%',
'jsAddData' => 1,
'editMode' => $context,
'data' => \@tableData,
'jsSortHeader' => 1,
}
);
print "<form method=post>";
$table->htmlDisplay();
my $nextContext = $context eq 'view' ? 'edit' : 'view';
print "<input type=submit name=context value=$nextContext>";
print "</form>";
=head1 DESCRIPTION
This module was developed to simplify the manipuation of complex tabular data in engineering and business-process web applications. The motivation was a rapid-prototype software development flow where the requirements gathering phase goes something ...
- toggling of the table between view and edit modes with support for common html widgets
- uniquification of form element data to support processing of html form submissions of table data
- support for rowspanning
- methods to generate javascript for dynamic addition and remove of rows and commonly needed features such as 'click-to-expand' text display, calendar widget date entry, and sorting
- support for callbacks when data need to be pre-processed prior to display
For the Horizontal table, data are provided to tables in an array-of-hashes (most common case) or a hash-of-hashes. For the Vertical table, a single hash of data produces a single column of data while a hash-of-hashes supports muliple data columns.
=head1 TABLE METHODS AND PARAMETERS
The class methods are designed along 'public' and 'private' lines. The intended use model is indicated in the method descriptions.
lib/HTML/EditableTable.pm view on Meta::CPAN
if ($val !~ /^1|true|0|false$/) { confess "value ($val) is a flag which must be set to 0, 1, 'true', or 'false'"; }
if ($val eq 'false') { $val = 0; }
elsif ($val eq 'true') { $val = 1; }
return $val;
}
=head2 htmlAddDataSetup (private)
Used outside the table to create a <div> for the insertion of new table rows with javascript
=cut
sub htmlAddDataSetup {
my $self = shift @_;
my $tableFields = $self->{'tableFields'} || confess "missing table fields";
my $tableId = $self->getTableId();
print "<div name=readroot_$tableId id=readroot_$tableId style=\"display:none\">";
foreach my $colSpec (@$tableFields) {
next if (exists $colSpec->{'viewOnly'});
# limited callback support
if (exists $colSpec->{'callback'} && !$colSpec->{'dbfield'}) {
my $fp = $colSpec->{'callback'};
if (!$fp) { confess "no callback exists for $colSpec->{label}!"; }
my $html = &$fp(undef, $colSpec);
print "$html";
}
elsif (!exists $colSpec->{'formElement'}) {
print "<input type=text disabled>";
}
my $formElm = $colSpec->{'formElement'};
my $name = $colSpec->{'dbfield'};
my $id = $colSpec->{'dbfield'};
if (exists $colSpec->{'rowspanArrayKey'}) {
$name = $colSpec->{'rowspanArrayKey'};
$id = $colSpec->{'rowspanArrayKey'};
}
if (defined $formElm) {
if ($formElm eq 'textfield') {
print "<input type=textfield name='$name' id='$id'>";
}
elsif ($formElm eq 'textarea') {
print "<textarea rows=3 cols=60 name='$name' id='$id'></textarea>";
}
elsif ($formElm eq 'popup') {
if (exists $colSpec->{'selectionLabels'}) {
print popup_menu(-id=>$name, -name=>$name, -id=>$id, -values=>$colSpec->{'selectionList'}, -labels=>$colSpec->{'selectionLabels'}, -override=>1);
}
else {
print popup_menu(-id=>$name, -name=>$name, -id=>$id, -values=>$colSpec->{'selectionList'}, -override=>1);
}
}
elsif ($formElm eq 'scrollingList') {
my $selectionCount = scalar(@{$colSpec->{'selectionList'}});
if ($selectionCount > 8) { $selectionCount = 8; }
if (exists $colSpec->{'selectionLabels'}) {
print scrolling_list(-name=>$name, -id=>$id, -values=>$colSpec->{'selectionList'}, -labels=>$colSpec->{'selectionLabels'}, -override=>1, -size=>$selectionCount, -multiple=>'true');
}
else {
print scrolling_list(-name=>$name, -id=>$id, -values=>$colSpec->{'selectionList'}, -size=>$selectionCount, -multiple=>'true', -override=>1);
}
}
elsif ($formElm eq 'deleteRowButton') {
print "<input name='remove' id=remove type='button' value='remove' onClick=\"this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);\">";
}
elsif($colSpec->{'formElement'} eq 'html5Calendar') {
print "<input id='$id' name='$name' type=date/>";
}
elsif($colSpec->{'formElement'} eq 'checkbox') {
my $checked = '';
if ($colSpec->{'checkBehavior'} eq 'checked' ) { $checked = 'checked' }
print "<input type=checkbox name='$name' id='$id' $checked/>";
}
# dynarch jscalendar-1.0 support
elsif($colSpec->{'formElement'} eq 'calendar') {
# script credit to www.dynarch.com
my $spanText = 'Click here to add date';
print "<div id=jscalsetup_$self->{tableId}>";
print "<input type=\"hidden\" name=\"$name\" id=\"$id\"/>\n";
print "<span style=\"background-color: \#fff; cursor: default;\"\n";
print "onmouseover=\"this.style.backgroundColor='#eee';\"\n";
print "onmouseout=\"this.style.backgroundColor='#fff';\"\n";
print "id=\"showD_$name\"\n";
print "><b>$spanText</b></span>";
print "</div>";
}
}
}
print "</div>";
}
##########################################################################
# These methods are intended to be protected
##########################################################################
=head2 makeTable (abstract protected)
Method which must be provided by a class dervied from EditableTable.
=cut
lib/HTML/EditableTable.pm view on Meta::CPAN
# reset the flag
$self->{'vtableFirstColumn'} = undef;
}
# we must have a cell value defined at this point
if ($editMode eq 'edit' && exists $colSpec->{'formElement'}) {
# sometimes we swap form elements if there is no value
if (!$cellValue && exists ($colSpec->{formElementOnNull})) { $colSpec->{formElement} = $colSpec->{formElementOnNull}; }
my $name = $colSpec->{'dbfield'};
if (exists $colSpec->{'rowspanArrayKey'}) {
$name = $colSpec->{'rowspanArrayKey'}
}
if (exists $colSpec->{'uniquifierField'}) {
# maybe an array of unquifiers
if (ref($colSpec->{'uniquifierField'})) {
foreach my $uniquifier (@{$colSpec->{'uniquifierField'}}) {
if (!exists $row->{$uniquifier}) { confess join ":", "field '$uniquifier' called for as a uniquifier but no value exists", __FILE__, __LINE__; }
$name .= '_' . $row->{$uniquifier};
}
}
else {
if (!exists $row->{$colSpec->{'uniquifierField'}}) { confess join ":", "field '$colSpec->{'uniquifierField'}' called for as a uniquifier but no value exists", __FILE__, __LINE__; }
$name .= '_' . $row->{$colSpec->{'uniquifierField'}};
}
# S.K.: Improvement
if (ref($colSpec->{'rowspanArrayUniquifier'})) {
foreach my $rowspan_uniquifier (@{$colSpec->{'rowspanArrayUniquifier'}}) {
if (exists $colSpec->{'rowspanArrayKeyForUniquification'}) {
$name .= '_' . $row->{$colSpec->{'rowspanArrayKeyForUniquification'}}->[$rowspanSubcounter]->{$rowspan_uniquifier};
}
elsif (exists $colSpec->{'dbfield'}) {
$name .= '_' . $row->{$colSpec->{'dbfield'}}->[$rowspanSubcounter]->{$rowspan_uniquifier};
}
else {
confess join ":", "field '$rowspan_uniquifier' called for as a uniquifier but no value exists", __FILE__, __LINE__;
}
}
}
else {
if (exists $colSpec->{'rowspanArrayUniquifier'} && exists $colSpec->{'rowspanArrayKeyForUniquification'}) {
$name .= '_' . $row->{$colSpec->{'rowspanArrayKeyForUniquification'}}->[$rowspanSubcounter]->{$colSpec->{'rowspanArrayUniquifier'}};
}
elsif (exists $colSpec->{'rowspanArrayUniquifier'}) {
$name .= '_' . $row->{$colSpec->{'dbfield'}}->[$rowspanSubcounter]->{$colSpec->{'rowspanArrayUniquifier'}};
}
}
}
if (exists $colSpec->{'masterCounterUniquify'}) {
$name .= '_' . $self->{'masterCounter'}++;
}
if ($colSpec->{'formElement'} eq 'popup') {
# we typically use a negative id for new data - sometimes we need to prevent edits on existing rows
my $disabled = undef;
if (exists $colSpec->{'editOnlyOnNegativeValue'} && $cellValue > 0) {
$disabled = 'DISABLED';
}
if (exists $colSpec->{'selectionListCallback'}) {
my $fp = $colSpec->{'selectionListCallback'};
my $selectionList = &$fp($row);
print "<td $tdFormat>" . popup_menu(-tabindex=>$tabindex, -id=>$name, -name=>$name, -values=>$selectionList, -default=>$cellValue, -override=>1) . "</td>";
}
elsif (exists $colSpec->{'selectionLabels'}) {
print "<td $tdFormat>";
# new version of firefox maybe? - undef disabled flag now results in disabled field??
if ($disabled) {
print popup_menu(-tabindex=>$tabindex, -disabled=>$disabled, -id=>$name, -name=>$name, -values=>$colSpec->{'selectionList'}, -labels=>$colSpec->{'selectionLabels'}, -default=>$cellValue, -override=>1);
}
else {
print popup_menu(-tabindex=>$tabindex, -id=>$name, -name=>$name, -values=>$colSpec->{'selectionList'}, -labels=>$colSpec->{'selectionLabels'}, -default=>$cellValue, -override=>1);
}
# disabled field will not submit
if ($disabled) {
print "<input type=hidden name=\"$name\" value=\"$cellValue\">";
}
print "</td>";
}
else {
print "<td $tdFormat>" . popup_menu(-tabindex=>$tabindex, -id=>$name, -name=>$name, -values=>$colSpec->{'selectionList'}, -default=>$cellValue, -override=>1) . "</td>";
}
}
elsif ($colSpec->{'formElement'} eq 'scrollingList') {
my $selectionCount = scalar(@{$colSpec->{'selectionList'}});
if ($selectionCount > 8) { $selectionCount = 8; }
# split apart a comma delmited list
my @cellValues = split ',', $cellValue;
if (exists $colSpec->{'selectionLabels'}) {
print "<td $tdFormat>", scrolling_list(-tabindex=>$tabindex, -id=>$name, -name=>$name, -values=>$colSpec->{'selectionList'}, -labels=>$colSpec->{'selectionLabels'}, -override=>1, -size=>$selectionCount, -multiple=>'true', -default=>[@cellValues]),...
}
else {
print "<td $tdFormat>", scrolling_list(-tabindex=>$tabindex, -id=>$name, -name=>$name, -values=>$colSpec->{'selectionList'}, -size=>$selectionCount, -multiple=>'true', -override=>1, -default=>[@cellValues]), "</td>";
}
}
elsif ($colSpec->{'formElement'} eq 'textfield') {
my $default = $cellValue || '';
if ($colSpec->{'subBr'}) {
$default =~ s/\n/\<br\>/g;
}
elsif ($colSpec->{'subCommaForBr'}) {
$default =~ s/\<br\>/,/g;
}
my $size;
if (exists $colSpec->{'size'}) {
$size = $colSpec->{'size'};
}
elsif (exists $colSpec->{'minimalEditSize'}) {
$size = length($default) * 1.2;
if ($size < 10) { $size = 15; }
}
else {
$size = length($default) * 2;
if ($size < 60) { $size = 40; }
}
my $maxlength = 255; # danger really need to check db metadata.
if ($colSpec->{'maxlength'}) { $maxlength = $colSpec->{'maxlength'}; }
print "<td $tdFormat>" . textfield(-tabindex=>$tabindex, -id=>$name, -name=>$name, -value=>"$default", -size=>$size, -maxlength=>$maxlength, -override=>1) . "</td>";
}
elsif ($colSpec->{'formElement'} eq 'textarea') {
my $default = $cellValue;
my $size = length($default) * 2;
my $cols = 80;
if ($colSpec->{minimalEditSize}) { $cols = 40; }
my $rows = sprintf("%i", $size/80);
if ($rows < 4) { $rows = 4; }
print "<td $tdFormat>" . textarea(-tabindex=>$tabindex, -id=>$name, -name=>$name, -cols=>$cols, -rows=>$rows, -value=>$default, -override=>1) . "</td>";
}
elsif ($colSpec->{'formElement'} eq 'checkbox') {
my $default = $cellValue;
my $checked = '';
lib/HTML/EditableTable.pm view on Meta::CPAN
print "<input id=\"$name\" name=\"$name\" type=date value=\"$cellValue\"/>";
print "</td>";
}
# dynarch jscalendar-1.0 support
elsif($colSpec->{'formElement'} eq 'calendar') {
# script credit to www.dynarch.com
my $spanText;
if ($cellValue) {
$spanText = $cellValue;
}
else {
$cellValue = '';
$spanText = 'Click here to add date';
}
print "<td $tdFormat>";
print "<input type=\"hidden\" name=\"$name\" id=\"$name\" value=\"$cellValue\"/>\n";
print "<span style=\"background-color: \#fff; cursor: default;\"\n";
print "onmouseover=\"this.style.backgroundColor='#eee';\"\n";
print "onmouseout=\"this.style.backgroundColor='#fff';\"\n";
print "id=\"showD_$name\"\n";
print "><b>$spanText</b></span>\n";
print "<script type=\"text/javascript\">\n";
print "Calendar.setup({\n";
print "inputField : \"$name\",\n";
print "ifFormat : \"%Y-%m-%d\",\n";
print "displayArea : \"showD_$name\",\n";
print "daFormat : \"%Y-%m-%d\",\n";
print "cache : true\n";
print "});\n";
print "</script>\n";
print "</td>";
}
elsif ($colSpec->{'formElement'} eq 'deleteRowButton') {
print "<td $tdFormat>";
print "<input name='remove' id=remove type='button' value='remove' onClick=\"this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);\">";
print "</td>";
}
else {
confess join ":", "Unknown form element ($colSpec->{'formElement'})!", __FILE__, __LINE__;
}
}
elsif (exists $colSpec->{'htmlSub'}) {
my $html = $colSpec->{'htmlSub'};
$html =~ s/<$colSpec->{'dbfield'}>/$cellValue/g;
print "<td $tdFormat>" . $html . "</td>";
}
else {
my $name;
# if we have a list and labels for a popup, assume the provided value is an index to the label;
if (exists $colSpec->{'selectionList'} && exists $colSpec->{'selectionLabels'}) {
print "<td $tdFormat>" . $colSpec->{'selectionLabels'}->{$cellValue} . "</td>";
}
else {
# sometimes we want to substitue <br> for newlines
my $content = $cellValue;
if ($colSpec->{'subBr'}) {
$content =~ s/\n/\<br\>/g;
}
# if the content is short is short enough an contains thinks that looks like links, convert them to links
if ($colSpec->{'linkifyContentOnView'}) {
(my @links) = $content =~ /(http\:\/\/\S+)/g;
foreach my $link (@links) {
# escape $link
$link =~ s/\//\\\//g;
$link =~ s/\?/\\\?/g;
$content =~ s/($link)/\<a href=\"$1\"\>$1\<\/a\>/;
}
}
# sometimes we want to substitue <br> for newlines
if ($colSpec->{'subBr'}) {
$content =~ s/\n/\<br\>/g;
}
# some large text displays are truncated or provided with expandable links
if ($colSpec->{'drillDownTruncate'} && length($content) > $colSpec->{'drillDownTruncate'}) {
(my $truncatedContent) = $content =~ /(.{0,$colSpec->{'drillDownTruncate'}})/;
$truncatedContent .= "...<input type=button style=\"font-size:65%;\" value=more>";
my $tdUid = $self->{'elementUid'}++;
my $divUid = $self->{'elementUid'}++;
my $truncatedDivUid = $self->{'elementUid'}++;
my $aUid = $self->{'elementUid'}++;
print "<td $tdFormat id=$tdUid>" . "<div style=text-decoration:none id=$aUid href=\"javascript:void(0)\" onclick=\"expandText($aUid, $divUid, $truncatedDivUid);\">" . $truncatedContent . "</div>" . "<div id=$divUid style=display:none>$content</div...
}
else {
if (!defined($content)) { $content = ''; }
print "<td $tdFormat>" . $content . "</td>";
}
}
}
}
}
=head1 TABLE FIELD PARAMETERS
=head2 dbfield (frequent)
Specifies the data hash key for provided data for the table element. Also Specifies the form element base name that will be used. Typically, this is also a database field name.
'dbfield' => part_id
=head2 label (frequent)
Specifies the table column header for horizontal tables and the first colum for vertical tables.
'label' => 'Part Id#'
=head2 formElement (frequent)
formElement specifies the html input field that will be used when the table is in 'edit' mode. Valid values are
=over
=item *
calendar - Implements popup calendar using www.dynarch.com jscalendar 1.0. Requires this javascript library to be accessible. See L</"JAVASCRIPT INTEGRATION"> for details.
=item *
checkbox - Implements checkbox html element
=item *
deleteRowButton - Combine with jsAddRow Table-level feature. Provides button to delete a table row.
=item *
html5Calendar - Alternative to calendar. Implements HTML5 'date' input type. Tested with Opera, which is the only browser supporting this HTML5 input as of this writing.
=item *
hidden - Implements hidden element type.
=item *
popup - implements CGI "poup"
=item *
scrollingList - implments CGI "scrolling_list"
=item *
textarea - implements textarea HTML element
=item *
textfield - implements html input of type 'text'
=back
'formElement' => 'checkbox'
=head2 selectionList (frequent)
An array reference to a list of values to display in a popup or scrollingList
'selectionList' => [ '34GXT', '35TTG', '56YUG' ]
=head2 selectionLabels (frequent)
A hash reference to labels and values to present in a popup or scrollingList. The keys are displayed while the values are provided in the form.
'selectionLabels' => { '34GXT' => 'Big Widget', '35TTG' => 'Medium Widget', '56YUG' => 'Small Widget' }
=head2 editOnly (frequent)
Don't display this field when the table is in 'view' mode.
'editOnly' => 1
=head2 viewOnly (frequent)
Don't display this field when the table is in 'edit' mode.
'viewOnly' => 1
=head2 default (frequent)
Provides default value for form elements when no value is present in the data
'default' => 'UX56SG'
=head2 uniquifierField (frequent)
Sets the field whose 'dbfield' value is used to provide a unique name and id to other form elements in the same array (row or column, depending on the implementation) of data. This is done by appending an '_' and then the value of the specified dbfi...
my @tableFields = (
{
'dbfield' => 'part_id'
}
{
'dbfield' => 'description',
'uniquifierField' => 'part_id'
'formElement' => 'textfield',
}
);
with data
my @data = (
'part_id' => 1234
)
will produce
<input type=text id='description_1234' name='description_1234'>
This field can also be an arrayref to a list of fields. The values of each will be joined with '_' characters to create the field name and id.
=head2 drillDownTruncate (occasional)
Implements a javascript which truncates the text and provides a toggle to switch between full and truncated text. The value sets the number of characters which are displayed in 'truncated' mode.
'drillDownTruncate' => 100
=head2 callback (occasional)
Provides a mechanism to process data with a custom function or method prior to display. Typically used for custom formatting, setting table values based on other values, or 'child' database queries.
'callback' => &callbackFunction
lib/HTML/EditableTable.pm view on Meta::CPAN
'dbfield' => 'part_id',
'label' => 'Part ID#'
},
{
'dbfield' => 'sub_data',
'rowspanArrayKey' => 'sub_assembly_name',
'label' => 'Part Sub-Assembly',
'masterCounterUniquify' => 1
}
);
produces a table with the following unique id's in 'edit' mode. Note the flattening of the table in 'edit' mode. If this is not desired set the table-level param 'rowspannedEdit'.
------------------------------------------------------
| Part ID# | Part Sub-Assembly |
|----------|-----------------------------------------|
| UX34GT | 34R (sub_assembly_name_1) |
|----------|-----------------------------------------|
| UX34GT | 23D (sub_assembly_name_2) |
|----------|-----------------------------------------|
| RT67IV | 14G (sub_assembly_name_3) |
|----------|-----------------------------------------|
| RT67IV | 13R (sub_assembly_name_4) |
------------------------------------------------------
=head2 styleHandler (rare)
Callback mechanism to provide a style for the <td> tag.
'styleHandler' => &getStyle
The interface for the callback is
&getStyle(
$row # hashref to the current data set
)
=head2 modeModifier (rare)
Provides a callback mechanism to determine if the mode ('view' or 'edit') should be changed for this field only
'modeModifer' => &getMode
The interface for this callback is as follows:
&getMode (
$editMode, # 'view' or 'edit'
$data # hashref to the current dataset (row or column, depending on table type)
)
The callback must return 'view' or 'edit'.
=head2 editOnlyOnNegativeValue (rare)
Use this feature when it is desired to prevent editing on existing data and only allow edting of new data where the value is <0
'editOnlyOnNegativeValue' => 1,
=head2 selectionListCallback (rare)
Specifies a callback to produce a value list for a popup or scrollingList element. Useful when a dynamic query or calculation must be made.
'selectionListCallback' => &getListValues
The interface for this call back is as follows:
&getListValues (
$dataSet # current row or column data hashref
);
The callback must provide an arrayref of values.
=head2 htmlSub (rare)
provides a simple mechanism to substitute the current field's value into a string template
'htmlSub' => "http://www.site.com?value=<dbfield>"
The '<dbfield>' text will be replaced by the current dataset's $data->{dbfield}
=head1 JAVASCRIPT INTEGRATION
=head2 Overview
The javascript features are encapsulated in HTML::EditableTable::Javascript. Each method provided by this class provides a distinct javascript feature, allowing for clean override or extension. The intent is to provide all javascript functionality "...
To use a custom javascript class, call setJavascript() prior to htmlDisplay() or htmlJavascriptDisplay(). Note that the Javascript object requires a reference to the parent table so it must be created after the table.
Inherit from the HTML::EditableTable::Javascript class to extend or override javascript code generation.
package MyNewJavascript {
@ISA = qw(HTML::EditableTable::Javascript);
# new code
}
1;
my $table = HTML::EditableTable::Vertical->new();
my $customJavascript = MyNewJavascript->new($table);
$table->setJavascript($customJavascript);
The functionality provided through javascript are described below:
=head2 Table Sorting
Client-side table sorting is implemented using Stuart Langridge's SortTable Version 2: http://www.kryogenix.org/code/browser/sorttable/ See L</"SORTING"> for more details on this and other table sorting options. To use this feature set the 'jsSortH...
$table->setJsSortHeader(1);
=head2 Click-to-Expand Text
This feature truncates text to the specified number of characters by default and provides a "more" button to display the full text. A click on the full text returns the cell to its truncated state. This feature is useful when the full text consumes...
my $tableField =
{
'dbfield' => 'description',
'label' => 'Part Description',
'drillDownTruncate' => 60,
};
=head2 Mousover Tooltips
( run in 1.589 second using v1.01-cache-2.11-cpan-364913b4093 )