diff --git a/lib/WebGUI/Asset.pm b/lib/WebGUI/Asset.pm
index ffa977eda..da1bd09bd 100644
--- a/lib/WebGUI/Asset.pm
+++ b/lib/WebGUI/Asset.pm
@@ -2605,7 +2605,15 @@ sub update {
# set the property
if ($propertyDefinition->{serialize}) {
- $setPairs{$property} = JSON->new->canonical->encode($value);
+ # Only serialize references
+ if ( ref $value ) {
+ $setPairs{$property} = JSON->new->canonical->encode($value);
+ }
+ # Passing already serialized JSON string
+ elsif ( $value ) {
+ $setPairs{$property} = $value;
+ $value = JSON->new->decode( $value ); # for setting in _properties, below
+ }
}
else {
$setPairs{$property} = $value;
diff --git a/lib/WebGUI/Asset/Wobject/Calendar.pm b/lib/WebGUI/Asset/Wobject/Calendar.pm
index 165576667..b2be4eeb7 100644
--- a/lib/WebGUI/Asset/Wobject/Calendar.pm
+++ b/lib/WebGUI/Asset/Wobject/Calendar.pm
@@ -257,12 +257,32 @@ sub definition {
},
icalFeeds => {
- fieldType => "textarea",
+ fieldType => "JsonTable",
defaultValue => [],
serialize => 1,
- noFormPost => 1,
- autoGenerate => 0,
- tab => "display",
+ tab => "feeds",
+ fields => [
+ {
+ name => 'feedId',
+ type => 'id',
+ },
+ {
+ name => 'url',
+ type => 'text',
+ size => '40',
+ label => $i18n->get('Feed URL'),
+ },
+ {
+ name => 'status',
+ type => 'readonly',
+ label => $i18n->get('434','WebGUI'),
+ },
+ {
+ name => 'lastUpdated',
+ type => 'readonly',
+ label => $i18n->get('454', 'WebGUI'),
+ },
+ ],
},
icalInterval => {
@@ -507,168 +527,16 @@ sub deleteFeed {
#----------------------------------------------------------------------------
-=head2 getEditForm
+=head2 getEditTabs ( )
-Adds an additional tab for feeds.
-
-TODO: Abstract the Javascript enough to export into extras/yui-webgui for use
-in other areas.
+Add the feeds tab to the edit form
=cut
-sub getEditForm {
- my $self = shift;
- my $session = $self->session;
- my $form = $self->SUPER::getEditForm;
- my $i18n = WebGUI::International->new($session,"Asset_Calendar");
-
- my $tab = $form->addTab("feeds",$i18n->get("feeds"), 6);
- $tab->raw("
");
-
- $tab->raw(<<'ENDJS');
-
-ENDJS
-
-
- my $addFeed = $i18n->get('Add a feed');
- my $add = $i18n->get('Add');
- my $feedUrl = $i18n->get('Feed URL');
- my $status = $i18n->get('434', 'WebGUI');
- my $lastUpdated = $i18n->get('454', 'WebGUI');
- $tab->raw(<<"ENDHTML");
-
-
-
-
-
-
- | |
- $feedUrl |
- $status |
- $lastUpdated |
- |
-
-
-ENDHTML
-
-
-
- # Add the existing feeds
- my $feeds = $self->getFeeds();
- $tab->raw('');
-
-
- $tab->raw(" |
");
- return $form;
+sub getEditTabs {
+ my ( $self ) = @_;
+ my $i18n = WebGUI::International->new($self->session,"Asset_Calendar");
+ return $self->SUPER::getEditTabs, ["feeds",$i18n->get("feeds"), 6];
}
#----------------------------------------------------------------------------
@@ -1000,37 +868,6 @@ sub processPropertiesFromFormPost {
$self->createSubscriptionGroup();
}
- $self->session->errorHandler->info( "DEFAULT VIEW:" . $self->get('defaultView') );
-
- ### Get feeds from the form
- # Workaround WebGUI::Session::Form->param bug that returns duplicate
- # names.
- my %feeds;
- for my $feedId ( grep /^feeds-/, ($form->param()) ) {
- $feedId =~ s/^feeds-//;
- $feeds{$feedId}++;
- }
- my @feedsFromForm = keys %feeds;
-
- # Delete old feeds that are not in @feeds
- my @oldFeeds = map { $_->{feedId} } @{ $self->getFeeds };
-
- for my $feedId (@oldFeeds) {
- if (!isIn($feedId, @feedsFromForm)) {
- $self->deleteFeed($feedId);
- }
- }
-
- # Create new feeds
- for my $feedId (grep /^new(\d+)/, @feedsFromForm) {
- $self->addFeed({
- url => $form->param("feeds-".$feedId),
- feedType => "ical",
- lastUpdated => 'never',
- lastResult => '',
- });
- }
-
return;
}
diff --git a/lib/WebGUI/Form/JsonTable.pm b/lib/WebGUI/Form/JsonTable.pm
index 33ac0cf6a..d3cc2812b 100644
--- a/lib/WebGUI/Form/JsonTable.pm
+++ b/lib/WebGUI/Form/JsonTable.pm
@@ -86,6 +86,23 @@ sub getName {
#-------------------------------------------------------------------
+=head2 getOriginalValue ( )
+
+Get the original value, encoding to JSON if necessary
+
+=cut
+
+sub getOriginalValue {
+ my ( $self ) = @_;
+ my $value = $self->SUPER::getOriginalValue;
+ if ( ref $value eq "ARRAY" ) {
+ return JSON->new->encode( $value );
+ }
+ return $value;
+}
+
+#-------------------------------------------------------------------
+
=head2 getValue ( value )
Get the value of the field. Substitute id fields with GUIDs.
@@ -96,6 +113,7 @@ sub getValue {
my ( $self, $value ) = @_;
$value ||= $self->SUPER::getValue;
+ $self->session->log->info( "JsonTable Got $value from form" );
$value = JSON->new->decode( $value );
for my $row ( @{$value} ) {
@@ -162,13 +180,14 @@ sub toHtml {
$fieldHtml .= '';
}
else { # Readonly or unknown
- $fieldHtml = '';
+ $fieldHtml = ' ';
}
$output .= '' . $fieldHtml . ' | ';
}
- $output .= '';
+ $output .= ' | ' # Extra cell for buttons
+ . '';
# Build the existing rows
$output .= '';
@@ -185,7 +204,8 @@ sub toHtml {
$output .= sprintf '',
$url->extras('yui-webgui/build/form/jsontable.js');
$output .= '';
return $output;
diff --git a/www/extras/yui-webgui/build/form/jsontable.js b/www/extras/yui-webgui/build/form/jsontable.js
new file mode 100644
index 000000000..101764e35
--- /dev/null
+++ b/www/extras/yui-webgui/build/form/jsontable.js
@@ -0,0 +1,219 @@
+
+// Initialize namespace
+if (typeof WebGUI == "undefined") {
+ var WebGUI = {};
+}
+if (typeof WebGUI.Form == "undefined") {
+ WebGUI.Form = {};
+}
+
+/****************************************************************************
+ * WebGUI.Form.JsonTable( fieldName, tableId, columns )
+ * Create a JsonTable object.
+ *
+ * fieldName holds the current JSON-encoded array of hashrefs of values.
+ *
+ * tableId is where to put the rows and add all the events.
+ *
+ * columns is an array of hashes of column data with the following keys:
+ * type -- The type of column, one of "text", "select",
+ * "id", "hidden", "readonly"
+ * name -- The name of the column
+ * label -- The label of the column
+ * options -- select only. An array of name, label of options.
+ *
+ */
+WebGUI.Form.JsonTable
+= function ( fieldName, tableId, columns ) {
+ this.fieldName = fieldName;
+ this.tableId = tableId;
+ this.columns = columns;
+ this.table = document.getElementById( this.tableId );
+ this.tbody = this.table.getElementsByTagName( "tbody" )[0];
+
+ // Find the form
+ this.form = this.table;
+ while ( this.form.nodeName != "FORM" ) {
+ this.form = this.form.parentNode;
+ }
+
+ this.field = this.form.elements[ this.fieldName ];
+ this.json = this.field.value;
+ this.newRow = YAHOO.util.Dom.getElementsByClassName( "new_row", "tr", this.table )[0];
+
+ try {
+ this.data = YAHOO.lang.JSON.parse( this.json );
+ }
+ catch (err) {
+ this.data = [];
+ }
+
+ // Add submit listener to update JSON
+ YAHOO.util.Event.addListener( this.form, "submit", this.update, this, true );
+
+ this.addButton = this.table.getElementsByTagName( "button" )[0];
+ YAHOO.util.Event.addListener( this.addButton, "click",
+ function(e) {
+ this.addRow();
+ e.preventDefault();
+ return false;
+ },
+ this, true
+ );
+
+ this.init();
+
+ return this;
+};
+
+/****************************************************************************
+ * addActions( row )
+ * Add the row actions to the given row
+ */
+WebGUI.Form.JsonTable.prototype.addActions
+= function (row) {
+ // Add row actions
+ var buttonCell = row.lastChild;
+ var deleteButton = document.createElement('input');
+ deleteButton.type = "button";
+ deleteButton.value = "Delete";
+ YAHOO.util.Event.addListener( deleteButton, "click",
+ function (e) {
+ this.deleteRow( row );
+ },
+ this, true
+ );
+ buttonCell.appendChild( deleteButton );
+
+ var moveUpButton = document.createElement('input');
+ moveUpButton.type = "button";
+ moveUpButton.value = "Up";
+ YAHOO.util.Event.addListener( moveUpButton, "click",
+ function (e) {
+ this.moveRowUp( row );
+ },
+ this, true
+ );
+ buttonCell.appendChild( moveUpButton );
+
+ var moveDownButton = document.createElement('input');
+ moveDownButton.type = "button";
+ moveDownButton.value = "Down";
+ YAHOO.util.Event.addListener( moveDownButton, "click",
+ function (e) {
+ this.moveRowDown( row );
+ },
+ this, true
+ );
+ buttonCell.appendChild( moveDownButton );
+};
+
+/****************************************************************************
+ * addRow ( )
+ * Add a new row to the bottom of the table
+ */
+WebGUI.Form.JsonTable.prototype.addRow
+= function () {
+ var newRow = this.newRow.cloneNode(true);
+ this.tbody.appendChild( newRow );
+ newRow.className = "";
+ newRow.style.display = "table-row";
+ this.addActions( newRow );
+ return newRow;
+};
+
+/****************************************************************************
+ * deleteRow( row )
+ * Delete the row from the table
+ */
+WebGUI.Form.JsonTable.prototype.deleteRow
+= function ( row ) {
+ row.parentNode.removeChild( row );
+};
+
+/****************************************************************************
+ * init ( )
+ * Initialize the JsonTable by adding rows for every datum
+ */
+WebGUI.Form.JsonTable.prototype.init
+= function () {
+ for ( var row in this.data ) {
+ // Copy new_row
+ var newRow = this.addRow();
+
+ // Fill in values based on field type
+ var cells = newRow.getElementsByTagName( "td" );
+ for ( var i = 0; i < this.columns.length - 1; i++ ) { // Last cell is for buttons
+ var cell = cells[i];
+ var column = this.columns[i];
+ var field = cell.childNodes[0];
+ var value = this.data[row][column.name] || '';
+ if ( column.type == "text" || column.type == "id"
+ || column.type == "hidden" ) {
+ field.value = value;
+ }
+ else if ( column.type == "select" ) {
+ for ( var x = 0; x < field.options.length; x++ ) {
+ if ( field.options[x].value == value ) {
+ field.options[x].selected = true;
+ }
+ }
+ }
+ else { // "readonly" or unknown
+ cell.appendChild( document.createTextNode( value ) );
+ }
+ }
+ }
+};
+
+/****************************************************************************
+ * moveRowDown( row )
+ * Move the row down in the table
+ */
+WebGUI.Form.JsonTable.prototype.moveRowDown
+= function ( row ) {
+ var after = row.nextSibling;
+ if ( after ) {
+ row.parentNode.insertBefore( after, row );
+ }
+};
+
+/****************************************************************************
+ * moveRowUp( row )
+ * Move the row up in the table
+ */
+WebGUI.Form.JsonTable.prototype.moveRowUp
+= function ( row ) {
+ var before = row.previousSibling;
+ if ( before && before.className != "new_row" ) {
+ row.parentNode.insertBefore( row, before );
+ }
+};
+
+/****************************************************************************
+ * update ( )
+ * Update the value in our field with the correct JSON
+ */
+WebGUI.Form.JsonTable.prototype.update
+= function (e) {
+ var rows = this.tbody.getElementsByTagName( 'tr' );
+ var data = [];
+ for ( var i = 1; i < rows.length; i++ ) {
+ var cells = rows[i].getElementsByTagName( 'td' );
+ var rowData = {};
+ for ( var x = 0; x < this.columns.length; x++ ) {
+ var cell = cells[x];
+ var column = this.columns[x];
+ var field = cell.childNodes[0];
+ if ( field.nodeName == "INPUT" ) {
+ rowData[ column.name ] = field.value;
+ }
+ else if ( field.nodeName == "SELECT" ) {
+ var value = field.options[ field.selectedIndex ].value;
+ rowData[ column.name ] = field.value;
+ }
+ }
+ data.push( rowData );
+ }
+ this.field.value = YAHOO.lang.JSON.stringify( data );
+};