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 ); +};