added: DataTable asset

This commit is contained in:
Doug Bell 2008-10-28 22:27:17 +00:00
parent 828930d193
commit 3e1f66a0e7
9 changed files with 1638 additions and 0 deletions

View file

@ -0,0 +1,296 @@
package WebGUI::Asset::Wobject::DataTable;
$VERSION = "1.0.0";
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2008 Plain Black Corporation.
#-------------------------------------------------------------------
# Please read the legal notices (docs/legal.txt) and the license
# (docs/license.txt) that came with this distribution before using
# this software.
#-------------------------------------------------------------------
# http://www.plainblack.com info@plainblack.com
#-------------------------------------------------------------------
use strict;
use Tie::IxHash;
use WebGUI::International;
use WebGUI::Utility;
use base 'WebGUI::Asset::Wobject';
#-------------------------------------------------------------------
=head2 definition ( session, definition )
=cut
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift;
my $i18n = WebGUI::International->new($session, 'Asset_DataTable');
tie my %properties, 'Tie::IxHash', (
data => {
fieldType => 'DataTable',
defaultValue => undef,
autoGenerate => 0,
},
templateId => {
tab => "display",
fieldType => "template",
namespace => "DataTable",
defaultValue => "3rjnBVJRO6ZSkxlFkYh_ug",
label => $i18n->get( "editForm templateId label" ),
hoverHelp => $i18n->get( "editForm templateId description" ),
},
);
push @{$definition}, {
assetName => $i18n->get('assetName'),
icon => 'Asset.gif',
autoGenerateForms => 1,
tableName => 'DataTable',
className => 'WebGUI::Asset::Wobject::DataTable',
properties => \%properties,
};
return $class->SUPER::definition($session, $definition);
}
#----------------------------------------------------------------------------
=head2 getDataJson ( )
Get the data as a JSON object with the following structure:
{
columns => [
{
key => "Column Key",
formatter => "Column Format",
},
...
],
rows => [
{
"Column Key" => "Column Value",
...
},
...
],
}
=cut
sub getDataJson {
my $self = shift;
return $self->get( "data" );
}
#----------------------------------------------------------------------------
=head2 getDataTable ( )
Get the YUI DataTable markup and script for this DataTable.
=cut
# TODO Have this method get from a WebGUI::DataSource object
sub getDataTable {
my $self = shift;
# This method assumes the form control has been prepared
return $self->{ _datatable }->getValueAsHtml;
}
#----------------------------------------------------------------------------
=head2 getDataTemplateVars ( )
Get the template variables for the raw data. Returns a hash reference with
"rows" and "columns" keys.
=cut
# TODO Have this method get from a WebGUI::DataSource object
sub getDataTemplateVars {
my $self = shift;
# This method assumes the form control has been prepared
my $json = $self->{ _datatable }->getValue;
my $dt = JSON->new->decode( $json );
# Make row data more friendly to templates
my %cols = map { $_->{ key } => $_ } @{ $dt->{ columns } };
for my $row ( @{ $dt->{ rows } } ) {
# Create the column loop for the row
for my $col ( @{ $dt->{ columns } } ) {
push @{ $row->{ row_columns } }, {
%{ $col },
value => $row->{ $col->{ key } },
};
}
}
return $dt;
}
#----------------------------------------------------------------------------
=head2 getEditForm ( )
Add the data table to the edit form.
=cut
# TODO Get the DataSource's edit form
sub getEditForm {
my $self = shift;
my $tabform = $self->SUPER::getEditForm( @_ );
$tabform->getTab( "data" )->raw(
WebGUI::Form::DataTable->new( $self->session, {
name => "data",
value => $self->get( "data" ),
defaultValue => undef,
showEdit => 1,
} )->toHtml
);
return $tabform;
}
#----------------------------------------------------------------------------
=head2 getEditTabs ( )
Add a tab for the data table.
=cut
sub getEditTabs {
my $self = shift;
my $i18n = WebGUI::International->new( $self->session, "Asset_DataTable" );
return (
$self->SUPER::getEditTabs,
[ "data" => $i18n->get( "tab label data" ) ],
);
}
#----------------------------------------------------------------------------
=head2 getTemplateVars ( )
Get the template vars for this asset.
=cut
sub getTemplateVars {
my $self = shift;
my $var = $self->get;
$var->{ url } = $self->getUrl;
$var->{ dataTable } = $self->getDataTable;
$var->{ dataJson } = $self->getDataJson;
%{ $var } = (
%{ $var },
%{ $self->getDataTemplateVars },
);
return $var;
}
#----------------------------------------------------------------------------
=head2 prepareView ( )
Prepare the view. Add stuff to HEAD.
=cut
sub prepareView {
my $self = shift;
$self->SUPER::prepareView( @_ );
my $session = $self->session;
# For now, prepare the form control.
# TODO Use a WebGUI::DataSource
my $dt = WebGUI::Form::DataTable->new( $session, {
name => "data",
value => $self->get( 'data' ),
defaultValue => undef,
} );
$dt->prepare;
$self->{ _datatable } = $dt;
# Prepare the template
my $template = WebGUI::Asset::Template->new( $session, $self->get( "templateId" ) );
$template->prepare;
$self->{ _template } = $template;
return;
}
#----------------------------------------------------------------------------
=head2 view ( )
method called by the www_view method. Returns a processed template
to be displayed within the page style.
=cut
sub view {
my $self = shift;
my $session = $self->session;
my $var = $self->getTemplateVars;
my $dt = $self->{ _datatable };
my $template = $self->{ _template };
return $self->processTemplate( $var, undef, $template );
}
#----------------------------------------------------------------------------
=head2 www_ajaxGetData ( )
Get the data asynchronously.
=cut
sub www_ajaxGetData {
my $self = shift;
$self->session->http->setMimeType( "application/json" );
return $self->getDataJson;
}
#----------------------------------------------------------------------------
=head2 www_ajaxUpdateData ( )
Update the data table asynchronously.
=cut
sub www_ajaxUpdateData {
my $self = shift;
my $data = $self->session->form->get( "data" );
if ( $data && $self->canEdit ) {
$self->update( { data => $data } );
}
$data ||= $self->get( "data" );
$self->session->http->setMimeType( "application/json" );
return $data;
}
1;

View file

@ -0,0 +1,68 @@
package WebGUI::Content::AjaxI18N;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2008 Plain Black Corporation.
-------------------------------------------------------------------
Please read the legal notices (docs/legal.txt) and the license
(docs/license.txt) that came with this distribution before using
this software.
-------------------------------------------------------------------
http://www.plainblack.com info@plainblack.com
-------------------------------------------------------------------
=cut
use strict;
use JSON;
=head1 NAME
Package WebGUI::Content::AjaxI18N
=head1 DESCRIPTION
A content handler to get i18n data using the WebGUI.i18n JavaScript object.
=head1 SYNOPSIS
use WebGUI::Content::AjaxI18N
my $output = WebGUI::Content::AjaxI18N::handler($session);
=head1 SUBROUTINES
These subroutines are available from this package:
=cut
#-------------------------------------------------------------------
=head2 handler ( session )
The content handler for this package.
=cut
sub handler {
my ( $session ) = @_;
# Only handle op=ajaxGetI18N
return undef unless ( $session->form->get( "op" ) eq "ajaxGetI18N" );
my $json = $session->form->get( "request" );
my $namespaces = JSON->new->decode( $json );
my $i18n = WebGUI::International->new( $session );
my $response = {};
for my $ns ( keys %{ $namespaces } ) {
for my $key ( @{ $namespaces->{ $ns } } ) {
$response->{ $ns }->{ $key } = $i18n->get( $key, $ns );
}
}
$session->http->setMimeType( "application/json" );
return JSON->new->encode( $response );
}
1;

View file

@ -0,0 +1,407 @@
package WebGUI::Form::DataTable;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2008 Plain Black Corporation.
-------------------------------------------------------------------
Please read the legal notices (docs/legal.txt) and the license
(docs/license.txt) that came with this distribution before using
this software.
-------------------------------------------------------------------
http://www.plainblack.com info@plainblack.com
-------------------------------------------------------------------
=cut
use strict;
use base 'WebGUI::Form::Control';
use WebGUI::International;
=head1 NAME
Package WebGUI::Form::DataTable
=head1 DESCRIPTION
Create an editable table. Users can add columns and rows to the table.
=head1 SEE ALSO
This is a subclass of WebGUI::Form::Control.
=head1 METHODS
The following methods are specifically available from this class. Check the superclass for additional methods.
=cut
#-------------------------------------------------------------------
=head2 definition ( [ additionalTerms ] )
See the super class for additional details.
=head3 additionalTerms
The following additional parameters have been added via this sub class.
=head4 ajaxDataUrl
This is the URL to get the data from, AJAX-style.
=head4 ajaxDataFunc
This is the ?func= to get the data from.
=head4 ajaxSaveUrl
This is the URL to send AJAX requests to. If this exists, will send
updates to the table asyncronously.
=head4 ajaxSaveFunc
This is the ?func= to send AJAX requests to.
=head4 showEdit
If true, will enable the table for editing. This is only necessary when
displaying the table with getValueAsHtml().
=cut
sub definition {
my $class = shift;
my $session = shift;
my $definition = shift || [];
push @{$definition}, {
showEdit => {
defaultValue => 0,
},
ajaxDataUrl => {
defaultValue => undef,
},
ajaxDataFunc => {
defaultValue => "view",
},
ajaxSaveUrl => {
defaultValue => undef,
},
ajaxSaveFunc => {
defaultValue => "view",
},
};
return $class->SUPER::definition($session, $definition);
}
#-------------------------------------------------------------------
=head2 getDataTableHtml ( )
Render the DataTable
=cut
sub getDataTableHtml {
my $self = shift;
$self->prepare unless $self->{_prepared};
my $data = JSON->new->decode( $self->getOriginalValue );
my $id = $self->get( 'id' );
# Get the HTML for the table
my $html = $self->getTableHtml( $data );
### Prepare the columns data
my %parsers = (
date => "YAHOO.util.DataSource.parseDate",
number => "YAHOO.util.DataSource.parseNumber",
);
my %editors = (
date => "date",
textbox => "textbox",
);
my @columnsJson = ();
for my $column ( @{ $data->{ columns } } ) {
# Not using a datastructure and JSON.pm because of function references for "parser"
my $columnDef = '{'
. qq{"key" : "$column->{ key }", }
. qq{"abbr" : "$column->{ key }", }
. qq{"formatter" : "$column->{ formatter }", }
. qq{"resizable" : 1, }
. qq{"sortable" : 1}
;
# Automatically determine the parser to use
if ( $parsers{ $column->{ formatter } } ) {
$columnDef .= qq{, "parser" : $parsers{ $column->{ formatter } }};
};
# If we can edit
if ( $self->get( 'showEdit' ) ) {
# Set the editor
my $editor = $editors{ $column->{ formatter } }
|| $editors{ "textbox" }
;
$columnDef .= qq{, "editor" : "$editor"};
}
$columnDef .= '}';
push @columnsJson, $columnDef;
}
my $columnsJson = "[" . join( ",", @columnsJson ) . "]";
### Prepare any options
my $options = {
"showEdit" => $self->get( 'showEdit' ),
"inputName" => $self->get( 'name' ),
"ajaxDataUrl" => $self->get( 'ajaxDataUrl' ),
"ajaxDataFunc" => $self->get( 'ajaxDataFunc' ),
"ajaxSaveUrl" => $self->get( 'ajaxSaveUrl' ),
"ajaxSaveFunc" => $self->get( 'ajaxSaveFunc' ),
};
my $optionsJson = JSON->new->encode( $options );
# Progressively enhance the bejesus out of it
$html .= <<"ENDJS";
<script type="text/javascript">
var myDataTable = WebGUI.Form.DataTable( "$id-container", $columnsJson, $optionsJson );
</script>
ENDJS
return $html;
}
#-------------------------------------------------------------------
=head2 getDefaultValue ( )
Get the default value. If none exists, return at least an appropriate
data structure.
=cut
sub getDefaultValue {
my $self = shift;
my $value = $self->SUPER::getDefaultValue( @_ );
if ( !$value ) {
$value = JSON->new->encode(
{
columns => [
{
key => "New Column",
formatter => "text",
},
],
rows => [
{
"New Column" => "Value",
},
],
}
);
}
return $value;
}
#-------------------------------------------------------------------
=head2 getName ( session )
Returns the name of the form control.
=cut
sub getName {
my ($class, $session) = @_;
return WebGUI::International->new($session, "Form_DataTable")->get("topicName");
}
#-------------------------------------------------------------------
=head2 getOriginalValue ( )
Get the original value, or the default value.
=cut
sub getOriginalValue {
my $self = shift;
my $value = $self->SUPER::getOriginalValue( @_ );
if ( !$value ) {
$value = $self->getDefaultValue;
}
return $value;
}
#-------------------------------------------------------------------
=head2 getValue ( [ value ] )
Return the data for the table in a serialized JSON object with the following
structure.
$VAR1 = {
columns => [
{
key => column name,
formatter => "", one of "button", "checkbox", "currency", "date", "dropdown",
"email", "link", "number", "radio", "text", "textarea", "textbox"
// FUTURE ENHANCEMENTS
editor => "", one of "text", "date", "dropdown", "radio", "check"
editorOptions => [ ... ], needed for "dropdown", "radio", "check"
resizable => 1,
sortable => 1,
},
],
rows => [
{
column name => value,
column name => value,
...
},
]
}
=cut
sub getValue {
my $self = shift;
my $value = $self->SUPER::getValue(@_);
# If passing in a data structure, encode to JSON
if ( ref $value eq "HASH" ) {
$value = JSON->new->encode( $value );
}
return $value;
}
#-------------------------------------------------------------------
=head2 getValueAsHtml ( )
Get the value as HTML. Render the datatable in a non-editable form.
=cut
sub getValueAsHtml {
my $self = shift;
return $self->getDataTableHtml;
}
#-------------------------------------------------------------------
=head2 getTableHtml ( [data] )
Get the HTML to render the table. C<data> is the data structure with
columns and rows to render. Defaults to C<getValue>.
=cut
sub getTableHtml {
my $self = shift;
my $data = shift;
my $html = '<div id="' . $self->get('id') . '-container" class="yui-skin-sam">';
# Only insert the table if we're not getting AJAX Data
if ( !$self->get( "ajaxDataUrl" ) ) {
$html .= '<table id="' . $self->get('id') . '-container-table"><thead><tr>';
for my $column ( @{ $data->{ columns } } ) {
$html .= '<th>' . $column->{ key } . '</th>';
}
# TODO: Add table footer
$html .= '</tr></thead><tbody>';
for my $row ( @{ $data->{ rows } } ) {
$html .= '<tr>';
for my $column ( @{ $data->{ columns } } ) {
$html .= '<td>' . $row->{ $column->{ key } } . '</td>';
}
$html .= '</tr>';
}
$html .= '</tbody></table>';
}
$html .= '</div>';
# Add hidden form element to hold JSON
if ( $self->get( 'showEdit' ) ) {
$html .= '<input type="hidden" name="' . $self->get( 'name' ) . '" />';
}
return $html;
}
#-------------------------------------------------------------------
=head2 prepare ( )
Load all the script and css files we need. Call this in prepareView() if needed.
Otherwise, is called automatically.
=cut
sub prepare {
my $self = shift;
# Source in the scripts
my $style = $self->session->style;
my $url = $self->session->url;
$style->setLink( $url->extras( 'yui/build/datatable/assets/skins/sam/datatable.css' ), { rel => "stylesheet", type => "text/css" } );
$style->setScript( $url->extras( 'yui/build/yahoo-dom-event/yahoo-dom-event.js' ) );
$style->setScript( $url->extras( 'yui/build/element/element-beta.js' ) );
$style->setScript( $url->extras( 'yui/build/dragdrop/dragdrop-min.js' ) );
$style->setScript( $url->extras( 'yui/build/connection/connection-min.js' ) );
$style->setScript( $url->extras( 'yui/build/json/json-min.js' ) );
# Prepare the editors
if ( $self->get( 'showEdit' ) ) {
$style->setLink( $url->extras( 'yui/build/button/assets/skins/sam/button.css', { rel => "stylesheet", type => "text/css" } ) );
$style->setLink( $url->extras( 'yui/build/calendar/assets/skins/sam/calendar.css', { rel => "stylesheet", type => "text/css" } ) );
$style->setLink( $url->extras( 'yui/build/container/assets/skins/sam/container.css' ), { rel => "stylesheet", type => "text/css" } );
$style->setScript( $url->extras( 'yui/build/container/container-min.js' ) );
$style->setScript( $url->extras( 'yui/build/button/button-min.js' ) );
$style->setScript( $url->extras( 'yui/build/calendar/calendar-min.js' ) );
}
$style->setScript( $url->extras( 'yui-webgui/build/i18n/i18n.js' ) );
$style->setScript( $url->extras( 'yui/build/datasource/datasource.js' ) );
$style->setScript( $url->extras( 'yui/build/datatable/datatable.js' ) );
$style->setScript( $url->extras( 'yui-webgui/build/form/datatable.js' ) );
$self->{_prepared} = 1;
return;
}
#-------------------------------------------------------------------
=head2 toHtml ( )
Render the DataTable in an editable format.
=cut
sub toHtml {
my $self = shift;
$self->set( 'showEdit', 1 );
return $self->getDataTableHtml;
}
1;

View file

@ -0,0 +1,19 @@
package WebGUI::i18n::English::Asset_DataTable;
use strict;
our $I18N = {
'assetName' => {
message => q{DataTable},
lastUpdated => 0,
},
'tab label data' => {
message => q{Data Table},
lastUpdated => 0,
context => q{Label for the tab with the editable data table},
},
};
1;

View file

@ -0,0 +1,132 @@
package WebGUI::i18n::English::Form_DataTable;
use strict;
our $I18N = {
'topicName' => {
message => q{DataTable},
lastUpdated => 0,
},
'delete rows' => {
message => q{Delete Selected Rows},
lastUpdated => 0,
context => q{Label for button to delete the selected rows},
},
'save' => {
message => q{Save},
lastUpdated => 0,
context => q{Label for button to Save changes},
},
"add row" => {
message => q{Add Row},
lastUpdated => 0,
context => q{Label for button to Add Row to the table},
},
"help" => {
message => q{Help},
lastUpdated => 0,
context => q{Label for button to open the help dialog},
},
"edit schema" => {
message => q{Edit Schema},
lastUpdated => 0,
context => q{Label for button to edit the table column configuration},
},
"delete confirm" => {
message => q{Are you sure you want to delete these rows?},
lastUpdated => 0,
context => q{Message for pop-up to confirm deleting rows from the table},
},
"format text" => {
message => q{Text},
lastUpdated => 0,
context => q{Format for a plain text column},
},
"format email" => {
message => q{E-mail},
lastUpdated => 0,
context => q{Format for a column for an e-mail address},
},
"format link" => {
message => q{URL},
lastUpdated => 0,
context => q{Format for a column for URLs},
},
"format number" => {
message => q{Number},
lastUpdated => 0,
context => q{Format for a column with numbers},
},
"add column" => {
message => q{Add Column},
lastUpdated => 0,
context => q{Label for button to add a column},
},
"cancel" => {
message => q{Cancel},
lastUpdated => 0,
context => q{Label for button to cancel},
},
"ok" => {
message => q{Ok},
lastUpdated => 0,
context => q{Label for button to close an information dialog},
},
"save success" => {
message => q{Table saved successfully!},
lastUpdated => 0,
context => q{Message shown when the table save succeeds},
},
"save failure" => {
message => q{Save failed! Please try again.},
lastUpdated => 0,
context => q{Message shown when the table save fails},
},
"help edit cell" => {
message => q{Double-click a cell to edit the cell. Hitting tab will save the current cell and open the next.},
lastUpdated => 0,
context => q{How to edit a cell. Shown in the help pop-up},
},
"help select row" => {
message => q{Click on a row to select it. Hold shift or ctrl to select multiple rows.},
lastUpdated => 0,
context => q{How to select a row. Shown in the help pop-up},
},
"help add row" => {
message => q{Clicking Add Row will add a row to the bottom of the table.},
lastUpdated => 0,
context => q{How to add a row. Shown in the help pop-up},
},
"help default sort" => {
message => q{By default, the table will be sorted exactly as it is when it is saved.},
lastUpdated => 0,
context => q{How to set the default sort. Shown in the help pop-up},
},
"help reorder column" => {
message => q{Drag and drop columns to reorder them.},
lastUpdated => 0,
context => q{How to reorder columns. Shown in the help pop-up},
},
};
1;