From 9de7e341122c24be2235b7d92d1d7c0109844978 Mon Sep 17 00:00:00 2001 From: Yung Han Khoe Date: Thu, 13 Mar 2008 19:06:18 +0000 Subject: [PATCH] add: Thingy asset --- docs/changelog/7.x.x.txt | 1 + .../root_import_thingy-templates.wgpkg | Bin 0 -> 2734 bytes docs/upgrades/upgrade_7.5.5-7.5.6.pl | 80 + etc/WebGUI.conf.original | 5 +- lib/WebGUI/Asset/Wobject/Thingy.pm | 2544 +++++++++++++++++ lib/WebGUI/Help/Asset_Thingy.pm | 232 ++ lib/WebGUI/i18n/English/Asset_Thingy.pm | 877 ++++++ t/Asset/Wobject/Thingy.t | 115 + www/extras/wobject/Thingy/thingy.css | 36 + www/extras/wobject/Thingy/thingy.js | 523 ++++ 10 files changed, 4411 insertions(+), 2 deletions(-) create mode 100644 docs/upgrades/packages-7.5.6/root_import_thingy-templates.wgpkg create mode 100644 lib/WebGUI/Asset/Wobject/Thingy.pm create mode 100644 lib/WebGUI/Help/Asset_Thingy.pm create mode 100644 lib/WebGUI/i18n/English/Asset_Thingy.pm create mode 100644 t/Asset/Wobject/Thingy.t create mode 100644 www/extras/wobject/Thingy/thingy.css create mode 100644 www/extras/wobject/Thingy/thingy.js diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index b30a99b1b..e051655cb 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -10,6 +10,7 @@ - ensure proper XML encoding for ITransact messages - fixed: fatal error duplicate keywords added to a wiki page - rfe: added the ability to choose whether assets should be added to the front or end of the first content position of the page (Dept of State) + - Added Thingy asset 7.5.5 - fixed: Several typos in the new Calendar help documentation. diff --git a/docs/upgrades/packages-7.5.6/root_import_thingy-templates.wgpkg b/docs/upgrades/packages-7.5.6/root_import_thingy-templates.wgpkg new file mode 100644 index 0000000000000000000000000000000000000000..38add7e1c122bb7d3ef8b3e9c7a5d4b025637cbc GIT binary patch literal 2734 zcmV;f3Q_eRiwFP!000001MORFbKAHP*5~^b8g-`A>s%yJueQ(ij9=ndnIv{?CBD15 z)lecNA*M)%0PQH9`|n*~Ndn-D{3d%YJ?TS26ANImy8xbN0oE(e|7$jz{cg8XX*R8X z*Q!+7ef(9^U$bI0`@LSP*Xy@hm8#XWdfiGDsyzQMV%!cvwOcZtMfCCg!64x$28sVa zzNHtfDYdoIf34`6>wgfP|b9Cf-UhA?Z*Sxb|{LxhutMR!z!_vPnp6PMm|K zs8MUH0@r5z_1C};p>$ui=S8lY)`J_xUow@oU4op^So8 z4(-XD4C#XS5y#Q=nwr!s^rK+lymly-S}oNn<4czeV`buDogHvcPEPmqpPts9L)avw z0jIvyHSeawx$VsgeM~(PhfpnDPGH4{XINB}Ruc#Y_Q77@fG^4T&Bwvc&b~1H&d#Mj z{!AwDaO}Gd2~{ng#@kRDxtfeiGjeQ;Pn2M+^i_3sO@j|Ur&Btyld;vbVK0amsgN%3 zLPTmL1E*#OFhg$iNR{DpLBHY1+LqzxcmCu$FyeoIp?BqADo?T%K4#r=I=lJzK&)2#oEYEReZBf6aX!* z+W*_VW_JH?ciMpeHv9kchrvVle{+x5R+;Z`kH>X>Xl{twkdi$LHg=}@koyJE*4(P@HNb`K!Ok=S-|Su0_Wm>QI0-$usoU<~u&~MnMqpJJb{Y4l ztC|ECBlPxF?Z=;Y8}{DrI7~Du=)`s$DPGbI6k{JNyT}{O7%nO~a(zE`l+s9=P!z-? z(S%a#%IYHm1{;9Sb+?JZk8S`3$%3jf9aeFOOE@VmlNQr$gFaU}8Zn^aUn2NNLPOkd zR9hA9tnSb+-xQ-A@B5XHj~V_DY^z>8a38kPg70{lfz{|rJ- z46w6vGJO9o`AZFU4&>&*1+Xb98$gq?`(w}qUv@MMT?j&(P1wCP@MwZiZ6#!L|90RV z`{4rNv$o87Kn7S~PY^d}y>~A-dU<>rwBH`Ow;#?&UjNl4J(<3F{ZD0;GB~<6u-Wc! zTidOU>d^q3C1moCfEP>fU+V?&U$@unW%57mPN%)Wf6tHpDwPfX8=Ck}o-w(kX-9WhF|8p3&-*64%k$h=9%-?US4( zBLqpYcrcOY0)?$&d9qH*+CoPBc6kU)#;HmU0JLukc=1T3q_1k#8{4Hb4~n=S0RI!( zVb!D)!8~IP1pPB58r(73m(U-ws&;Y9S3LDHHYr)B-etio)g)^gEyLHKenfy%+fuKj zed02-V%bozniwopF~TsdA&1rg`z0oc<JvWW_a4Zx+aEK z{RAmq&);Z(^1RonNXfTssR>-6*6i{)&3 zb2~enUZ0)3Bie!8h5{DSi4y+TenI}%>-73L{?~M^J{7=im-O2w1 z>fZ3b6eH;ge}N#dU~?2;oHpcemS(;U0~5jWf5O1T;;@>5WhL&zz(^SSp<-YH{_jSv zMwmQ)K{yxZUxoBYGPHt5QXb(_IRDXj3(7)qJYHj>H3kK(-a55PoAj%?HU z9-nt=ww9x-u z9K$WDEPPrNSYUwsu+!k6?3{dwXh@vBzn9nvPM17wiiC@cXw2a*Aj}ZVi>aLo1CC)i z*j-dLdw&ek#WZ1rOc4KmnZB+T0DTTw_5G4GV}LD*!$*{ME$y;c2M!aliG$bXU3=ZBkYTBz0*PX z%l^l=ov-7g^Nv0K_4DS;cCGC0?#4>^f9D1HKYSaK{r&^ae>eC4?snc9BsTniXrBLS zcR23k|9Gmj$pEB~c9Q|P$9=;bXiLq9-;u05P1Hql2Z~r&dZw7U_h{&m>OkaoIxBV1 zMRGb|VW|#}IM+;7OHWcoZmHnpEiKO}^$aJi22I6BlegQ%@PF!?K@6*rb!p2E`p)O4@nv!?p+@fW*;=x7FUT4bPwhx&66to!H>;^ zgqy+L=_!0q=E^7;i^Y0sL2_rWVA+D%TwKi$;k&Sdaf845iZ!HBt#7bF#r-B@-?62d-hdqqOi8lhc?!@_sSK^_`Q*RK@UV zV9zLiPEdzOa_C1MuT%COW*80PyDleu^tae7xmlP)tB!kU1W8)`j&S4e{J_W(4ZN=-Ya1={qn7IvQNA3!cV`2 ovzwlM`^*0AOoj30hQ}K60h=Z^7T8$e&trlA0UtD9Q2db->write(<<'ENDSQL'); +create table if not exists Thingy ( + assetId varchar(22) binary not null, + revisionDate bigint not null, + templateId varchar(22) not null, + defaultThingId varchar(22), + primary key (assetId, revisionDate) + ) +ENDSQL + + $session->db->write(<<'ENDSQL'); +create table if not exists Thingy_things ( + assetId varchar(22) binary not null, + thingId varchar(22) binary not null, + label varchar(255) not null, + editScreenTitle varchar(255) not null, + editInstructions text, + groupIdAdd varchar(22) not null, + groupIdEdit varchar(22) not null, + saveButtonLabel varchar(255) not null, + afterSave varchar(255) not null, + editTemplateId varchar(22) not null, + onAddWorkflowId varchar(22), + onEditWorkflowId varchar(22), + onDeleteWorkflowId varchar(22), + groupIdView varchar(22) not null, + viewTemplateId varchar(22) not null, + defaultView varchar(255) not null, + searchScreenTitle varchar(255) not null, + searchDescription text, + groupIdSearch varchar(22) not null, + groupIdImport varchar(22) not null, + groupIdExport varchar(22) not null, + searchTemplateId varchar(22) not null, + thingsPerPage int(11) not null default 25, + sortBy varchar(22), + display int(11), + primary key (thingId) + ) +ENDSQL + + $session->db->write(<<'ENDSQL'); +create table if not exists Thingy_fields ( + assetId varchar(22) binary not null, + thingId varchar(22) binary not null, + fieldId varchar(22) not null, + sequenceNumber int(11) not null, + dateCreated bigint(20) not null, + createdBy varchar(22) not null, + dateUpdated bigint(20) not null, + updatedBy varchar(22) not null, + label varchar(255) not null, + fieldType varchar(255) not null, + defaultValue varchar(255), + possibleValues varchar(255), + subText varchar(255), + status varchar(255) not null, + width int(11), + height int(11), + vertical smallint(1), + extras varchar(255), + display int(11), + viewScreenTitle int(11), + displayInSearch int(11), + searchIn int(11), + fieldInOtherThingId varchar(22), + primary key (fieldId, thingId, assetId) + ) +ENDSQL + + $session->config->addToArray("assets","WebGUI::Asset::Wobject::Thingy"); + + print "DONE!\n" unless $quiet; +} # --------------- DO NOT EDIT BELOW THIS LINE -------------------------------- #---------------------------------------------------------------------------- diff --git a/etc/WebGUI.conf.original b/etc/WebGUI.conf.original index da9ca791d..0cd05b2c9 100644 --- a/etc/WebGUI.conf.original +++ b/etc/WebGUI.conf.original @@ -235,8 +235,9 @@ "WebGUI::Asset::Wobject::InOutBoard", "WebGUI::Asset::File::ZipArchive", "WebGUI::Asset::Wobject::WSClient", - "WebGUI::Asset::Wobject::SQLForm" - ], + "WebGUI::Asset::Wobject::SQLForm", + "WebGUI::Asset::Wobject::Thingy" + ], # Specify the list assets that are used for utility purposes only # and are not typically used as a normal part of content diff --git a/lib/WebGUI/Asset/Wobject/Thingy.pm b/lib/WebGUI/Asset/Wobject/Thingy.pm new file mode 100644 index 000000000..e0197f4da --- /dev/null +++ b/lib/WebGUI/Asset/Wobject/Thingy.pm @@ -0,0 +1,2544 @@ +package WebGUI::Asset::Wobject::Thingy; + +#------------------------------------------------------------------- +# WebGUI is Copyright 2001-2006 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 warnings; +use version; +use Tie::IxHash; +use WebGUI::International; +use WebGUI::Utility; +use WebGUI::Text; +use WebGUI::Form::File; +use base 'WebGUI::Asset::Wobject'; + +our $VERSION = "1.0.0"; + +#------------------------------------------------------------------- + +=head2 addField ( field, retainIds ) + +Adds a new field. + +=head3 + +A hashref containing the properties of the new field. + +=head3 + +If retainIds is true the new field will keep the fieldId and assetId in the properties hashref. The thingId is +always taken from the field hashref. + +=cut + +sub addField { + + my $self = shift; + my $field = shift; + my $retainIds = shift; + my $dbDataType = shift || $self->_getDbDataType($field->{fieldType}); + my $db = $self->session->db; + my $error = $self->session->errorHandler; + my ($oldFieldId, $newFieldId,$useAssetId,$useSequence); + + $error->info("Adding Field, label: ".$field->{label}.", fieldId: ".$field->{fieldId}.",thingId: ".$field->{thingId}); + + if ($retainIds){ + $oldFieldId = $field->{fieldId}; + } + else { + $useAssetId = 1; + #$useSequence = 1; + } + + $field->{fieldId} = "new"; + $newFieldId = $self->setCollateral("Thingy_fields","fieldId",$field,1,$useAssetId); + + if ($retainIds){ + $db->write("update Thingy_fields set fieldId = ".$db->quote($oldFieldId) + ." where fieldId = ".$db->quote($newFieldId)); + $newFieldId = $oldFieldId; + } + + my $thingyTableName = "Thingy_".$field->{thingId}; + my $columnName = "field_".$newFieldId; + $db->write( + "ALTER TABLE ".$db->dbh->quote_identifier($thingyTableName) + ." ADD ".$db->dbh->quote_identifier($columnName)." ". $dbDataType + ); + + return $newFieldId; +} + +#------------------------------------------------------------------- + +=head2 addThing ( thing, retainIds ) + +Adds a new thing. + +=head3 + +A hashref containing the properties of the new thing. + +=head3 + +If retainIds is true the new thing will keep the thingId and assetId in the properties hashref. + +=cut + +sub addThing { + + my $self = shift; + my $thing = shift; + my $retainIds = shift; + my $db = $self->session->db; + my $error = $self->session->errorHandler; + my ($oldThingId, $newThingId,$useAssetId); + + $error->info("Adding Thing, label: ".$thing->{label}.", id: ".$thing->{thingId}); + + if ($retainIds){ + $oldThingId = $thing->{thingId}; + } + else{ + $useAssetId = 1; + } + + $thing->{thingId} = "new"; + $newThingId = $self->setCollateral("Thingy_things","thingId",$thing,0,$useAssetId); + + if ($retainIds){ + $db->write("update Thingy_things set thingId = ".$db->quote($oldThingId) + ." where thingId = ".$db->quote($newThingId)); + $newThingId = $oldThingId; + } + + $db->write("create table ".$db->dbh->quote_identifier("Thingy_".$newThingId)."( + thingDataId varchar(22) binary not null, + dateCreated int not null, + createdById varchar(22) not null, + updatedById varchar(22) not null, + updatedByName varchar(255) not null, + lastUpdated int not null, + ipAddress varchar(255), + primary key (thingDataId) + )"); + + return $newThingId; +} + +#------------------------------------------------------------------- + +=head2 definition ( ) + +defines wobject properties for Thingy instances. If you choose to "autoGenerateForms", the +getEditForm method is unnecessary/redundant/useless. + +=cut + +sub definition { + my $class = shift; + my $session = shift; + my $definition = shift; + my $i18n = WebGUI::International->new($session, 'Asset_Thingy'); + my %properties; + tie %properties, 'Tie::IxHash'; + + %properties = ( + templateId =>{ + fieldType=>"template", + defaultValue=>'ThingyTmpl000000000001', + tab=>"display", + noFormPost=>0, + namespace=>"Thingy", + hoverHelp=>$i18n->get('templateId label description'), + label=>$i18n->get('templateId label'), + }, + defaultThingId => { + autoGenerate => 0, + default=>undef, + fieldType=>"selectBox", + }, + ); + push(@{$definition}, { + assetName=>$i18n->get('assetName'), + icon=>'Thingy.gif', + autoGenerateForms=>1, + tableName=>'Thingy', + className=>'WebGUI::Asset::Wobject::Thingy', + properties=>\%properties + }); + return $class->SUPER::definition($session, $definition); +} + + +#------------------------------------------------------------------- + +=head2 duplicate ( ) + +Duplicates a Thingy, including the definitions of the Things in this Thingy and their fields. + +=cut + +sub duplicate { + my $self = shift; + my $options = shift; + my $newAsset = $self->SUPER::duplicate($options); + my $db = $self->session->db; + my $assetId = $self->get("assetId"); + my $fields; + + my $things = $db->buildArrayRefOfHashRefs('select * from Thingy_things where assetId = ?',[$assetId]); + foreach my $thing (@$things) { + my $oldThingId = $thing->{thingId}; + my $newThingId = $newAsset->addThing($thing,0); + $fields = $db->buildArrayRefOfHashRefs('select * from Thingy_fields where assetId=? and thingId=?' + ,[$assetId,$oldThingId]); + foreach my $field (@$fields) { + # set thingId to newly created thing's id. + $field->{thingId} = $newThingId; + + $newAsset->addField($field,0); + } + } + return $newAsset; +} + +#------------------------------------------------------------------- + +=head2 exportAssetData ( ) + +See WebGUI::AssetPackage::exportAssetData() for details. + +=cut + +sub exportAssetData { + my $self = shift; + my $data = $self->SUPER::exportAssetData; + my $db = $self->session->db; + my $assetId = $self->get("assetId"); + + $data->{things} = $db->buildArrayRefOfHashRefs('select * from Thingy_things where assetId = ?',[$assetId]); + $data->{fields} = $db->buildArrayRefOfHashRefs('select * from Thingy_fields where assetId = ?',[$assetId]); + + return $data; +} +#------------------------------------------------------------------- + +=head2 deleteField ( fieldId , thingId ) + +Deletes a field from Collateral and drops the fields column in the thingy table. + +=head3 fieldId + +The id of the field that should be deleted. + +=head3 thingId + +The id of the thing to which the field to be deleted belongs. + +=cut + +sub deleteField { + + my $self = shift; + my $fieldId = shift; + my $thingId = shift; + my $db = $self->session->db; + my $error = $self->session->errorHandler; + + my ($deletedSequenceNumber) = $db->quickArray("select sequenceNumber from Thingy_fields where fieldId = ?",[$fieldId]); + $self->deleteCollateral("Thingy_fields","fieldId",$fieldId); + $db->write("update Thingy_fields set sequenceNumber = sequenceNumber -1 where sequenceNumber > ?",[$deletedSequenceNumber]); + + my ($columnExists) = $db->quickArray("show columns from ".$db->dbh->quote_identifier("Thingy_".$thingId) + ." like ".$db->quote("field_".$fieldId)); + if ($columnExists){ + $db->write("ALTER TABLE ".$db->dbh->quote_identifier("Thingy_".$thingId)." DROP " + .$db->dbh->quote_identifier("field_".$fieldId)); + } + $error->info("Deleted field: $fieldId in thing: $thingId."); + return undef; +} + +#------------------------------------------------------------------- + +=head2 deleteThing ( thingId ) + +Deletes a Thing and its fields from Collateral and drops the things table. + +=head3 thingId + +The id of the Thing that should be deleted. + +=cut + +sub deleteThing { + + my $self = shift; + my $thingId = shift; + my $session = $self->session; + my $error = $session->errorHandler; + + $self->deleteCollateral("Thingy_things","thingId",$thingId); + $self->deleteCollateral("Thingy_fields","thingId",$thingId); + $self->session->db->write("drop table if exists ".$session->db->dbh->quote_identifier("Thingy_".$thingId)); + + $error->info("Deleted thing: $thingId."); + return undef; +} + +#------------------------------------------------------------------- + +=head2 _getDbDataType ( fieldType ) + +returns the database data type for a field based on the fieldType. + +=head3 fieldType + +The fieldType for which the database data type should be returned. + +=cut + +sub _getDbDataType { + + my $self = shift; + my $fieldType = shift; + my $session = $self->session; + + my ($dbDataType, $formClass); + + if ($fieldType =~ m/^otherThing/x){ + $dbDataType = "varchar(22)"; + } + else{ + $formClass = 'WebGUI::Form::' . ucfirst $fieldType; + my $formElement = eval { WebGUI::Pluggable::instanciate($formClass, "new", [$session]) }; + $dbDataType = $formElement->get("dbDataType"); + } + return $dbDataType; + +} + +#------------------------------------------------------------------- + +=head2 getEditFieldForm ( ) + +returns the form that will be used in the edit dialog for Thingy_fields. + +=cut + +sub getEditFieldForm { + + my $self = shift; + my $field = shift; + my (%fieldStatus, $f, %fieldTypes, $things); + my $fieldId = $field->{fieldId} || "new"; + my $i18n = WebGUI::International->new($self->session, 'Asset_Thingy'); + my $defaultValue; + tie %fieldStatus, 'Tie::IxHash'; + tie %fieldTypes, 'Tie::IxHash'; + + %fieldStatus = ( + "hidden" => $i18n->get('fieldstatus hidden label'), + "visible" => $i18n->get('fieldstatus visible label'), + "editable" => $i18n->get('fieldstatus editable label'), + "required" => $i18n->get('fieldstatus required label'), + ); + + %fieldTypes = ( + "dateTime" => "dateTime", + "TimeField" => "TimeField", + "float" => "float", + "zipcode" => "zipcode", + "text" => "text", + "textarea" => "textarea", + "HTMLArea" => "HTMLArea", + "url" => "url", + "date" => "date", + "email" => "email", + "phone" => "phone", + "integer" => "integer", + "yesNo" => "yesNo", + "selectList" => "select", + "radioList" => "radioList", + "checkList" => "checkList", + "selectBox" => "selectBox", + "file" => "file", + ); + + $things = $self->session->db->read('select thingId, label from Thingy_things left join asset using(assetId) +where asset.state = "published"'); + while (my $thing = $things->hashRef) { + my $fieldType = "otherThing_".$thing->{thingId}; + $fieldTypes{$fieldType} = $thing->{label}; + } + + my $dialogPrefix; + if ($fieldId eq "new"){ + $dialogPrefix = "addDialog"; + } + else{ + $dialogPrefix = "edit_".$fieldId."_Dialog"; + } + + $f = WebGUI::HTMLForm->new($self->session,{ + action=>$self->getUrl, + tableExtras=>' cellpadding="0" cellspacing="0"' + }); + $f->hidden( + -name => "fieldId", + -value => $fieldId, + ); + $f->hidden( + -name => "thingId", + -value => $field->{thingId}, + ); + $f->hidden( + -name => "func", + -value => "editFieldSave" + ); + $f->text( + -name=>"label", + -label=>$i18n->get('field label label'), + -hoverHelp=>$i18n->get('field label description'), + -value=>$field->{label} + ); + $f->selectBox( + -name=>"fieldType", + -label=>$i18n->get('field type label'), + -hoverHelp=>$i18n->get('field type description'), + -value=>$field->{fieldType} || "text", + -options=>\%fieldTypes, + -id=>$dialogPrefix."_fieldType_formId", + ); + $f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_fieldInThing_module")); + + $f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_defaultFieldInThing_module")); + unless ($field->{fieldType} =~ m/^otherThing/x){ + $defaultValue = $field->{defaultValue}; + } + my $defaultValueForm = WebGUI::Form::Textarea($self->session, { + name=>"defaultValue", + label=>$i18n->get('default value label'), + hoverHelp=>$i18n->get('default value description'), + value=>$defaultValue, + subtext=>'
'.$i18n->get(85), + width=>200, + height=>60, + resizable=>0, + }); + $f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_defaultValue_module",$defaultValueForm,$i18n->get('default value label'))); + + $f->text( + -name=>"subtext", + -value=>$field->{subtext}, + -label=>$i18n->get('subtext label'), + -hoverHelp=>$i18n->get('subtext description'), + ); + $f->selectBox( + -name=>"status", + -options=>\%fieldStatus, + -label=>$i18n->get('field status label'), + -hoverHelp=>$i18n->get('field status description'), + -value=> [ $field->{status} || "editable" ] , + ); + + my $widthForm = WebGUI::Form::Integer($self->session, { + name=>"width", + hoverHelp=>$i18n->get('width description'), + value=>($field->{width} || 250), + size=>10, + }); + $f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_width_module",$widthForm,$i18n->get('width label'))); + + my $sizeForm = WebGUI::Form::Integer($self->session, { + name=>"size", + hoverHelp=>$i18n->get('size description'), + value=>($field->{size} || 25), + size=>10, + }); + $f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_size_module",$sizeForm,$i18n->get('size label'))); + + my $heightForm = WebGUI::Form::Integer($self->session, { + name=>"height", + value=>$field->{height} || 40, + label=>$i18n->get('height label'), + hoverHelp=>$i18n->get('height description'), + size=>10, + }); + $f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_height_module",$heightForm,$i18n->get('height label'))); + + my $verticalForm = WebGUI::Form::YesNo($self->session, { + name=>"vertical", + value=>$field->{vertical}, + label=>$i18n->get('vertical label'), + hoverHelp=>$i18n->get('vertical description'), + }); + $f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_vertical_module",$verticalForm,$i18n->get('vertical label'))); + + my $valuesForm = WebGUI::Form::Textarea($self->session, { + name=>"possibleValues", + hoverHelp=>$i18n->get('possible values description'), + value=>$field->{possibleValues}, + width=>200, + height=>60, + resizable=>0, + }); + $f->raw($self->getHtmlWithModuleWrapper($dialogPrefix."_values_module",$valuesForm,$i18n->get('possible values label'))); + $f->text( + -name=>"extras", + -value=>$field->{extras}, + -label=>$i18n->get('extras label'), + -hoverHelp=>$i18n->get('extras description'), + ); + return $f; +} +#------------------------------------------------------------------- + +=head2 getEditForm ( ) + +Returns the tabform object that will be used in generating the edit page for Thingy's. +Adds the defaultThingId selectBox to the tabform object, because the options for this selectBox depends on already +existing Things. The rest of the form is auto-generated. + +=cut + +sub getEditForm { + + my $self = shift; + my $i18n = WebGUI::International->new($self->session, 'Asset_Thingy'); + my $tabform = $self->SUPER::getEditForm(); + + my $things = $self->session->db->buildHashRef('select thingId, label from Thingy_things where assetId = ?',[$self->get("assetId")]); + + $tabform->getTab("display")->selectBox( + -name=>"defaultThingId", + -value=>$self->get("defaultThingId"), + -label=>$i18n->get("default thing label"), + -options=>$things, + ); + + return $tabform; +} +#------------------------------------------------------------------- + +=head2 getFieldValue ( value, field ) + +Processes the field value for date(Time) fields and Other Thing fields. + +=head3 value + +The value as stored in the database. + +=head field + +A reference to a hash containing the fields properties. + +=cut + +sub getFieldValue { + + my $self = shift; + my $value = shift; + my $field = shift; + my $dateFormat = shift || "%z"; + my $dateTimeFormat = shift; + my $processedValue = $value; + my $dbh = $self->session->db->dbh; + + if ($field->{fieldType} eq "date"){ + $processedValue = $self->session->datetime->epochToHuman($value,$dateFormat); + } + elsif ($field->{fieldType} eq "dateTime"){ + $processedValue = $self->session->datetime->epochToHuman($value,$dateTimeFormat); + } + elsif ($field->{fieldType} =~ m/^otherThing/x) { + my $otherThingId = $field->{fieldType}; + $otherThingId =~ s/^otherThing_//x; + ($processedValue) = $self->session->db->quickArray('select ' + .$dbh->quote_identifier('field_'.$field->{fieldInOtherThingId}) + .' from '.$dbh->quote_identifier('Thingy_'.$otherThingId) + .' where thingDataId = ?',[$value]); + } + elsif ($field->{fieldType} eq "file") { + $processedValue = WebGUI::Form::File->new($self->session,{value=>$value})->displayValue(); + } + + return $processedValue; + +} + +#------------------------------------------------------------------- + +=head2 getFormElement ( data ) + +Returns the form element tied to this field. + +=head3 data + +A hashref containing the properties of this field. + +=cut + +sub getFormElement { + + my $self = shift; + my $data = shift; + my %param; + my $dbh = $self->session->db->dbh; + + $param{name} = "field_".$data->{fieldId}; + my $name = $param{name}; + $name =~ s/\^.*?\;//xgs ; # remove macro's from user input + $param{value} = $data->{value} || $data->{defaultValue}; + $param{size} = $data->{size}; + $param{height} = $data->{height}; + $param{width} = $data->{width}; + $param{extras} = $data->{extras}; + $param{vertical} = $data->{vertical}; + $param{fieldType} = $data->{fieldType}; + + if ($data->{fieldType} eq "checkbox") { + $param{value} = ($data->{defaultValue} =~ /checked/xi) ? 1 : ""; + } + if (WebGUI::Utility::isIn($data->{fieldType},qw(selectList checkList selectBox))) { + my @defaultValues; + if ($self->session->form->param($name)) { + @defaultValues = $self->session->form->selectList($name); + } else { + foreach (split(/\n/x, $data->{value})) { + s/\s+$//x; # remove trailing spaces + push(@defaultValues, $_); + } + } + $param{value} = \@defaultValues; + } + if (WebGUI::Utility::isIn($data->{fieldType},qw(selectList selectBox checkList radioList))) { + delete $param{size}; + my %options; + tie %options, 'Tie::IxHash'; + foreach (split(/\n/x, $data->{possibleValues})) { + s/\s+$//x; # remove trailing spaces + $options{$_} = $_; + } + $param{options} = \%options; + } + if ($data->{fieldType} eq "yesNo") { + if ($data->{defaultValue} =~ /yes/xi) { + $param{value} = 1; + } elsif ($data->{defaultValue} =~ /no/xi) { + $param{value} = 0; + } + } + if ($data->{fieldType} =~ m/^otherThing/x){ + my $otherThingId = $data->{fieldType}; + $otherThingId =~ s/^otherThing_(.*)/$1/x; + $param{fieldType} = "SelectList"; + + my $options = $self->session->db->buildHashRef('select thingDataId, ' + .$dbh->quote_identifier('field_'.$data->{fieldInOtherThingId}) + .' from '.$dbh->quote_identifier('Thingy_'.$otherThingId)); + + my $value = $data->{value} || $data->{defaultValue}; + ($param{value}) = $self->session->db->quickArray('select ' + .$dbh->quote_identifier('field_'.$data->{fieldInOtherThingId}) + .' from '.$dbh->quote_identifier('Thingy_'.$otherThingId) + .' where thingDataId = ?',[$value]); + $param{size} = 1; + $param{multiple} = 0; + $param{options} = $options; + $param{value} = $data->{value} || $data->{defaultValue}; + } + + my $formElement = eval { WebGUI::Pluggable::instanciate("WebGUI::Form::". ucfirst $param{fieldType}, "new", [$self->session, \%param ])}; + return $formElement->toHtml(); + +} + +#------------------------------------------------------------------- + +=head2 getHtmlWithModuleWrapper ( id , formElement, formDescription ) + +Returns a table row containing a form element in a yui module. + +=head3 id + +An id for the module div. + +=head3 formElement + +The from element rendered as html. + +=head3 formDescription + +The description of the from element. + +=cut + +sub getHtmlWithModuleWrapper { + + my $self = shift; + my $id = shift; + my $formElement = shift; + my $formDescription = shift; + + my $html = "\n\n"; + $html .= "\t
\n"; + $html .= "\t
\n"; + $html .= "\t\n"; + $html .= "\t"; + $html .= ""; + $html .= "\t\n\n"; + $html .= "\t
"; + $html .= $formDescription.""; + $html .= $formElement."
"; + $html .= "\t\n
\t\n
\n"; + $html .= ""; + + return $html; + +} + +#------------------------------------------------------------------- + +=head2 hasPrivileges ( groupId ) + +Checks if the current user has a certain privilege on a Thing. +A user that can edit a Thingy asset has all rights on every Thing by definition. + +=head3 groupId + +The id of the group that has the privileges that are to be checked. + +=cut + +sub hasPrivileges { + + my $self = shift; + my $privilegedGroupId = shift; + return ($self->canEdit || $self->session->user->isInGroup($privilegedGroupId)); + +} +#------------------------------------------------------------------- + +=head2 importAssetCollateralData ( data ) + +Imports Things and fields that where exported with a Thingy asset. + +=head3 data + +Hashref containing the Thingy's exported data. + +=cut + +sub importAssetCollateralData { + + my $self = shift; + my $session = $self->session; + my $error = $session->errorHandler; + my $data = shift; + my $id = $data->{properties}{assetId}; + my $class = $data->{properties}{className}; + my $version = $data->{properties}{revisionDate}; + my $assetExists = WebGUI::Asset->assetExists($self->session, $id, $class, $version); + + $error->info("Importing Things for Thingy ".$data->{properties}{title}); + my @importThings; + foreach my $thing (@{$data->{things}}) { + push(@importThings,$thing->{thingId}); + my ($thingIdExists) = $session->db->quickArray("select thingId from Thingy_things where thingId = ". + $session->db->quote($thing->{thingId})); + if ($assetExists && $thingIdExists){ + # update existing thing + $error->info("Updating Thing, label: ".$thing->{label}.", id: ".$thing->{thingId}); + $self->setCollateral("Thingy_things","thingId",$thing,0,0); + } + else{ + # add new thing + $self->addThing($thing,1); + } + } + # delete deleted things + my $thingsInDatabase = $session->db->read('select thingId from Thingy_things where assetId=?',[$self->get("assetId")]); + while (my $thingInDataBase = $thingsInDatabase->hashRef) { + if (!WebGUI::Utility::isIn($thingInDataBase->{thingId},@importThings)){ + # delete thing + $self->deleteThing($thingInDataBase->{thingId}); + } + } + + my @importFields; + foreach my $field (@{$data->{fields}}) { + push(@importFields,$field->{fieldId}); + my $dbDataType = $self->_getDbDataType($field->{fieldType}); + my ($fieldIdExists) = $session->db->quickArray("select fieldId from Thingy_fields where fieldId = ? and thingId = ? ",[$field->{fieldId},$field->{thingId}]); + if ($assetExists && $fieldIdExists){ + # update existing field + $error->info("Updating Field, label: ".$field->{label}.", id: ".$field->{fieldId}); + $self->_updateFieldType($field->{fieldType},$field->{fieldId},$field->{thingId},$field->{assetId},$dbDataType); + $self->setCollateral("Thingy_fields","fieldId",$field,1,0); + } + else{ + # Add field as Collateral, retain fieldId. + $self->addField($field,1,$dbDataType); + } + } + # delete deleted fields + my $fieldsInDatabase = $session->db->read('select fieldId, thingId from Thingy_fields where assetId = ' + .$session->db->quote($self->get("assetId"))); + while (my $fieldInDataBase = $fieldsInDatabase->hashRef) { + if (!WebGUI::Utility::isIn($fieldInDataBase->{fieldId},@importFields)){ + # delete field + $self->deleteField($fieldInDataBase->{fieldId},$fieldInDataBase->{thingId}); + } + } + + return undef; +} + + +#------------------------------------------------------------------- + +=head2 prepareView ( ) + +See WebGUI::Asset::prepareView() for details. + +=cut + +sub prepareView { + my $self = shift; + $self->SUPER::prepareView(); + my $template = WebGUI::Asset::Template->new($self->session, $self->get("templateId")); + $template->prepare; + $self->{_viewTemplate} = $template; + return undef; +} + + +#------------------------------------------------------------------- + +=head2 purge ( ) + +Removes collateral data and drops tables associated with a Thingy asset when the system +purges it's data. + +=cut + +sub purge { + my $self = shift; + my $session = $self->session; + + my @thingIds = $session->db->buildArray("select thingId from Thingy_things where assetId = " + .$session->db->quote($self->getId)); + foreach my $thingId (@thingIds){ + $session->db->write("drop table if exists ".$session->db->dbh->quote_identifier("Thingy_".$thingId)); + } + $self->session->db->write("delete from Thingy_things where assetId = ".$self->session->db->quote($self->getId)); + $self->session->db->write("delete from Thingy_fields where assetId = ".$self->session->db->quote($self->getId)); + + return $self->SUPER::purge; +} + +#------------------------------------------------------------------- + +=head2 triggerWorkflow ( workflowId, ) + +Alters a column for a field if the field's fieldType has changed. + +=head3 workflowId + +The id of the workflow that has to be triggered. + +=cut + +sub triggerWorkflow { + + my $self = shift; + my $workflowId = shift; + my $instance = WebGUI::Workflow::Instance->create($self->session, { + workflowId=>$workflowId, + className=>"WebGUI::Asset::Wobject::Thingy", + methodName=>"new", + parameters=>$self->getId + }); + + # deal with realtime + if ($instance->getWorkflow->isRealtime) { + my $status = $instance->runAll; + if ($status eq "done") { + $instance->delete; + } else { + my $errorMessage = "Realtime workflow instance ".$instance->getId." returned status ".$status." where + 'done' was expected"; + $self->session->errorHandler->warn($errorMessage); + return $errorMessage; + } + } + return undef; +} + +#------------------------------------------------------------------- + +=head2 _updateFieldType ( fieldType, fieldId, thingId, assetId, dbDataType ) + +Alters a column for a field if the field's fieldType has changed. + +=head3 fieldType + +The new fieldType for the field that has to be changed. + +=head3 fieldId + +The id of the field of which should be changed. + +=head3 thingId + +The id of the Thing to which the field belongs. + +=head3 assetId + +The id of the Thingy asset to which the field belongs. + +=head3 dbDataType + +The data type that the field should have in the database. + +=cut + +sub _updateFieldType { + + my $self = shift; + my $session = $self->session; + my $error = $session->errorHandler; + + my $newFieldType = shift; + my $fieldId = shift; + my $thingId = shift; + my $assetId = shift; + my $dbDataType = shift; + + my ($fieldType) = $self->session->db->quickArray("select fieldType from Thingy_fields where fieldId = " + .$self->session->db->quote($fieldId)." and assetId = ".$self->session->db->quote($assetId) + ." and thingId = ".$self->session->db->quote($thingId)); + + if($newFieldType ne $fieldType){ + my $thingyTableName = "Thingy_".$thingId; + my $columnName = "field_".$fieldId; + $error->info("changing column: $columnName, table: $thingyTableName"); + $self->session->db->write( + "ALTER TABLE ".$session->db->dbh->quote_identifier($thingyTableName). + " CHANGE ".$self->session->db->dbh->quote_identifier($columnName)." " + .$session->db->dbh->quote_identifier($columnName)." ".$dbDataType + ); + } + return undef; +} +#------------------------------------------------------------------- + +=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 $db = $self->session->db; + my $i18n = WebGUI::International->new($self->session,"Asset_Thingy"); + my ($defaultThingId,$defaultView); + + my $var = $self->get; + my $url = $self->getUrl; + + $var->{canEditThings} = $self->canEdit; + $var->{"addThing_url"} = $session->url->append($url, 'func=editThing;thingId=new'); + $var->{"manage_url"} = $session->url->append($url, 'func=manage'); + + #Get this Thingy's default thing + $defaultThingId = $self->get("defaultThingId"); + + if ($defaultThingId){ + # get default view + ($defaultView) = $db->quickArray("select defaultView from Thingy_things where thingId=?",[$defaultThingId]); + if ($defaultView eq "searchThing"){ + return $self->www_search($defaultThingId); + } + elsif ($defaultView eq "addThing"){ + return $self->www_editThingData($defaultThingId,"new"); + } + } + else{ + return $self->processTemplate($var, undef, $self->{_viewTemplate}); + } +} +#------------------------------------------------------------------- + +=head2 www_deleteFieldConfirm ( ) + +Deletes a field definition. Drops the column of a Thing's table that holds the data of this field. + +=cut + +sub www_deleteFieldConfirm { + my $self = shift; + my $session = $self->session; + my $fieldId = $session->form->process("fieldId"); + my $thingId = $session->form->process("thingId"); + return $session->privilege->insufficient() unless $self->canEdit; + + $self->deleteField($fieldId,$thingId); + + return 1; +} +#------------------------------------------------------------------- + +=head2 www_deleteThingConfirm ( ) + +Deletes a Thing, including field definitions and instances of this Thing and drops the table that holds the +instances of this Thing. + +=cut + +sub www_deleteThingConfirm { + my $self = shift; + my $thingId = $self->session->form->process("thingId"); + return $self->session->privilege->insufficient() unless $self->canEdit; + + $self->deleteThing($thingId); + + return $self->www_manage; +} +#------------------------------------------------------------------- + +=head2 www_deleteThingDataConfirm ( ) + +Deletes data in a Thing. + +=cut + +sub www_deleteThingDataConfirm { + + my $self = shift; + my $db = $self->session->db; + + my $thingId = $self->session->form->process("thingId"); + my $thingDataId = $self->session->form->process('thingDataId'); + + my ($groupIdEdit) = $db->quickHash("select groupIdEdit from Thingy_things where thingId=?",[$thingId]); + return $self->session->privilege->insufficient() unless $self->hasPrivileges($groupIdEdit); + + $self->deleteCollateral("Thingy_".$thingId,"thingDataId",$thingDataId); + + my ($onDeleteWorkflowId) = $db->quickArray("select onDeleteWorkflowId from Thingy_things where thingId=?" + ,[$thingId]); + if ($onDeleteWorkflowId){ + $self->triggerWorkflow($onDeleteWorkflowId); + } + + return $self->www_search; +} + +#------------------------------------------------------------------- + +=head2 www_editThing ( ) + +Shows a form to edit or add a Thing. General properties of a Thing are stored when the form is submitted. + +When editing fields in a thing some changes are saved immediately. Because of this a table has to be created for a new Thing +before the form is submitted. + +=cut + +sub www_editThing { + my $self = shift; + my $session = $self->session; + my ($tabForm, $output, %properties, $tab, %afterSave, %defaultView, $fields); + my ($fieldsHTML, $fieldsViewScreen, $fieldsSearchScreen); + tie %afterSave, 'Tie::IxHash'; + return $session->privilege->insufficient() unless $self->canEdit; + my $i18n = WebGUI::International->new($session, "Asset_Thingy"); + + my $thingId = $session->form->process("thingId"); + return $self->www_view unless ($thingId); + + if($thingId eq "new"){ + my $groupIdEdit = $self->get("groupIdEdit"); + %properties = ( + thingId=>$thingId, + label=>$i18n->get('assetName'), + editScreenTitle=>$i18n->get('edit screen title label'), + groupIdAdd=>$groupIdEdit, + groupIdEdit=>$groupIdEdit, + saveButtonLabel=>$i18n->get('default save button label'), + afterSave=>'searchThisThing', + editTemplateId=>"ThingyTmpl000000000003", + groupIdView=>$groupIdEdit, + viewTemplateId=>"ThingyTmpl000000000002", + defaultView=>'searchThing', + searchScreenTitle=>$i18n->get('search screen title label'), + groupIdSearch=>$groupIdEdit, + groupIdExport=>$groupIdEdit, + groupIdImport=>$groupIdEdit, + searchTemplateId=>"ThingyTmpl000000000004", + thingsPerPage=>25, + ); + $thingId = $self->addThing(\%properties,0); + } + else{ + %properties = $self->session->db->quickHash("select * from Thingy_things where thingId=".$self->session->db->quote($thingId)); + } + + $tabForm = WebGUI::TabForm->new($self->session, undef, undef, $self->getUrl('func=view')); + $tabForm->hidden({ + name => 'func', + value => 'editThingSave' + }); + $tabForm->hidden({ + name => 'thingId', + value => $thingId + }); + + $tabForm->addTab('fields', $i18n->get('fields tab label')); + + $self->session->style->setScript($self->session->url->extras('yui/build/utilities/utilities.js'), {type => + 'text/javascript'}); + $self->session->style->setScript($self->session->url->extras('yui/build/yahoo-dom-event/yahoo-dom-event.js'), {type=> + 'text/javascript'}); + $self->session->style->setScript($self->session->url->extras('yui/build/connection/connection-min.js'), {type => + 'text/javascript'}); + $self->session->style->setScript($self->session->url->extras('wobject/Thingy/thingy.js'), {type=> + 'text/javascript'}); + $self->session->style->setLink($self->session->url->extras('wobject/Thingy/thingy.css'), {type + =>'text/css', rel=>'stylesheet'}); + + $tab = $tabForm->getTab('fields'); + + $tab->text( + -name => 'label', + -label => $i18n->get('thing name label'), + -hoverHelp => $i18n->get('thing name description'), + -value => $properties{label}, + -maxlength => 64, + ); + + $fieldsHTML = "\n" + ."\n" + ."
\n" + ."".$i18n->get('fields label')."\n" + ."\n" + ."\n" + ." \n" + ."\n" + ."\n" + ."
\n" + ."
" + ." " + ."
\n" + ."
\n" + ."
\n" + ."
    \n"; + + $fieldsViewScreen = "
\n
" + ."".$i18n->get('fields label')."" + ."\n" + ."\n" + ." \n" + ." " + ." \n" + .""; + + $fieldsSearchScreen = "
".$i18n->get('display label')."".$i18n->get('view screen title label')."
\n
\n" + ."".$i18n->get('fields label')."\n" + ."\n" + ."\n" + ." \n" + ." \n" + ." \n" + ." \n" + ."\n"; + + $fields = $self->session->db->read('select * from Thingy_fields where assetId = '.$self->session->db->quote($self->get("assetId")).' and thingId = '.$self->session->db->quote($thingId).' order by sequenceNumber'); + while (my $field = $fields->hashRef) { + my $formElement; + if ($field->{fieldType} eq "file"){ + $formElement = ""; + } + else{ + $formElement = $self->getFormElement($field); + } + $fieldsHTML .= "
  • " + ."\n
  • ".$i18n->get('display label')."".$i18n->get('search label')."".$i18n->get('sort by label')."
    \n\n" + ." \n" + ." \n" + ." \n\n
    ".$field->{label}."".$formElement." session->url->page() + ."?func=editField;fieldId=".$field->{fieldId}.";thingId=".$thingId."','".$field->{fieldId}."')\" value='Edit' type='button'>" + ."session->url->page()."','".$field->{fieldId}."','".$thingId."')\" " + ."value='Delete' type='button'>
    \n\n"; + + $fieldsViewScreen .= "" + ."".$field->{label} + .""; + $fieldsViewScreen .= WebGUI::Form::checkbox($self->session, { + checked => $field->{display}, + name => "display_".$field->{fieldId} + }); + $fieldsViewScreen .= "\n"; + $fieldsViewScreen .= WebGUI::Form::checkbox($self->session, { + checked => $field->{viewScreenTitle}, + name => "viewScreenTitle_".$field->{fieldId} + }); + $fieldsViewScreen .= "\n\n
    "; + + $fieldsSearchScreen .= "\n" + ."".$field->{label} + ."\n"; + $fieldsSearchScreen .= WebGUI::Form::checkbox($self->session, { + checked => $field->{displayInSearch}, + name => "displayInSearch_".$field->{fieldId} + }); + $fieldsSearchScreen .= "\n"; + $fieldsSearchScreen .= WebGUI::Form::checkbox($self->session, { + checked => $field->{searchIn}, + name => "searchIn_".$field->{fieldId} + }); + my $sortBy; + $sortBy = 1 if ($properties{sortBy} eq $field->{fieldId}); + $fieldsSearchScreen .= "\n"; + $fieldsSearchScreen .= WebGUI::Form::radio($self->session, { + checked => $sortBy, + name => "sortBy", + value => $field->{fieldId}, + }); + $fieldsSearchScreen .= "\n\n
    "; + } + + $fieldsHTML .= "\n" + ."\n" + ."\n" + ."
    \n"; + + $tab->raw($fieldsHTML); + + $tabForm->addTab('edit', $i18n->get('edit screen tab label')); + $tab = $tabForm->getTab('edit'); + + $tab->text( + -name => 'editScreenTitle', + -label => $i18n->get('edit screen title label'), + -hoverHelp => $i18n->get('edit screen title description'), + -value => $properties{editScreenTitle}, + -maxlength => 64, + ); + $tab->textarea( + -name => 'editInstructions', + -label => $i18n->get('edit instructions label'), + -hoverHelp => $i18n->get('edit instructions description'), + -value => $properties{editInstructions}, + -maxlength => 64, + ); + $tab->group( + -name=> "groupIdAdd", + -value=> $properties{groupIdAdd}, + -hoverHelp=> $i18n->get('who can add description'), + -label => $i18n->get('who can add label') + ); + $tab->group( + -name=> "groupIdEdit", + -value=> $properties{groupIdEdit}, + -hoverHelp=> $i18n->get('who can edit description'), + -label => $i18n->get('who can edit label') + ); + $tab->text( + -name => 'saveButtonLabel', + -label => $i18n->get('save button label label'), + -hoverHelp => $i18n->get('save button label description'), + -value => $properties{saveButtonLabel} || $i18n->get('default save button label'), + -maxlength => 64, + ); + %afterSave = ( + "searchThisThing" => $i18n->get('search this thing label'), + "viewLastEdited" => $i18n->get('view last edited label'), + "addThing" => $i18n->get('add thing label'), + "thingyDefault" => $i18n->get('view thingy default label'), + ); + my $otherThings = $session->db->read("select thingId, label from Thingy_things left join asset using(assetId) +where thingId != ? and asset.state = 'published'",[$thingId]); + while (my $otherThing = $otherThings->hashRef) { + $afterSave{'searchOther_'.$otherThing->{thingId}} = $i18n->get('search other thing label').$otherThing->{label}; + $afterSave{'addOther_'.$otherThing->{thingId}} = $i18n->get('add other thing label').$otherThing->{label}; + } + + $tab->selectBox( + -name=>"afterSave", + -options=>\%afterSave, + -label=>$i18n->get('after save label'), + -hoverHelp=>$i18n->get('after save description'), + -value=>[ $properties{afterSave} || 'searchThisThing' ] + ); + $tab->template( + -name=>"editTemplateId", + -value=>$properties{editTemplateId}, + -namespace=>"Thingy/EditThing", + -label=>$i18n->get('edit template label'), + -hoverHelp=>$i18n->get('edit template description'), + ); + + + $tab->workflow( + -name=>"onAddWorkflowId", + -value=>$properties{onAddWorkflowId} || "", + -type=>"WebGUI::Asset::Wobject::Thingy", + -label=>$i18n->get('on add workflow label'), + -none=>1, + -includeRealtime=>1, + -hoverHelp=>$i18n->get('on add workflow description'), + ); + + $tab->workflow( + -name=>"onEditWorkflowId", + -value=>$properties{onEditWorkflowId} || "", + -type=>"WebGUI::Asset::Wobject::Thingy", + -label=>$i18n->get('on edit workflow label'), + -none=>1, + -includeRealtime=>1, + -hoverHelp=>$i18n->get('on edit workflow description'), + ); + + $tab->workflow( + -name=>"onDeleteWorkflowId", + -value=>$properties{onDeleteWorkflowId} || "", + -type=>"WebGUI::Asset::Wobject::Thingy", + -label=>$i18n->get('on delete workflow label'), + -none=>1, + -includeRealtime=>1, + -hoverHelp=>$i18n->get('on delete workflow description'), + ); + + $tabForm->addTab('view', $i18n->get('view screen tab label')); + $tab = $tabForm->getTab('view'); + $tab->group( + -name=> "groupIdView", + -value=> $properties{groupIdView}, + -hoverHelp=> $i18n->get('who can view description'), + -label => $i18n->get('who can view label') + ); + $tab->template( + -name=>"viewTemplateId", + -value=>$properties{viewTemplateId}, + -namespace=>"Thingy/ViewThing", + -label=>$i18n->get('view template label'), + -hoverHelp=>$i18n->get('view template description') + ); + %defaultView = ( + "searchThing" => $i18n->get('search thing label'), + "addThing" => $i18n->get('add thing label'), + ); + $tab->selectBox( + -name=>"defaultView", + -options=>\%defaultView, + -label=>$i18n->get('default view label'), + -hoverHelp=>$i18n->get('default view description'), + -value=>[ $properties{defaultView} || 'searchThing' ] + ); + + $tab->raw($fieldsViewScreen); + + $tabForm->addTab('search', $i18n->get('search screen tab label')); + $tab = $tabForm->getTab('search'); + $tab->text( + -name => 'searchScreenTitle', + -label => $i18n->get('search screen title label'), + -hoverHelp => $i18n->get('search screen title description'), + -value => $properties{searchScreenTitle}, + -maxlength => 64, + ); + + $tab->textarea( + -name => 'searchDescription', + -label => $i18n->get('search description label'), + -hoverHelp => $i18n->get('search description description'), + -value => $properties{searchDescription}, + -maxlength => 64, + ); + + $tab->group( + -name=> "groupIdSearch", + -value=> $properties{groupIdSearch}, + -hoverHelp=> $i18n->get('who can search description'), + -label=> $i18n->get('who can search label') + ); + $tab->group( + -name=> "groupIdImport", + -value=> $properties{groupIdImport}, + -hoverHelp=> $i18n->get('who can import description'), + -label=> $i18n->get('who can import label') + ); + $tab->group( + -name=> "groupIdExport", + -value=> $properties{groupIdExport}, + -hoverHelp=> $i18n->get('who can export description'), + -label=>$i18n->get('who can export label') + ); + $tab->template( + -name=>"searchTemplateId", + -value=>$properties{searchTemplateId}, + -namespace=>"Thingy/SearchThing", + -label=>$i18n->get('search template label'), + -hoverHelp=>$i18n->get('search template description') + ); + $tab->integer( + -name=>'thingsPerPage', + -label=>$i18n->get('things per page label'), + -hoverHelp => $i18n->get('things per page description'), + -value => $properties{thingsPerPage}, + ); + $tab->raw($fieldsSearchScreen); + + $output = $tabForm->print; + + my $dialog = "
    \n" + ."
    ".$i18n->get('add field label')."
    \n" + ."
    \n"; + + my %fieldProperties; + $fieldProperties{thingId} = $thingId; + my $dialogBody = $self->getEditFieldForm(\%fieldProperties); + $dialog .= $dialogBody->print; + + $dialog .= "
    \n" + ."
    "; + + $output = $self->getAdminConsole->render($output, $i18n->get('edit thing title')); + $output .= $dialog; + return $output; +} + +#------------------------------------------------------------------- + +=head2 www_editThingSave ( ) + +Processes and saves the general properties of a Thing and some field properties that are not persisted to the +database immediately. + +=cut + +sub www_editThingSave { + + my $self = shift; + return $self->session->privilege->insufficient() unless $self->canEdit; + + my ($thingId, $fields); + $thingId = $self->session->form->process("thingId"); + $self->setCollateral("Thingy_things","thingId",{ + thingId=>$thingId, + label=>$self->session->form->process("label"), + editScreenTitle=>$self->session->form->process("editScreenTitle"), + editInstructions=>$self->session->form->process("editInstructions"), + groupIdAdd=>$self->session->form->process("groupIdAdd"), + groupIdEdit=>$self->session->form->process("groupIdEdit"), + saveButtonLabel=>$self->session->form->process("saveButtonLabel"), + afterSave=>$self->session->form->process("afterSave"), + editTemplateId=>$self->session->form->process("editTemplateId") || 1, + onAddWorkflowId=>$self->session->form->process("onAddWorkflowId"), + onEditWorkflowId=>$self->session->form->process("onEditWorkflowId"), + onDeleteWorkflowId=>$self->session->form->process("onDeleteWorkflowId"), + groupIdView=>$self->session->form->process("groupIdView"), + viewTemplateId=>$self->session->form->process("viewTemplateId") || 1, + defaultView=>$self->session->form->process("defaultView"), + searchScreenTitle=>$self->session->form->process("searchScreenTitle"), + searchDescription=>$self->session->form->process("searchDescription"), + groupIdSearch=>$self->session->form->process("groupIdSearch"), + groupIdImport=>$self->session->form->process("groupIdImport"), + groupIdExport=>$self->session->form->process("groupIdExport"), + searchTemplateId=>$self->session->form->process("searchTemplateId") || 1, + thingsPerPage=>$self->session->form->process("thingsPerPage") || 25, + sortBy=>$self->session->form->process("sortBy"), + },0,1); + + $fields = $self->session->db->read('select * from Thingy_fields where assetId = '.$self->session->db->quote($self->get("assetId")).' and thingId = '.$self->session->db->quote($thingId).' order by sequenceNumber'); + while (my $field = $fields->hashRef) { + my $display = $self->session->form->process("display_".$field->{fieldId}) || 0; + my $viewScreenTitle = $self->session->form->process("viewScreenTitle_".$field->{fieldId}) || 0; + my $displayInSearch = $self->session->form->process("displayInSearch_".$field->{fieldId}) || 0; + my $searchIn = $self->session->form->process("searchIn_".$field->{fieldId}) || 0; + + $self->session->db->write("update Thingy_fields set display = ".$display.", viewScreenTitle = ".$viewScreenTitle.", displayinSearch = ".$displayInSearch.", searchIn = ".$searchIn." where fieldId = ".$self->session->db->quote($field->{fieldId})." and thingId = ".$self->session->db->quote($thingId)); + } + return $self->www_manage; +} +#------------------------------------------------------------------- + +=head2 www_editField ( ) + +Returns the html for a pop-up dialog to add or edit a field. + +=cut + +sub www_editField { + + my $self = shift; + my (%properties,$thingId,$fieldId,$dialogBody); + return $self->session->privilege->insufficient() unless $self->canEdit; + $fieldId = $self->session->form->process("fieldId"); + $thingId = $self->session->form->process("thingId"); + %properties = $self->session->db->quickHash("select * from Thingy_fields where thingId=".$self->session->db->quote($thingId)." and fieldId = ".$self->session->db->quote($fieldId)." and assetId = ".$self->session->db->quote($self->get("assetId"))); + $dialogBody = $self->getEditFieldForm(\%properties); + $self->session->output->print($dialogBody->print); + return "chunked"; +} +#------------------------------------------------------------------- + +=head2 www_editFieldSave ( ) + +Processes and saves a field. Returns the edited/added fieldId and the inner html for a list item on the fields tab of the edit Thing screen. + +=cut + +sub www_editFieldSave { + + my $self = shift; + my $session = $self->session; + return $session->privilege->insufficient() unless $self->canEdit; + my ($fieldId, $fieldTypeChanged, $newFieldId, $formClass, $dbDataType, $thingyTableName, $columnName); + my (%properties,$listItemHTML,$formElement); + my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); + my $label = $session->form->process("label"); + my $thingId = $self->session->form->process("thingId"); + my $error = $self->session->errorHandler; + my $defaultValue = $session->form->process("defaultValue"); + my $fieldType = $session->form->process("fieldType") || "ReadOnly"; + + if ($fieldType =~ m/^otherThing/){ + $defaultValue = $session->form->process("defaultFieldInThing"); + } + + $fieldId = $self->session->form->process("fieldId"); + %properties = ( + fieldId=>$fieldId, + thingId=>$thingId, + label=>$label, + fieldType=>$fieldType, + defaultValue=>$defaultValue, + possibleValues=>$self->session->form->process("possibleValues"), + subtext=>$self->session->form->process("subtext"), + status=>$self->session->form->process("status"), + width=>$self->session->form->process("width"), + height=>$self->session->form->process("height"), + vertical=>$self->session->form->process("vertical"), + extras=>$self->session->form->process("extras"), + display=>$self->session->form->process("display") || 1, + viewScreenTitle=>$self->session->form->process("viewScreenTitle") || 0, + fieldInOtherThingId=>$session->form->process("fieldInOtherThingId") || "", + ); + # Get the field's data type + $dbDataType = $self->_getDbDataType($properties{fieldType}); + + if ($fieldId eq "new") { + $properties{dateCreated} = time(); + $properties{createdBy} = $self->session->user->userId; + $newFieldId = $self->addField(\%properties,0,$dbDataType); + } + else{ + $properties{dateUpdated} = time(); + $properties{updatedBy} = $self->session->user->userId; + # Check if column has to be altered for existing fields. + $self->_updateFieldType($fieldType,$fieldId,$thingId,$self->get('assetId'),$dbDataType); + $newFieldId = $self->setCollateral("Thingy_fields","fieldId",\%properties,1,1,"thingId",$thingId); + } + + if ($properties{fieldType} eq "file"){ + $formElement = ""; + } + else{ + $formElement = $self->getFormElement(\%properties); + } + $listItemHTML = "\n\n\n" + ."\n" + ."\n\n
    ".$label."".$formElement." session->url->page() + ."?func=editField;fieldId=".$newFieldId.";thingId=".$properties{thingId}."','".$newFieldId."')\" value='Edit' type='button'>" + ."session->url->page()."','".$newFieldId + ."','".$properties{thingId}."')\" value='Delete' type='button'>
    "; + + $session->output->print($newFieldId.$listItemHTML); + return "chunked"; +} +#------------------------------------------------------------------- +=head2 www_editThingData ( ) + +Shows a form to edit a things data. + +=cut + +sub www_editThingData { + + my $self = shift; + my $session = $self->session; + my $thingId = shift || $session->form->process('thingId'); + my $thingDataId = shift || $session->form->process('thingDataId') || "new"; + my (%thingData, $fields,%thingProperties,@field_loop,$fieldValue); + my $var = $self->get; + my $url = $self->getUrl; + my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); + my $errors = shift; + $var->{error_loop} = $errors if ($errors); + + %thingProperties = $self->session->db->quickHash("select * from Thingy_things where thingId=".$self->session->db->quote($thingId)); + return $self->session->privilege->insufficient() unless $self->hasPrivileges($thingProperties{groupIdEdit}); + + $var->{canEditThings} = $self->canEdit; + $var->{"addThing_url"} = $session->url->append($url, 'func=editThing;thingId=new'); + $var->{"manage_url"} = $session->url->append($url, 'func=manage'); + + if($self->hasPrivileges($thingProperties{groupIdEdit})){ + if ($thingDataId ne "new"){ + $var->{"delete_url"} = $session->url->append($url, 'func=deleteThingDataConfirm;thingId=' + .$thingId.';thingDataId='.$thingDataId); + } + $var->{"delete_confirm"} = "onclick=\"return confirm('".$i18n->get("delete thing data warning")."')\""; + $var->{"add_url"} = $session->url->append($url,'func=editThingData;thingId='.$thingId.';thingDataId=new'); + $var->{"thing_label"} = $thingProperties{label}; + } + if($self->hasPrivileges($thingProperties{groupIdSearch})){ + $var->{"search_url"} = $session->url->append($url, 'func=search;thingId='.$thingId); + } + + + $var->{"form_start"} = WebGUI::Form::formHeader($self->session,{action=>$self->getUrl}) + .WebGUI::Form::hidden($self->session,{name=>"func",value=>"editThingDataSave"}); + $var->{"form_start"} .= WebGUI::Form::hidden($self->session,{name=>"thingDataId",value=>$thingDataId}); + $var->{"form_start"} .= WebGUI::Form::hidden($self->session,{name=>"thingId",value=>$thingId}); + $var->{editScreenTitle} = $thingProperties{editScreenTitle}; + $var->{editInstructions} = $thingProperties{editInstructions}; + + + if ($thingDataId ne "new"){ + # Get Field Values + %thingData = $session->db->quickHash("select * from Thingy_".$thingId." where thingDataId = +".$session->db->quote($thingDataId)); + } + + $fields = $session->db->read('select * from Thingy_fields where assetId = +'.$session->db->quote($self->get("assetId")).' and thingId = '.$session->db->quote($thingId).' order by +sequenceNumber'); + while (my %field = $fields->hash) { + my $fieldName = 'field_'.$field{fieldId}; + if ($session->form->process("func") eq "editThingDataSave"){ + $fieldValue = $session->form->process($fieldName,$field{fieldType},$field{defaultValue}); + } + else{ + $fieldValue = $thingData{"field_".$field{fieldId}}; + } + $field{value} = $fieldValue || $field{defaultValue}; + my $formElement .= $self->getFormElement(\%field); + + my $hidden = ($field{status} eq "hidden" && !$self->session->var->get("adminOn")); + my $value = $field{value}; + $value = $self->getFieldValue($value,\%field); + + my %fieldProperties = ( + "form" => $formElement, + "name" => "field_".$field{fieldId}, + "value" => $value, + "label" => $field{label}, + "isHidden" => $hidden, + "isVisible" => ($field{status} eq "visible" && !$hidden), + "isRequired" => ($field{status} eq "required" && !$hidden), + "subtext" => $field{subtext}, + ); + push(@field_loop, { map {("field_".$_ => $fieldProperties{$_})} keys(%fieldProperties) }); + } + $var->{field_loop} = \@field_loop; + $var->{"form_submit"} = WebGUI::Form::submit($self->session,{value => $thingProperties{saveButtonLabel}}); + $var->{"form_end"} = WebGUI::Form::formFooter($self->session); + if (WebGUI::Utility::isIn($session->form->process("func"),qw(editThingData editThingDataSave))){ + return $self->session->style->process($self->processTemplate($var,$thingProperties{editTemplateId}),$self->get("styleTemplateId")); + } + else{ + return $self->processTemplate($var,$thingProperties{editTemplateId}); + } +} +#------------------------------------------------------------------- +=head2 www_editThingDataSave ( ) + +Processes and saves data for a Thing. + +=cut + +sub www_editThingDataSave { + + my $self = shift; + my $session = $self->session; + my ($var,$newThingDataId, $fields,%thingProperties,%thingData,@errors,$hadErrors,$otherThingId,$workflowId); + my $thingId = $session->form->process('thingId'); + my $thingDataId = $session->form->process('thingDataId'); + my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); + + %thingProperties = $session->db->quickHash("select * from Thingy_things where +thingId=".$session->db->quote($thingId)); + return $session->privilege->insufficient() unless $self->hasPrivileges($thingProperties{groupIdEdit}); + + %thingData = ( + thingDataId=>$thingDataId, + updatedById=>$session->user->userId, + updatedByName=>$session->user->username, + lastUpDated=>time(), + ); + if ($thingDataId eq "new"){ + $thingData{dateCreated} = time(); + $thingData{createdById} = $session->user->userId; + $thingData{ipAddress} = $session->env->getIp; + } + + $fields = $session->db->read('select * from Thingy_fields where assetId = '.$session->db->quote($self->get("assetId")).' and thingId = '.$session->db->quote($thingId).' order by sequenceNumber'); + while (my $field = $fields->hashRef) { + my $fieldName = 'field_'.$field->{fieldId}; + my $fieldValue; + if ($field->{status} eq "required" || $field->{status} eq "editable"){ + my $fieldType = $field->{fieldType}; + $fieldType = "" if ($fieldType =~ m/^otherThing/x); + $fieldValue = $session->form->process($fieldName,$fieldType,$field->{defaultValue}); + } + if ($field->{status} eq "required" && ($fieldValue =~ /^\s$/x || $fieldValue eq "" || !(defined $fieldValue))) { + push (@errors,{ + "error_message"=>$field->{label}." ".$i18n->get('is required error').".", + }); + $hadErrors = 1; + } + if ($field->{status} eq "hidden") { + $fieldValue = $field->{defaultValue}; + WebGUI::Macro::process($self->session,\$fieldValue); + } + if ($field->{status} eq "visible") { + $fieldValue = $field->{defaultValue}; + #WebGUI::Macro::process($self->session,\$fieldValue); + } + $thingData{$fieldName} = $fieldValue; + } + if ($hadErrors){ + return $self->www_editThingData($thingId,$thingDataId,\@errors); + } + $newThingDataId = $self->setCollateral("Thingy_".$thingId,"thingDataId",\%thingData,0,0); + + # trigger workflow + if($thingDataId eq "new"){ + my ($onAddWorkflowId) = $session->db->quickArray("select onAddWorkflowId from Thingy_things where thingId=?" + ,[$thingId]); + if ($onAddWorkflowId){ + $self->triggerWorkflow($onAddWorkflowId); + } + }else{ + my ($onEditWorkflowId) = $session->db->quickArray("select onEditWorkflowId from Thingy_things where thingId=?" + ,[$thingId]); + if ($onEditWorkflowId){ + $self->triggerWorkflow($onEditWorkflowId); + } + } + + if ($thingProperties{afterSave} eq "searchThisThing") { + return $self->www_search($thingId); + } + elsif ($thingProperties{afterSave} eq "viewLastEdited"){ + return $self->www_viewThingData($thingId,$newThingDataId); + } + elsif ($thingProperties{afterSave} eq "addThing") { + return $self->www_editThingData($thingId,"new"); + } + elsif ($thingProperties{afterSave} =~ m/^searchOther_/x){ + $otherThingId = $thingProperties{afterSave}; + $otherThingId =~ s/^searchOther_//x; + return $self->www_search($otherThingId); + } + elsif ($thingProperties{afterSave} =~ m/^addOther_/x){ + $otherThingId = $thingProperties{afterSave}; + $otherThingId =~ s/^addOther_//x; + return $self->www_editThingData($otherThingId,"new"); + } + # if afterSave is thingy default or in any other case return view() + else { + return $self->view(); + } +} + +#------------------------------------------------------------------- +=head2 www_export ( ) + +Exports search results as csv. + +=cut + +sub www_export { + my $self = shift; + my $session = $self->session; + my ($query,$sth,$out,%thingProperties,$fields,@fields,$fileName,@fieldLabels); + my $thingId = $session->form->process('thingId'); + + %thingProperties = $session->db->quickHash("select * from Thingy_things where thingId=?",[$thingId]); + return $session->privilege->insufficient() unless $self->hasPrivileges($thingProperties{groupIdExport}); + + $fields = $session->db->read('select * from Thingy_fields where assetId =? and thingId = ? order by sequenceNumber', + [$self->get("assetId"),$thingId]); + while (my $field = $fields->hashRef) { + if ($field->{displayInSearch}){ + push(@fields, { + fieldId => $field->{fieldId}, + properties => $field, + }); + push(@fieldLabels,$field->{label}); + } + } + + $query = WebGUI::Cache->new($self->session,"query_".$thingId)->get; + $sth = $session->db->read($query); + + ### Loop through the returned structure and put it through Text::CSV + # Column heads + $out = WebGUI::Text::joinCSV(@fieldLabels); + + # Data lines + while (my $data = $sth->hashRef) { + my @fieldValues; + foreach my $field (@fields){ + my $fieldId = $field->{fieldId}; + # Export date and dateTime fields in an importable format. + my $value = $self->getFieldValue($data->{"field_".$fieldId},$field->{properties},"%y-%m-%d","%y-%m-%d %j:%n:%s"); + push(@fieldValues, $value); + } + $out .= "\n".WebGUI::Text::joinCSV( + @fieldValues + ); + } + + $fileName = "export_".$thingProperties{label}.".csv"; + $self->session->http->setFilename($fileName,"application/octet-stream"); + $self->session->http->sendHeader; + return $out; + +} +#------------------------------------------------------------------- +=head2 www_import ( ) + +Imports data from a .csv file. + +=cut + +sub www_import { + my $self = shift; + my $session = $self->session; + my $dbh = $session->db->dbh; + my ($sql,%thingProperties,$fields,@fields,$fileName,@insertColumns); + my ($handleDuplicates,$newThingDataId); + + my $thingId = $session->form->process('thingId'); + %thingProperties = $session->db->quickHash("select * from Thingy_things where +thingId=".$session->db->quote($thingId)); + return $session->privilege->insufficient() unless $self->hasPrivileges($thingProperties{groupIdImport}); + + $fields = $session->db->read('select label, fieldId, fieldType, fieldInOtherThingId from Thingy_fields ' + .' where assetId = '.$session->db->quote($self->get("assetId")) + .' and thingId = '.$session->db->quote($thingId) + .' order by sequenceNumber'); + while (my $field = $fields->hashRef) { + push(@insertColumns, $field) if ($session->form->process("fileContains_".$field->{fieldId})); + } + + my $error = $self->session->errorHandler; + my $storage = WebGUI::Storage->createTemp($self->session); + $handleDuplicates = $session->form->process("handleDuplicates"); + + $storage->addFileFromFormPost("importFile_file",1); + foreach my $file (sort(@{$storage->getFiles})) { + next unless ($storage->getFileExtension($file) eq "csv"); + + $error->info("Found import file $file"); + open my $importFile,"<",$storage->getPath($file); + my $lineNumber = 0; + my @data = (); + my @lines = <$importFile>; + close $importFile; + + for my $line (@lines){ + if ($lineNumber == 0 && $session->form->process('ignoreFirstLine')){ + $lineNumber++; + $error->info("Skipping first line"); + next; + } + $error->info("Reading line $lineNumber: $line"); + $lineNumber++; + chomp($line); + @data = WebGUI::Text::splitCSV($line); + + # check for duplicates + my $fieldNumber = 0; + my $foundDuplicateId = ""; + my @duplicatesConstraint; + + # Create duplicate constraint + foreach my $insertValue (@data){ + my $fieldId = $insertColumns[$fieldNumber]->{fieldId}; + if ($session->form->process("checkDuplicates_".$fieldId)){ + #$error->info("adding $fieldId to duplicates constraint"); + push(@duplicatesConstraint,"field_".$fieldId." = ".$session->db->quote($insertValue)); + } + $fieldNumber++; + } + + if((scalar @duplicatesConstraint) > 0){ + my $query = "select thingDataId from Thingy_".$thingId." where "; + $query .= join(" and ",@duplicatesConstraint); + $query .= " limit 1"; + ($foundDuplicateId) = $session->db->quickArray($query); + if ($foundDuplicateId){ + $error->info("found duplicate record: ".$foundDuplicateId." for data: ".$line); + } + } + + my %thingData = (); + $fieldNumber = 0; + + # Populate thingData hash + foreach my $fieldValue (@data){ + my $fieldName = "field_".$insertColumns[$fieldNumber]->{fieldId}; + my $fieldType = $insertColumns[$fieldNumber]->{fieldType}; + my $fieldInOtherThingId = $insertColumns[$fieldNumber]->{fieldInOtherThingId}; + # TODO: process dates and otherThing field id's + if ($fieldType eq "date" || $fieldType eq "dateTime"){ + $fieldValue =~ s/\//-/gx; + $fieldValue = $session->datetime->setToEpoch($fieldValue); + } + elsif($fieldType =~ m/^otherThing/x){ + my $otherThingId = $fieldType; + $otherThingId =~ s/^otherThing_(.*)/$1/x; + ($fieldValue) = $self->session->db->quickArray('select thingDataId ' + .' from '.$dbh->quote_identifier('Thingy_'.$otherThingId) + .' where '.$dbh->quote_identifier('field_'.$fieldInOtherThingId).' = ?',[$fieldValue]); + } + $thingData{$fieldName} = $fieldValue; + $fieldNumber++; + } + if ($foundDuplicateId && $handleDuplicates eq "overwrite"){ + $thingData{thingDataId} = $foundDuplicateId; + $error->info("Overwriting, thingDataId = ".$thingData{thingDataId}); + } + elsif ($foundDuplicateId eq ""){ + $thingData{thingDataId} = "new"; + $error->info("Importing new line"); + } + else{ + $error->info("Skipping line"); + next; + } + $thingData{lastUpdated} = time(); + $thingData{updatedByName} = $session->user->username; + $thingData{updatedById} = $session->user->userId; + $self->setCollateral("Thingy_".$thingId,"thingDataId",\%thingData,0,0) if ($thingData{thingDataId}); + } + } + + return $self->www_search($thingId); +} + +#------------------------------------------------------------------- +=head2 www_importForm ( ) + +Shows the import screen. + +=cut + +sub www_importForm { + my $self = shift; + my $session = $self->session; + my $db = $session->db; + my ($i18n,$form,%thingProperties,$fields,$fieldOptions,$output); + my $thingId = $session->form->process('thingId'); + + %thingProperties = $db->quickHash("select * from Thingy_things where thingId=?",[$thingId]); + return $session->privilege->insufficient() unless $self->hasPrivileges($thingProperties{groupIdImport}); + + $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); + + $output = "

    ".$i18n->get("import label")."

    "; + $form = WebGUI::HTMLForm->new($self->session,-action=>$self->getUrl); + $form->hidden( + -name => "thingId", + -value => $thingId + ); + $form->hidden( + -name => "func", + -value => "import" + ); + + $form->file( + -name => "importFile", + -label => $i18n->get("import file label"), + ); + + $form->selectBox( + -name => "handleDuplicates", + -label=> $i18n->get("duplicates label"), + -options=> { + "skip" => $i18n->get("skip label"), + "overwrite" => $i18n->get("overwrite label"), + }, + ); + $form->yesNo( + -name=>"ignoreFirstLine", + -label=>$i18n->get("ignore first line label"), + ); + + $fieldOptions = "" + ."" + ." " + ." " + .""; + + $fields = $db->read('select label, fieldId from Thingy_fields where assetId =? and thingId = ? order by sequenceNumber', + [$self->get("assetId"),$thingId]); + while (my $field = $fields->hashRef) { + $fieldOptions .= ""; + } + $fieldOptions .= "
    ".$i18n->get("file contains label")."".$i18n->get("check duplicates label")."
    ".$field->{label}.""; + $fieldOptions .= WebGUI::Form::checkbox($self->session, { + checked => "", + name => "fileContains_".$field->{fieldId} + }); + $fieldOptions .= ""; + $fieldOptions .= WebGUI::Form::checkbox($self->session, { + checked => "", + name => "checkDuplicates_".$field->{fieldId} + }); + $fieldOptions .= "
    "; + $form->raw($fieldOptions); + $form->submit; + + $output .= $form->print; + return $self->session->style->process($output,$self->get("styleTemplateId")); +} + + +#------------------------------------------------------------------- +=head2 www_manage ( ) + +Shows the screen to manage things in a Thingy. + +=cut + +sub www_manage { + + my $self = shift; + my $session = $self->session; + return $session->privilege->insufficient() unless $self->canEdit; + + my $i18n = WebGUI::International->new($self->session,"Asset_Thingy"); + my ($things, @things_loop); + my $var = $self->get; + my $url = $self->getUrl; + + $var->{canEditThings} = $self->canEdit; + $var->{"addThing_url"} = $session->url->append($url, 'func=editThing;thingId=new'); + + #Get things in this Thingy + $things = $self->session->db->read('select thingId, label, defaultView from Thingy_things ' + .'where assetId =?',[$self->get("assetId")]); + while (my $thing = $things->hashRef) { + my %templateVars = ( + 'thing_id' => $thing->{thingId}, + 'thing_label' => $thing->{label}, + 'thing_deleteUrl' => $session->url->append($url, 'func=deleteThingConfirm;thingId='.$thing->{thingId}), + 'thing_deleteIcon' => $session->icon->delete('func=deleteThingConfirm;thingId='.$thing->{thingId}, + "",$i18n->get('delete thing warning')), + 'thing_editUrl' => $session->url->append($url, 'func=editThing;thingId='.$thing->{thingId}), + 'thing_editIcon' => $session->icon->edit('func=editThing;thingId='.$thing->{thingId}), + 'thing_addUrl' => $session->url->append($url, + 'func=editThingData;thingId='.$thing->{thingId}.';thingDataId=new'), + 'thing_searchUrl' => $session->url->append($url, 'func=search;thingId='.$thing->{thingId}), + ); + # set the url for the view icon to the things default view + my $viewParams; + if ($thing->{defaultView} eq "addThing") { + $viewParams = 'func=editThingData;thingId='.$thing->{thingId}.';thingDataId=new'; + } + else{ + $viewParams = 'func=search;thingId='.$thing->{thingId}; + } + $templateVars{'thing_viewIcon'} = $session->icon->view($viewParams); + push (@things_loop, \%templateVars); + } + + $var->{"things_loop"} = \@things_loop; + + return $self->session->style->process($self->processTemplate($var, $self->get("templateId")),$self->get("styleTemplateId")); +} + +#------------------------------------------------------------------- + +=head2 www_moveFieldConfirm ( ) + +Moves a field up or down in the sequence of fields. + +=cut + +sub www_moveFieldConfirm { + + my $self = shift; + my $session = $self->session; + return $session->privilege->insufficient() unless $self->canEdit; + + my $error = $self->session->errorHandler; + my $direction = $session->form->process('direction'); + my $assetId = $self->get('assetId'); + my $fieldId = $session->form->process('fieldId'); + my $targetFieldId = $session->form->process('targetFieldId'); + + $error->info("moving $fieldId to target $targetFieldId, direction: $direction"); + + my ($thingId,$originalRank) = $session->db->quickArray( + "select thingId, sequenceNumber from Thingy_fields where fieldId = ".$session->db->quote($fieldId)." and assetId = ".$session->db->quote($assetId)); + my ($targetRank) = $session->db->quickArray( + "select sequenceNumber from Thingy_fields where fieldId = ".$session->db->quote($targetFieldId)." and assetId = ".$session->db->quote($assetId)); + + if($targetRank > $originalRank){ + # seq -- for orig seq < seq =< newseq + if ($direction eq "up"){ + $targetRank--; + } + my $sql = "update Thingy_fields set sequenceNumber = sequenceNumber - 1 where sequenceNumber > " + .$originalRank." and sequenceNumber <= ".$targetRank." and assetId = ".$session->db->quote($assetId) + ." and thingId = ".$session->db->quote($thingId); + $session->db->write($sql); + } + else{ + # seq ++ for newseq =< seq < orig seq + if ($direction eq "down") { + $targetRank++; + } + $session->db->write("update Thingy_fields set sequenceNumber = sequenceNumber + 1 where sequenceNumber >= " + .$targetRank." and sequenceNumber < ".$originalRank." and assetId = ".$session->db->quote($assetId)." and thingId = ".$session->db->quote($thingId)); + } + # orig seq = target seq + $self->session->db->write("update Thingy_fields set sequenceNumber = ".$targetRank." where fieldId = ".$self->session->db->quote($fieldId)." and assetId = ".$self->session->db->quote($assetId)." and thingId = ".$self->session->db->quote($thingId)); + + $self->session->output->print("fieldMoved"); + return "chunked"; + +} + +#------------------------------------------------------------------- +=head2 www_search ( ) + +Shows the search screen and performs the search. + +=cut + +sub www_search { + + my $self = shift; + my $thingId = shift || $self->session->form->process('thingId'); + my $session = $self->session; + my $dbh = $session->db->dbh; + my $i18n = WebGUI::International->new($self->session,"Asset_Thingy"); + my ($var,$url,$doSearch,$orderBy); + my ($fields,%thingProperties,@searchFields_loop,@displayInSearchFields_loop,$query,@constraints); + my (@searchResult_loop,$searchResults,@searchResults,@displayInSearchFields,$paginatePage,$currentUrl,$p); + + %thingProperties = $session->db->quickHash("select * from Thingy_things where thingId=".$self->session->db->quote($thingId)); + return $session->privilege->insufficient() unless $self->hasPrivileges($thingProperties{groupIdSearch}); + + $doSearch = $session->form->process("doSearch"); + $orderBy = $session->form->process("orderBy"); + $var = $self->get; + $url = $self->getUrl; + + $var->{canEditThings} = $self->canEdit; + $var->{"addThing_url"} = $session->url->append($url, 'func=editThing;thingId=new'); + $var->{"manage_url"} = $session->url->append($url, 'func=manage'); + + if ($doSearch && $self->hasPrivileges($thingProperties{groupIdExport})){ + $var->{"export_url"} = $session->url->append($url, 'func=export;thingId='.$thingId); + } + if ($self->hasPrivileges($thingProperties{groupIdImport})){ + $var->{"import_url"} = $session->url->append($url, 'func=importForm;thingId='.$thingId); + } + if ($self->hasPrivileges($thingProperties{groupIdEdit})){ + $var->{"add_url"} = $session->url->append($url,'func=editThingData;thingId='.$thingId.';thingDataId=new'); + $var->{"thing_label"} = $thingProperties{label}; + } + $var->{searchScreenTitle} = $thingProperties{searchScreenTitle}; + $var->{searchDescription} = $thingProperties{searchDescription}; + + $currentUrl = $self->getUrl(); + foreach ($self->session->form->param) { + unless ($_ eq "pn" || $_ eq "op" || $_ =~ /identifier/xi || $_ =~ /password/xi || $_ eq "orderBy" || +$self->session->form->process($_) eq "") { + $currentUrl = $self->session->url->append($currentUrl,$self->session->url->escape($_) + .'='.$self->session->url->escape($self->session->form->process($_))); + } + } + + $fields = $session->db->read('select * from Thingy_fields where assetId = +'.$session->db->quote($self->get("assetId")).' and thingId = '.$session->db->quote($thingId).' order by +sequenceNumber'); + while (my $field = $fields->hashRef) { + if ($field->{searchIn}){ + my $searchForm = $self->getFormElement($field); + my $searchTextForm = WebGUI::Form::Text($self->session, { + name=>"field_".$field->{fieldId}, + size=>25, + }); + my $fieldType; + if ($field->{fieldType} =~ m/^otherThing/x){ + $fieldType = "OtherThing"; + } + else{ + $fieldType = ucfirst $field->{fieldType}; + } + push(@searchFields_loop, { + "searchFields_fieldId" => $field->{fieldId}, + "searchFields_label" => $field->{label}, + "searchFields_form" => $searchForm, + "searchFields_textForm" => $searchTextForm, + "searchFields_is".$fieldType => 1, + }); + if ($doSearch){ + my $searchValue = $session->form->process("field_".$field->{fieldId}); + push(@constraints,$dbh->quote_identifier("field_".$field->{fieldId})." like '%".$searchValue."%'") if ($searchValue); + } + } + if ($doSearch){ + if($field->{displayInSearch}){ + my $orderByUrl = $currentUrl.";orderBy=".$field->{fieldId}; + push(@displayInSearchFields_loop, { + "displayInSearchFields_fieldId" => $field->{fieldId}, + "displayInSearchFields_label" => $field->{label}, + "displayInSearchFields_orderByUrl" => $orderByUrl, + }); + push(@displayInSearchFields, { + fieldId => $field->{fieldId}, + properties => $field, + }); + } + } + } + + if ($doSearch){ + $query = "select thingDataId, "; + $query .= join(", ",map {$dbh->quote_identifier('field_'.$_->{fieldId})} @displayInSearchFields); + $query .= " from ".$dbh->quote_identifier("Thingy_".$thingId); + $query .= " where ".join(" and ",@constraints) if (scalar(@constraints) > 0); + if ($orderBy){ + $query .= " order by ".$dbh->quote_identifier("field_".$orderBy); + } + + # store query in cache for thirty minutes + WebGUI::Cache->new($self->session,"query_".$thingId)->set($query,30*60); + + $paginatePage = $self->session->form->param('pn') || 1; + $currentUrl .= ";orderBy=".$orderBy if ($orderBy); + + $p = WebGUI::Paginator->new($self->session,$currentUrl,$thingProperties{thingsPerPage}, undef, $paginatePage); + $p->setDataByQuery($query); + $searchResults = $p->getPageData($paginatePage); + foreach my $searchResult (@$searchResults){ + my (@field_loop); + foreach my $field (@displayInSearchFields){ + my $fieldId = $field->{fieldId}; + my $value = $self->getFieldValue($searchResult->{"field_".$fieldId},$field->{properties}); + push(@field_loop,{ + "field_value" => $value, + "field_id" => $fieldId, + }); + } + my $thingDataId = $searchResult->{thingDataId}; + my %templateVars = ( + "searchResult_id" => $thingDataId, + "searchResult_view_url" => $session->url->append($url, 'func=viewThingData;thingId=' + .$thingId.';thingDataId='.$thingDataId), + "searchResult_field_loop" => \@field_loop, + ); + if ($self->hasPrivileges($thingProperties{groupIdEdit})){ + $templateVars{searchResult_elete_icon} = $session->icon->delete('func=deleteThingDataConfirm;thingId=' + .$thingId.';thingDataId='.$thingDataId,$url,$i18n->get('delete thing data warning')); + $templateVars{searchResult_edit_icon} = $session->icon->edit('func=editThingData;thingId=' + .$thingId.';thingDataId='.$thingDataId,$url); + } + push(@searchResult_loop,\%templateVars); + } + $var->{canEditThingData} = $self->hasPrivileges($thingProperties{groupIdEdit}); + $var->{searchResult_loop} = \@searchResult_loop; + $p->appendTemplateVars($var); + } + + $var->{"form_start"} = WebGUI::Form::formHeader($self->session,{action=>$self->getUrl}) + .WebGUI::Form::hidden($self->session,{name=>"func",value=>"search"}); + $var->{"form_start"} .= WebGUI::Form::hidden($self->session,{name=>"thingId",value=>$thingId}); + $var->{"form_start"} .= WebGUI::Form::hidden($self->session,{name=>"doSearch",value=>1}); + $var->{"form_submit"} = WebGUI::Form::submit($self->session,{value=>$i18n->get("search button label")}); + $var->{"form_end"} = WebGUI::Form::formFooter($self->session); + + $var->{searchFields_loop} = \@searchFields_loop; + $var->{displayInSearchFields_loop} = \@displayInSearchFields_loop; + + if (WebGUI::Utility::isIn($session->form->process("func"),qw(search import editThingDataSave deleteThingDataConfirm))){ + return $session->style->process($self->processTemplate($var,$thingProperties{searchTemplateId}),$self->get("styleTemplateId")); + } + else{ + return $self->processTemplate($var,$thingProperties{searchTemplateId}); + } +} +#------------------------------------------------------------------- +=head2 www_selectDefaultFieldValue ( ) + +Returns a form element to select a field in a thing. + +=cut + +sub www_selectDefaultFieldValue { + + my $self = shift; + my $thingId = $self->session->form->process('thingId'); + my $fieldId = $self->session->form->process('fieldId'); + my $fieldInOtherThingId = $self->session->form->process('fieldInOtherThingId'); + return "" if ($thingId eq "" || $fieldId eq ""); + + my $session = $self->session; + my $dbh = $session->db->dbh; + my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); + + my ($groupIdView) = $session->db->quickArray("select groupIdView from Thingy_things where thingId=?",[$thingId]); + return $session->privilege->insufficient() unless $self->hasPrivileges($groupIdView); + + my $options = $session->db->buildHashRef('select thingDataId, ' + .$dbh->quote_identifier('field_'.$fieldInOtherThingId) + .' from '.$dbh->quote_identifier('Thingy_'.$thingId) + .' where '.$dbh->quote_identifier('field_'.$fieldInOtherThingId).' != ""'); + my ($value) = $session->db->quickArray('select defaultValue from Thingy_fields where fieldId=?',[$fieldId]); + + my $formElement; + if (scalar(keys %$options) > 0){ + $formElement = WebGUI::Form::SelectBox($self->session,{ + name => "defaultFieldInThing", + options => $options, + value => $value, + extras => 'style="width: 200px;"', + }); + } + else{ + $formElement = $i18n->get('no field values message'); + } + my $html .= "\t\n"; + $html .= "\t"; + $html .= ""; + $html .= "\t\n\n"; + $html .= "\t
    "; + $html .= $i18n->get("default value label").""; + $html .= $formElement."
    "; + + $self->session->output->print($html); + return "chunked"; +} + +#------------------------------------------------------------------- +=head2 www_selectFieldInThing ( ) + +Returns a form element to select a field in a thing. + +=cut + +sub www_selectFieldInThing { + + my $self = shift; + my $thingId = $self->session->form->process('thingId'); + my $fieldId = $self->session->form->process('fieldId'); + my $prefix = $self->session->form->process('prefix'); + my $session = $self->session; + my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); + + my ($groupIdView) = $session->db->quickArray("select groupIdView from Thingy_things where thingId=".$self->session->db->quote($thingId)); + return $session->privilege->insufficient() unless $self->hasPrivileges($groupIdView); + + my $fields = $session->db->buildHashRef('select fieldId, label from Thingy_fields' + .' where assetId = ? and thingId = ? and fieldId != ? order by sequenceNumber', + [$self->get("assetId"),$thingId,$fieldId]); + + my ($value) = $session->db->quickArray('select fieldInOtherThingId from Thingy_fields where fieldId = ' + .$session->db->quote($fieldId)); + + my $formElement = WebGUI::Form::SelectBox($self->session,{ + name => "fieldInOtherThingId", + options => $fields, + id => $prefix."_fieldInOtherThing_formId", + value => $value, + extras => 'style="width: 200px;"', + }); + + my $html .= "\t\n"; + $html .= "\t"; + $html .= ""; + $html .= "\t\n\n"; + $html .= "\t
    "; + $html .= $i18n->get("field in other thing label").""; + $html .= $formElement."
    "; + + $self->session->output->print($html); + return "chunked"; +} + +#------------------------------------------------------------------- +=head2 www_viewThingData ( ) + +Shows the view screen of a Thing + +=cut + +sub www_viewThingData { + + my $self = shift; + my $session = $self->session; + my $thingId = shift || $session->form->process('thingId'); + my $thingDataId = shift || $session->form->process('thingDataId'); + my (%thingData, $fields,%thingProperties,@field_loop,@viewScreenTitleFields); + my $var = $self->get; + my $url = $self->getUrl; + my $i18n = WebGUI::International->new($self->session, "Asset_Thingy"); + + %thingProperties = $self->session->db->quickHash("select * from Thingy_things where +thingId=".$self->session->db->quote($thingId)); + return $self->session->privilege->insufficient() unless $self->hasPrivileges($thingProperties{groupIdView}); + + $var->{canEditThings} = $self->canEdit; + $var->{"addThing_url"} = $session->url->append($url, 'func=editThing;thingId=new'); + $var->{"manage_url"} = $session->url->append($url, 'func=manage'); + + if($self->hasPrivileges($thingProperties{groupIdEdit})){ + $var->{"edit_url"} = $session->url->append($url,'func=editThingData;thingId=' + .$thingId.';thingDataId='.$thingDataId); + $var->{"delete_url"} = $session->url->append($url, 'func=deleteThingDataConfirm;thingId=' + .$thingId.';thingDataId='.$thingDataId); + $var->{"add_url"} = $session->url->append($url, 'func=editThingData;thingId='.$thingId.';thingDataId=new'); + $var->{"thing_label"} = $thingProperties{label}; + $var->{"delete_confirm"} = "onclick=\"return confirm('".$i18n->get("delete thing data warning")."')\""; + } + if($self->hasPrivileges($thingProperties{groupIdSearch})){ + $var->{"search_url"} = $session->url->append($url, 'func=search;thingId='.$thingId); + } + + # Get Field Values + %thingData = $session->db->quickHash("select * from Thingy_".$thingId." where thingDataId = " + .$session->db->quote($thingDataId)); + + $fields = $session->db->read('select * from Thingy_fields where assetId = ' + .$session->db->quote($self->get("assetId")).' and thingId = '.$session->db->quote($thingId).' order by +sequenceNumber'); + while (my %field = $fields->hash) { + my $hidden = ($field{status} eq "hidden" && !$self->session->var->get("adminOn")); + + my $originalValue = $thingData{"field_".$field{fieldId}}; + my $value = $self->getFieldValue($originalValue,\%field); + + my $otherThingUrl; + if ($field{fieldType} =~ m/^otherThing/x) { + my $otherThingId = $field{fieldType}; + $otherThingId =~ s/^otherThing_//x; + my ($groupIdView) = $session->db->quickArray("select groupIdView from Thingy_things where thingId +=?",[$otherThingId]); + if($self->hasPrivileges($groupIdView)){ + $otherThingUrl = $session->url->append($url,"func=viewThingData;thingId=$otherThingId;thingDataId=$originalValue"); + } + } + + my %fieldProperties = ( + "id" => $field{fieldId}, + "name" => "field_".$field{fieldId}, + "value" => $value, + "label" => $field{label}, + "isHidden" => $hidden, + "url" => $otherThingUrl, + ); + push(@viewScreenTitleFields,$value) if ($field{viewScreenTitle}); + push(@field_loop, { map {("field_".$_ => $fieldProperties{$_})} keys(%fieldProperties) }); + } + $var->{viewScreenTitle} = join(" ",@viewScreenTitleFields); + $var->{field_loop} = \@field_loop; + return $self->session->style->process($self->processTemplate($var,$thingProperties{viewTemplateId}),$self->get("styleTemplateId")); + +} + +#------------------------------------------------------------------- +# Collateral methods can be removed after Collateral methods in Wobject.pm are updated to quote table/column names. +# + +sub setCollateral { + my $self = shift; + my $table = shift; + my $keyName = shift; + my $properties = shift; + my $useSequence = shift; + my $useAssetId = shift; + my $setName = shift || "assetId"; + my $setValue = shift || $self->get($setName); + my ($key, $seq, $dbkeys, $dbvalues); + my $counter = 0; + my $sql; + if ($properties->{$keyName} eq "new" || $properties->{$keyName} eq "") { + $properties->{$keyName} = $self->session->id->generate(); + $sql = "insert into ".$self->session->db->dbh->quote_identifier($table)." ("; + my $dbkeys = ""; + my $dbvalues = ""; + unless ($useSequence eq "0") { + unless (exists $properties->{sequenceNumber}) { + my ($seq) = $self->session->db->quickArray("select max(sequenceNumber) from $table where +$setName=?",[$setValue]); + $properties->{sequenceNumber} = $seq+1; + } + } + unless ($useAssetId eq "0") { + $properties->{assetId} = $self->get("assetId"); + } + foreach my $key (keys %{$properties}) { + if ($counter++ > 0) { + $dbkeys .= ','; + $dbvalues .= ','; + } + $dbkeys .= $self->session->db->dbh->quote_identifier($key); + $dbvalues .= $self->session->db->quote($properties->{$key}); + } + $sql .= $dbkeys.') values ('.$dbvalues.')'; + $self->updateHistory("added collateral item ".$table." ".$properties->{$keyName}); + } else { + $sql = "update ".$self->session->db->dbh->quote_identifier($table)." set "; + foreach my $key (keys %{$properties}) { + unless ($key eq "sequenceNumber") { + $sql .= ',' if ($counter++ > 0); + $sql .= $self->session->db->dbh->quote_identifier($key)."=".$self->session->db->quote($properties->{$key}); + } + } + $sql .= " where $keyName=".$self->session->db->quote($properties->{$keyName}); + $self->updateHistory("edited collateral item ".$table." ".$properties->{$keyName}); + } + $self->session->db->write($sql); + $self->reorderCollateral($table,$keyName,$setName,$setValue) if ($properties->{sequenceNumber} < 0); + return $properties->{$keyName}; +} + + +sub deleteCollateral { + my $self = shift; + my $table = shift; + my $keyName = shift; + my $keyValue = shift; + $self->session->db->write("delete from ".$self->session->db->dbh->quote_identifier($table) + ." where $keyName=".$self->session->db->quote($keyValue)); + $self->updateHistory("deleted collateral item ".$keyName." ".$keyValue); +} + +1; diff --git a/lib/WebGUI/Help/Asset_Thingy.pm b/lib/WebGUI/Help/Asset_Thingy.pm new file mode 100644 index 000000000..b404c3702 --- /dev/null +++ b/lib/WebGUI/Help/Asset_Thingy.pm @@ -0,0 +1,232 @@ +package WebGUI::Help::Asset_Thingy; + +our $HELP = { + 'thingy template' => { + title => 'thingy template label', + body => '', + fields => [], + isa => [ + { namespace => "Asset_Thingy", + tag => "thingy asset template variables" + }, + { namespace => "Asset_Template", + tag => "template variables" + }, + ], + variables => [ + { 'name' => 'things_loop', + 'variables' => [ + { 'name' => 'thing_editIcon' }, + { 'name' => 'thing_deleteIcon' }, + { 'name' => 'thing_viewIcon' }, + { 'name' => 'thing_label' }, + { 'name' => 'thing_id' }, + { 'name' => 'thing_editUrl' }, + { 'name' => 'thing_deleteUrl' }, + { 'name' => 'thing_searchUrl' }, + { 'name' => 'thing_addUrl' }, + ] + }, + ], + related => [ + { tag => 'edit thing template', + namespace => 'Asset_Thingy' + }, + { tag => 'view thing template', + namespace => 'Asset_Thingy' + }, + { tag => 'search thing template', + namespace => 'Asset_Thingy' + }, + ] + }, + + 'edit thing template' => { + title => 'edit thing template label', + body => '', + fields => [], + isa => [ + { namespace => "Asset_Thingy", + tag => "thingy asset template variables" + }, + { namespace => "Asset_Template", + tag => "template variables" + }, + ], + variables => [ + { 'name' => 'delete_url' }, + { 'name' => 'delete_confirm' }, + { 'name' => 'search_url' }, + { 'name' => 'add_url' }, + { 'name' => 'editScreenTitle' }, + { 'name' => 'editInstructions' }, + { 'name' => 'error_loop', + 'variables' => [ { 'name' => 'error_message' } ] + }, + { 'name' => 'field_loop', + 'variables' => [ + { 'name' => 'field_isHidden' }, + { 'name' => 'field_isRequired' }, + { 'name' => 'field_isDisplayed' }, + { 'name' => 'field_label' }, + { 'name' => 'field_form' }, + { 'name' => 'field_name' }, + { 'name' => 'field_value' }, + { 'name' => 'field_subtext' }, + ] + }, + { 'required' => 1, + 'name' => 'form_start' + }, + { 'required' => 1, + 'name' => 'form_submit' + }, + { 'required' => 1, + 'name' => 'form_end' + } + ], + related => [ + { tag => 'thingy template', + namespace => 'Asset_Thingy' + }, + { tag => 'view thing template', + namespace => 'Asset_Thingy' + }, + { tag => 'search thing template', + namespace => 'Asset_Thingy' + }, + ] + }, + + 'view thing template' => { + title => 'view thing template label', + body => '', + isa => [ + { namespace => "Asset_Thingy", + tag => "thingy asset template variables" + }, + { namespace => "Asset_Template", + tag => "template variables" + }, + ], + fields => [], + variables => [ + { 'name' => 'delete_url' }, + { 'name' => 'delete_confirm' }, + { 'name' => 'search_url' }, + { 'name' => 'add_url' }, + { 'name' => 'edit_url' }, + { 'name' => 'viewScreenTitle' }, + { 'name' => 'field_loop', + 'variables' => [ + { 'name' => 'field_isHidden' }, + { 'name' => 'field_label' }, + { 'name' => 'field_value' }, + { 'name' => 'field_name' }, + { 'name' => 'field_id' }, + { 'name' => 'field_url' }, + ] + } + ], + related => [ + { tag => 'edit thing template', + namespace => 'Asset_Thingy' + }, + { tag => 'search thing template', + namespace => 'Asset_Thingy' + }, + { tag => 'thingy template', + namespace => 'Asset_Thingy' + }, + ] + }, + + 'search thing template' => { + title => 'search thing template label', + body => '', + fields => [], + isa => [ + { namespace => "Asset_Thingy", + tag => "thingy asset template variables" + }, + { namespace => "Asset_Template", + tag => "template variables" + }, + ], + variables => [ + { 'name' => 'add_url' }, + { 'name' => 'import_url' }, + { 'name' => 'export_url' }, + { 'name' => 'searchScreenTitle' }, + { 'name' => 'searchDescription' }, + { 'name' => 'searchFields_loop', + 'variables' => [ + { 'name' => 'searchFields_fieldId' }, + { 'name' => 'searchFields_searchForm' }, + { 'name' => 'searchFields_label' }, + ] + }, + { 'required' => 1, + 'name' => 'form_start' + }, + { 'required' => 1, + 'name' => 'form_submit' + }, + { 'required' => 1, + 'name' => 'form_end' + }, + { 'name' => 'displayInSearchFields_loop', + 'variables' => [ + { 'name' => 'displayInSearchFields_fieldId' }, + { 'name' => 'displayInSearchFields_orderByUrl' }, + { 'name' => 'displayInSearchFields_label' }, + ] + }, + { 'name' => 'searchResult_loop', + 'variables' => [ + { 'name' => 'searchResult_id' }, + { 'name' => 'searchResult_view_url' }, + { 'name' => 'searchResult_edit_icon' }, + { 'name' => 'searchResult_delete_icon' }, + { 'name' => 'searchResult_field_loop', + 'variables' => [ + { 'name' => 'field_id' }, + { 'name' => 'field_value' }, + ] + }, + ] + }, + ], + related => [ + { tag => 'edit thing template', + namespace => 'Asset_Thingy' + }, + { tag => 'view thing template', + namespace => 'Asset_Thingy' + }, + { tag => 'thingy template', + namespace => 'Asset_Thingy' + }, + ] + }, + + 'thingy asset template variables' => { + private => 1, + title => 'data form asset template variables title', + body => 'data form asset template variables body', + isa => [ + { namespace => "Asset_Wobject", + tag => "wobject template variables" + }, + ], + fields => [], + variables => [ + { 'name' => 'canEditThings' }, + { 'name' => 'manage_url' }, + { 'name' => 'addThing_url' }, + ], + related => [] + }, +}; + +1; diff --git a/lib/WebGUI/i18n/English/Asset_Thingy.pm b/lib/WebGUI/i18n/English/Asset_Thingy.pm new file mode 100644 index 000000000..618355dc4 --- /dev/null +++ b/lib/WebGUI/i18n/English/Asset_Thingy.pm @@ -0,0 +1,877 @@ +package WebGUI::i18n::English::Asset_Thingy; + +our $I18N = { + + 'cache timeout' => { + message => q|Cache Timeout|, + lastUpdated => 0 + }, + + 'cache timeout help' => { + message => q|Since all users will see this asset the same way, we can cache it for long periods of time to increase performance. How long should we cache it?

    UI Level: 8|, + lastUpdated => 0 + }, + + 'assetName' => { + message => q|Thingy|, + lastUpdated => 1128830080, + context => 'Default name of all snippets' + }, + + 'template_label' => { + message => q|Thingy List Template|, + lastUpdated => 1121703035, + }, + + 'add thing label' => { + message => q|Add Thing|, + lastUpdated => 1104630516, + }, + + 'default thing label' => { + message => q|Default Thing|, + lastUpdated => 1104630516, + }, + + 'manage things label' => { + message => q|Manage Things|, + lastUpdated => 1104630516, + }, + + 'delete thing warning' => { + message => q|Are you sure you want to delete this Thing and all data in it? This is not versioned and can not be undone.|, + lastUpdated => 1104630516, + }, + + 'delete thing data warning' => { + message => q|Are you sure you want to delete this thing? This is not versioned and cannot be undone.|, + lastUpdated => 1104630516, + }, + + 'fields tab label' => { + message => q|Fields|, + lastUpdated => 1104630516, + }, + + 'edit screen tab label' => { + message => q|Edit Screen|, + lastUpdated => 1104630516, + }, + + 'view screen tab label' => { + message => q|View Screen|, + lastUpdated => 1104630516, + }, + + 'search screen tab label' => { + message => q|Search Screen|, + lastUpdated => 1104630516, + }, + + 'edit thing title' => { + message => q|Edit/Add Thing|, + lastUpdated => 1104630516, + }, + + 'thing name label' => { + message => q|Thing Name|, + lastUpdated => 1104630516, + }, + + 'fields label' => { + message => q|Fields|, + lastUpdated => 1104630516, + }, + + 'add field label' => { + message => q|Add Field|, + lastUpdated => 1104630516, + }, + + 'edit screen title label' => { + message => q|Edit screen title|, + lastUpdated => 1104630516, + }, + + 'edit screen title description' => { + message => q|The title of the edit screen|, + lastUpdated => 1104630516, + }, + + 'edit instructions label' => { + message => q|Instructions|, + lastUpdated => 1104630516, + }, + + 'edit instructions description' => { + message => q|Instructions on the edit screen about adding or editing a thing.|, + lastUpdated => 1104630516, + }, + + 'who can add label' => { + message => q|Who can add?|, + lastUpdated => 1104630516, + }, + + 'who can add description' => { + message => q|The group that can add this thing.|, + lastUpdated => 1104630516, + }, + + 'who can edit label' => { + message => q|Who can edit?|, + lastUpdated => 1104630516, + }, + + 'who can edit description' => { + message => q|The group that can edit this thing.|, + lastUpdated => 1104630516, + }, + + 'save button label label' => { + message => q|Save Button Label|, + lastUpdated => 1104630516, + }, + + 'default save button label' => { + message => q|Save|, + lastUpdated => 1104630516, + }, + + 'save button label description' => { + message => q|The label of the save button on the edit sceen.|, + lastUpdated => 1104630516, + }, + + 'after save label' => { + message => q|After Save|, + lastUpdated => 1104630516, + }, + + 'search this thing label' => { + message => q|Search this Thing|, + lastUpdated => 1104630516, + }, + + 'view last edited label' => { + message => q|View Last Edited/Added|, + lastUpdated => 1104630516, + }, + + 'search other thing label' => { + message => q|Search Other Thing: |, + lastUpdated => 1104630516, + }, + + 'add other thing label' => { + message => q|Add Other Thing: |, + lastUpdated => 1104630516, + }, + + 'view thingy default label' => { + message => q|View Thingy Default|, + lastUpdated => 1104630516, + }, + + + 'after save description' => { + message => q|The screen that is displayed after saving this thing|, + lastUpdated => 1104630516, + }, + + 'edit template label' => { + message => q|Edit Template|, + lastUpdated => 1104630516, + }, + + 'edit template description' => { + message => q|edit template is used to display the view screen of this thing.|, + lastUpdated => 1104630516, + }, + + 'on add workflow label' => { + message => q|On Add|, + lastUpdated => 1104630516, + }, + + 'on add workflow description' => { + message => q|Workflow that is triggered after adding this thing|, + lastUpdated => 1104630516, + }, + + 'on edit workflow label' => { + message => q|On Edit|, + lastUpdated => 1104630516, + }, + + 'on edit workflow description' => { + message => q|Workflow that is triggered after editing this thing|, + lastUpdated => 1104630516, + }, + + 'on delete workflow label' => { + message => q|On Delete|, + lastUpdated => 1104630516, + }, + + 'on delete workflow description' => { + message => q|Workflow that is triggered after deleting this thing|, + lastUpdated => 1104630516, + }, + + 'who can view label' => { + message => q|Who can view?|, + lastUpdated => 1104630516, + }, + + 'who can view description' => { + message => q|The group that can view this thing.|, + lastUpdated => 1104630516, + }, + + 'view template label' => { + message => q|View Template|, + lastUpdated => 1104630516, + }, + + 'view template description' => { + message => q|This template is used to display the view screen of this thing.|, + lastUpdated => 1104630516, + }, + + 'search thing label' => { + message => q|Search|, + lastUpdated => 1104630516, + }, + + 'default view label' => { + message => q|Default View|, + lastUpdated => 1104630516, + }, + + 'default view description' => { + message => q|The default screen for this thing. This can be either the search screen or the add screen.|, + lastUpdated => 1104630516, + }, + + 'display label' => { + message => q|Display|, + lastUpdated => 1104630516, + }, + + 'view screen title label' => { + message => q|View Screen Title|, + lastUpdated => 1104630516, + }, + + 'search screen title label' => { + message => q|Search Screen Title|, + lastUpdated => 1104630516, + }, + + 'search screen title description' => { + message => q|The title of the search screen|, + lastUpdated => 1104630516, + }, + + 'search descrpiption label' => { + message => q|Description|, + lastUpdated => 1104630516, + }, + + 'search descrpiption description' => { + message => q|Description of the search screen.|, + lastUpdated => 1104630516, + }, + + 'who can search label' => { + message => q|Who can search?|, + lastUpdated => 1104630516, + }, + + 'who can search description' => { + message => q|The group that can search this thing.|, + lastUpdated => 1104630516, + }, + + 'who can import label' => { + message => q|Who can import?|, + lastUpdated => 1104630516, + }, + + 'who can import description' => { + message => q|The group that can import data into this thing.|, + lastUpdated => 1104630516, + }, + + 'who can export label' => { + message => q|Who can export?|, + lastUpdated => 1104630516, + }, + + 'who can export description' => { + message => q|The group that can export this things data.|, + lastUpdated => 1104630516, + }, + + 'search button label' => { + message => q|Search|, + lastUpdated => 1104630516, + }, + + 'search template label' => { + message => q|Search Template|, + lastUpdated => 1104630516, + }, + + 'search template description' => { + message => q|This template is used to display the search screen of this thing.|, + lastUpdated => 1104630516, + }, + + 'things per page label' => { + message => q|Things Per Page|, + lastUpdated => 1104630516, + }, + + 'things per page description' => { + message => q|The number of things that the search screen displays per page.|, + lastUpdated => 1104630516, + }, + + 'search in label' => { + message => q|Search|, + lastUpdated => 1104630516, + }, + + 'sort by label' => { + message => q|Sort By|, + lastUpdated => 1104630516, + }, + + 'export label' => { + message => q|Export|, + lastUpdated => 1104630516, + }, + + 'import label' => { + message => q|Import|, + lastUpdated => 1104630516, + }, + + 'import file label' => { + message => q|Choose a file to import|, + lastUpdated => 1104630516, + }, + + 'duplicates label' => { + message => q|What about duplicates?|, + lastUpdated => 1104630516, + }, + + 'ignore first line label' => { + message => q|Ignore first line?|, + lastUpdated => 1104630516, + }, + + 'skip label' => { + message => q|Skip|, + lastUpdated => 1104630516, + }, + + 'overwrite label' => { + message => q|Overwrite|, + lastUpdated => 1104630516, + }, + + 'file contains label' => { + message => q|File Contains|, + lastUpdated => 1104630516, + }, + + 'check duplicates label' => { + message => q|Check Duplicates|, + lastUpdated => 1104630516, + }, + + 'field label label' => { + message => q|Label|, + lastUpdated => 1031514049 + }, + + 'field label description' => { + message => q|The label for this field.|, + lastUpdated => 1119156590, + }, + + 'field type label' => { + message => q|Field Type|, + lastUpdated => 1031514049 + }, + + 'field type description' => { + message => q|Choose the type of form element for this field. This is also used to validate any input that the user may supply.|, + lastUpdated => 1119156590, + }, + + 'default value label' => { + message => q|Default Value|, + lastUpdated => 1031514049 + }, + + 'default value description' => { + message => q|Enter the default value (if any) for the field. For Yes/No fields, enter "yes" to select "Yes" and "no" to select "No".|, + lastUpdated => 1119156590, + }, + + 'subtext label' => { + message => q|Subtext|, + lastUpdated => 1031514049 + }, + + 'subtext description' => { + message => q|An extension of the label, this is additional information such as a description of what should go in the field or optional instructions for the field.|, + lastUpdated => 1133811301, + }, + + 'fieldstatus hidden label' => { + message => q|Hidden|, + lastUpdated => 1031514049 + }, + 'fieldstatus visible label' => { + message => q|Visible|, + lastUpdated => 1031514049 + }, + 'fieldstatus editable label' => { + message => q|Editable|, + lastUpdated => 1031514049 + }, + 'fieldstatus required label' => { + message => q|Required|, + lastUpdated => 1031514049 + }, + + + 'field status label' => { + message => q|Status|, + lastUpdated => 1031514049 + }, + + 'field status description' => { + message => q|Hidden fields will not be visible to the user. Visible fields can be seen by the user but not modified. Editable fields can be filled in by the user. Required fields must be filled in by the user. If you choose Hidden or Visible, be sure to fill in a Default Value.|, + lastUpdated => 1119156590, + }, + + 'width label' => { + message => q|Width|, + lastUpdated => 1104630516, + }, + + 'width description' => { + message => q|Set the width of textareas and HTMLareas in pixels.|, + lastUpdated => 1104630516, + }, + + 'size label' => { + message => q|Size|, + lastUpdated => 1104630516, + }, + + 'size description' => { + message => q|Set the size(width) of most fields in characters.|, + lastUpdated => 1104630516, + }, + + 'height label' => { + message => q|Height|, + lastUpdated => 1104630516, + }, + + 'height description' => { + message => q|Set the height of this field in pixels. Only used on Textareas and HTMLAreas.|, + lastUpdated => 1153876588, + }, + + 'height subtext' => { + message => q|Optional for text area and HTML area.|, + lastUpdated => 1104630516, + }, + + 'vertical label' => { + message => q|Vertical|, + lastUpdated => 1104630516, + }, + + 'vertical description' => { + message => q|This property controls whether radio buttons and checklists are laid out horizontally or +vertically.|, + lastUpdated => 1104630516, + }, + + 'extras label' => { + message => q|Extras|, + lastUpdated => 1104630516, + }, + + 'extras description' => { + message => q|Here you can enter additional tag properties for the field tag. For instance +'class="myClass"'.|, + lastUpdated => 1104630516, + }, + + 'possible values label' => { + message => q|Possible values|, + lastUpdated => 1104630516, + }, + + 'possible values description' => { + message => q|This field is used for the list types (like Checkbox List and Select List). Enter the values +you wish to appear, one per line.|, + lastUpdated => 1104630516, + }, + + 'possible values subtext' => { + message => q|One per line.|, + lastUpdated => 1104630516, + }, + + 'field in other thing label' => { + message => q|Field In Other Thing|, + lastUpdated => 1104630516, + }, + + 'edit label' => { + message => q|Edit|, + lastUpdated => 1104630516, + }, + + 'delete label' => { + message => q|Delete|, + lastUpdated => 1104630516, + }, + + 'add label' => { + message => q|Add|, + lastUpdated => 1104630516, + }, + + 'search label' => { + message => q|Search|, + lastUpdated => 1104630516, + }, + + 'is required error' => { + message => q| is required|, + lastUpdated => 1104630516, + }, + + 'thingy template label' => { + message => q|Thingy Template|, + lastUpdated => 1104630516, + }, + + 'view thing template label' => { + message => q|Thingy View Thing Template|, + lastUpdated => 1104630516, + }, + + 'edit thing template label' => { + message => q|Thingy Edit Thing Template|, + lastUpdated => 1104630516, + }, + + 'search thing template label' => { + message => q|Thingy Search Thing Template|, + lastUpdated => 1104630516, + }, + + 'canEditThings' => { + message => q|Is true if the current user can view the Things that are defined for this Thingy Asset|, + lastUpdated => 1104630516, + }, + + 'things_loop' => { + message => q|A loop containing the Things that are defined for this Thingy Asset, with links to management +functions for those Things|, + lastUpdated => 1104630516, + }, + + 'thing_editIcon' => { + message => q|An icon with a link to the edit screen for this Thing|, + lastUpdated => 1104630516, + }, + + 'thing_editUrl' => { + message => q|A link to the edit screen for this Thing|, + lastUpdated => 1104630516, + }, + + 'thing_viewIcon' => { + message => q|An icon with a link to default screen for this Thing|, + lastUpdated => 1104630516, + }, + + 'thing_searchUrl' => { + message => q|A link to the search screen for this Thing|, + lastUpdated => 1104630516, + }, + + 'thing_addUrl' => { + message => q|A link to the add screen for this Thing|, + lastUpdated => 1104630516, + }, + + 'thing_deleteIcon' => { + message => q|An icon with a link to delete this Thing|, + lastUpdated => 1104630516, + }, + + 'thing_deleteUrl' => { + message => q|A link to delete this Thing|, + lastUpdated => 1104630516, + }, + + 'thing_label' => { + message => q|The label for this Thing|, + lastUpdated => 1104630516, + }, + + 'thing_id' => { + message => q|The id of this Thing|, + lastUpdated => 1104630516, + }, + + 'manage_url' => { + message => q|This Url will lead to a screen to manage the Things in this Thingy Asset.|, + lastUpdated => 1104630516, + }, + + 'addThing_url' => { + message => q|This Url leads to the screen to add a new Thing to this Thingy Asset.|, + lastUpdated => 1104630516, + }, + + 'delete_url' => { + message => q|The Url to delete the current thing|, + lastUpdated => 1104630516, + }, + + 'delete_confirm' => { + message => q|This contains an onclick property for the delete link that adds a javascript confirmation|, + lastUpdated => 1104630516, + }, + + 'search_url' => { + message => q|Url that leads to the search screen|, + lastUpdated => 1104630516, + }, + + 'add_url' => { + message => q|Url to the add screen for this thing|, + lastUpdated => 1104630516, + }, + + 'editScreenTitle' => { + message => q|The title for the edit screen|, + lastUpdated => 1104630516, + }, + + 'editInstructions' => { + message => q|Instructions about editing this thing|, + lastUpdated => 1104630516, + }, + + 'error_loop' => { + message => q|A loop containing error information, for instance if someone doesn't fill out a required +field.|, + lastUpdated => 1104630516, + }, + + 'error_message' => { + message => q|An error message indicating what the user might have done wrong.|, + lastUpdated => 1104630516, + }, + + 'field_loop' => { + message => q|A loop containing the visible fields for this thing|, + lastUpdated => 1104630516, + }, + + 'field_isHidden' => { + message => q|A conditional indicating whether this field is supposed to be hidden.|, + lastUpdated => 1104630516, + }, + + 'field_isRequired' => { + message => q|A conditional indicating whether this field is required.|, + lastUpdated => 1104630516, + }, + + 'field_isDisplayed' => { + message => q|A conditional indicating whether this field is supposed to be displayed.|, + lastUpdated => 1104630516, + }, + + 'field_form' => { + message => q|The form element for this field.|, + lastUpdated => 1104630516, + }, + + 'field_name' => { + message => q|The name of the form element for this field|, + lastUpdated => 1104630516, + }, + + 'field_label' => { + message => q|The label of this field|, + lastUpdated => 1104630516, + }, + + 'field_url' => { + message => q|An optional url that this field should link to, used i.e. for fields in other things.|, + lastUpdated => 1104630516, + }, + + 'field_value' => { + message => q|The value of this field|, + lastUpdated => 1104630516, + }, + + 'field_subtext' => { + message => q|A description of the field so that users know what to put in the field.|, + lastUpdated => 1104630516, + }, + + 'form_start' => { + message => q|The start tag of the form|, + lastUpdated => 1104630516, + }, + + 'form_submit' => { + message => q|A form button to submit the form data.|, + lastUpdated => 1104630516, + }, + + 'form_end' => { + message => q|The end of the form|, + lastUpdated => 1104630516, + }, + + 'edit_url' => { + message => q|Url to the current things edit screen.|, + lastUpdated => 1104630516, + }, + + 'viewScreenTitle' => { + message => q|The title for the view screen|, + lastUpdated => 1104630516, + }, + + 'import_url' => { + message => q|Url to import data into this Thing from a csv file|, + lastUpdated => 1104630516, + }, + + 'export_url' => { + message => q|Url to export the data in a search result into a csv file. This is only available after a +search has been done.|, + lastUpdated => 1104630516, + }, + + 'searchScreenTitle' => { + message => q|The title of the search screen|, + lastUpdated => 1104630516, + }, + + 'searchDescription' => { + message => q|A description of the search screen.|, + lastUpdated => 1104630516, + }, + + 'searchFields_loop' => { + message => q|A loop that contains the fields that are searchable|, + lastUpdated => 1104630516, + }, + + 'searchFields_label' => { + message => q|The label of a searchable field.|, + lastUpdated => 1104630516, + }, + + 'searchFields_fieldId' => { + message => q|The fieldId of a searchable field.|, + lastUpdated => 1104630516, + }, + + 'searchFields_form' => { + message => q|The form element to search this field.|, + lastUpdated => 1104630516, + }, + + 'displayInSearchFields_loop' => { + message => q|A loop containing the fields that are displayed in the search results.|, + lastUpdated => 1104630516, + }, + + 'displayInSearchFields_orderByUrl' => { + message => q|Url to order the search results by this field.|, + lastUpdated => 1104630516, + }, + + 'displayInSearchFields_label' => { + message => q|The label of this field.|, + lastUpdated => 1104630516, + }, + + 'displayInSearchFields_fieldId' => { + message => q|The fieldId of this field.|, + lastUpdated => 1104630516, + }, + + 'searchResult_loop' => { + message => q|A loop containting the search results.|, + lastUpdated => 1104630516, + }, + + 'searchResult_id' => { + message => q|The id of a search result.|, + lastUpdated => 1104630516, + }, + + 'searchResult_view_url' => { + message => q|Url to the view screen of this search result|, + lastUpdated => 1104630516, + }, + + 'searchResult_edit_icon' => { + message => q|Edit icon that links to the edit screen of this search result.|, + lastUpdated => 1104630516, + }, + + 'searchResult_delete_icon' => { + message => q|Delete icon to delete this search result.|, + lastUpdated => 1104630516, + }, + + 'searchResult_field_loop' => { + message => q|A loop containing the fields that are to be displayed for this search result.|, + lastUpdated => 1104630516, + }, + + 'field_id' => { + message => q|The id of this field.|, + lastUpdated => 1104630516, + }, + + 'no field values message' => { + message => q|Field does not have any values.|, + lastUpdated => 1104630516, + }, + + '' => { + message => q||, + lastUpdated => 1104630516, + }, +}; + +1; diff --git a/t/Asset/Wobject/Thingy.t b/t/Asset/Wobject/Thingy.t new file mode 100644 index 000000000..e69690b71 --- /dev/null +++ b/t/Asset/Wobject/Thingy.t @@ -0,0 +1,115 @@ +#------------------------------------------------------------------- +# 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 FindBin; +use strict; +use lib "$FindBin::Bin/../../lib"; + +##The goal of this test is to test the creation of Thingy Wobjects. + +use WebGUI::Test; +use WebGUI::Session; +use WebGUI::PseudoRequest; +use Test::More tests => 7; # increment this value for each test you create +use WebGUI::Asset::Wobject::Thingy; + +my $session = WebGUI::Test->session; + +# Do our work in the import node +my $node = WebGUI::Asset->getImportNode($session); + +my $versionTag = WebGUI::VersionTag->getWorking($session); +$versionTag->set({name=>"Thingy Test"}); +my $thingy = $node->addChild({className=>'WebGUI::Asset::Wobject::Thingy'}); + +# Test for a sane object type +isa_ok($thingy, 'WebGUI::Asset::Wobject::Thingy'); + +# Test to see if we can set new values +my $newThingySettings = { + templateId=>'testingtestingtesting1', + #searchRoot=>'testingtestingtesting2', + #classLimiter=>'WebGUI::Asset::Wobject::Article', +}; +$thingy->update($newThingySettings); + +foreach my $newSetting (keys %{$newThingySettings}) { + is ($thingy->get($newSetting), $newThingySettings->{$newSetting}, "updated $newSetting is ".$newThingySettings->{$newSetting}); +} + +# Test adding a new Thing +my $i18n = WebGUI::International->new($session, "Asset_Thingy"); +my $groupIdEdit = $thingy->get("groupIdEdit"); +my %thingProperties = ( + thingId=>"new", + label=>$i18n->get('assetName'), + editScreenTitle=>$i18n->get('edit screen title label'), + groupIdAdd=>$groupIdEdit, + groupIdEdit=>$groupIdEdit, + saveButtonLabel=>$i18n->get('default save button label'), + afterSave=>'searchThisThing', + editTemplateId=>"ThingyTmpl000000000003", + groupIdView=>$groupIdEdit, + viewTemplateId=>"ThingyTmpl000000000002", + defaultView=>'searchThing', + searchScreenTitle=>$i18n->get('search screen title label'), + groupIdSearch=>$groupIdEdit, + groupIdExport=>$groupIdEdit, + groupIdImport=>$groupIdEdit, + searchTemplateId=>"ThingyTmpl000000000004", + thingsPerPage=>25, +); +my $thingId = $thingy->addThing(\%thingProperties,0); + +my $isValidId = $session->id->valid($thingId); + +is($isValidId,1,"addThing returned a valid id: ".$thingId); + +my $thingTableName = "Thingy_".$thingId; + +my ($thingTableNameCheck) = $session->db->quickArray("show tables like ".$session->db->quote($thingTableName)); + +is($thingTableNameCheck,$thingTableName,"An empty table: ".$thingTableName." for the new thing exists."); + +my %fieldProperties = ( + thingId=>$thingId, + fieldId=>"new", + label=>$i18n->get('assetName')." field", + dateCreated=>time(), + fieldType=>"textarea", + status=>"editable", +); + +my $fieldId = $thingy->addField(\%fieldProperties,0); + +$isValidId = $session->id->valid($fieldId); + +is($isValidId,1,"Adding a textarea field: addField returned a valid id: ".$fieldId); + +my ($fieldLabel, $columnType, $Null, $Key, $Default, $Extra) = $session->db->quickArray("show columns from " + .$session->db->dbh->quote_identifier($thingTableName) + ." like ".$session->db->quote("Field_".$fieldId)); + +is($fieldLabel,"field_".$fieldId,"A column for the new field Field_$fieldId exists."); +is($columnType,"longtext","The columns is the right type"); + +=cut +my $request = WebGUI::PseudoRequest->new(); +$session->{_request} = $request; + +$session->request->uri($thingy->get("url")); + +$request->setup_body({ param1 => 'value1' }); +=cut +END { + # Clean up after thy self + $versionTag->rollback(); +} + diff --git a/www/extras/wobject/Thingy/thingy.css b/www/extras/wobject/Thingy/thingy.css new file mode 100644 index 000000000..4fddbbe98 --- /dev/null +++ b/www/extras/wobject/Thingy/thingy.css @@ -0,0 +1,36 @@ +/*div.workarea { padding:10px; float:left }*/ + +ul.draglist { + /*position: relative;*/ + width: 600px; + background: #f7f7f7; + /*border: 1px solid gray;*/ + list-style: none; + margin:0; + padding:0; +} + +ul.draglist li { + margin: 1px; + cursor: move; +} + +ul.draglist_alt li { + margin: 1px; + cursor: move; +} + + +li.list1 { + /*background-color: #D1E6EC;*/ + border:1px solid #7EA6B2; +} + +#dialog1{ + height: 400px; +} + +#dialog2{ + height: 400px; +} + diff --git a/www/extras/wobject/Thingy/thingy.js b/www/extras/wobject/Thingy/thingy.js new file mode 100644 index 000000000..79e3faf47 --- /dev/null +++ b/www/extras/wobject/Thingy/thingy.js @@ -0,0 +1,523 @@ +function initOptionalFields(prefix,fieldId) { + + var fieldInThing_module_rendered; + + var height_module = new YAHOO.widget.Module(prefix + "_height_module", { visible: false }); + height_module.render(); + + var width_module = new YAHOO.widget.Module(prefix + "_width_module", { visible: false }); + width_module.render(); + + var size_module = new YAHOO.widget.Module(prefix + "_size_module", { visible: false }); + size_module.render(); + + var vertical_module = new YAHOO.widget.Module(prefix + "_vertical_module", { visible: false }); + vertical_module.render(); + + var values_module = new YAHOO.widget.Module(prefix + "_values_module", { visible: false }); + values_module.render(); + + var defaultValue_module = new YAHOO.widget.Module(prefix + "_defaultValue_module", { visible: false }); + defaultValue_module.render(); + + var fieldInThing_module = new YAHOO.widget.Module(prefix + "_fieldInThing_module", { visible: false }); + fieldInThing_module.render(); + + var defaultFieldInThing_module = new YAHOO.widget.Module(prefix + "_defaultFieldInThing_module", { visible: false }); + defaultFieldInThing_module.render(); + + YAHOO.util.Event.onContentReady(prefix+"_fieldType_formId", checkFieldType); + YAHOO.util.Event.addListener(prefix+"_fieldType_formId", "change", checkFieldType); + + function checkFieldType(){ + + if (this.value == "HTMLArea" || this.value == "textarea"){ + height_module.show(); + width_module.show() + }else{ + height_module.hide(); + width_module.hide() + } + if (this.value == "radioList" || this.value == "checkList"){ + vertical_module.show(); + }else{ + vertical_module.hide(); + } + if (this.value == "HTMLArea" || this.value == "textarea" || this.value == "radioList" || this.value == "checkList" || this.value == "zipcode"){ + size_module.hide() + }else{ + size_module.show(); + } + if (this.value == "selectList" || this.value == "selectBox" || this.value == "radioList" || this.value == "checkList"){ + values_module.show(); + }else{ + values_module.hide(); + } + var valueStart = this.value.slice(0,10); + + if(valueStart == "otherThing" || this.value == "file"){ + defaultValue_module.hide(); + }else{ + defaultValue_module.show(); + } + if(valueStart == "otherThing"){ + var thingId = this.value.slice(11); + + var getFieldValues = function() { + var fieldInOtherThingId = this.value; + var url = location.pathname + "?func=selectDefaultFieldValue;thingId=" + thingId + ";fieldInOtherThingId=" + fieldInOtherThingId + ";fieldId=" + fieldId; + + var handleSuccess = function(o){ + defaultFieldInThing_module.setBody(o.responseText); + defaultFieldInThing_module.show(); + }; + + var handleFailure = function(o) { + alert("Get field values failed: " + o.status); + }; + + var callback = + { + success:handleSuccess, + failure:handleFailure + }; + + var request = YAHOO.util.Connect.asyncRequest('GET', url, callback); + + }; + + if (fieldInThing_module_rendered == thingId){ + fieldInThing_module.show(); + }else{ + var url = location.pathname + "?func=selectFieldInThing;thingId=" + thingId + ";prefix=" +prefix + ";fieldId=" + fieldId; + var handleSuccess = function(o){ + fieldInThing_module.setBody(o.responseText); + fieldInThing_module.show(); + fieldInThing_module_rendered = thingId; + YAHOO.util.Event.onContentReady(prefix+"_fieldInOtherThing_formId",getFieldValues); + YAHOO.util.Event.addListener(prefix+"_fieldInOtherThing_formId","change", getFieldValues); + + }; + + var handleFailure = function(o) { + alert("Get fields in thing failed: " + o.status); + }; + + var callback = + { + success:handleSuccess, + failure:handleFailure + }; + + var request = YAHOO.util.Connect.asyncRequest('GET', url, callback); + } + }else{ + fieldInThing_module.hide(); + defaultFieldInThing_module.hide(); + } + } +} + +function editListItem(url,fieldId) { + + var handleGetFormSuccess = function(o){ + + var handleSuccess = function(o) { + var response = o.responseText; + var listItemId = response.slice(0,22); + var newInnerHTML = response.slice(22); + var label = editFieldDialog.getData().label; + + var li = new YAHOO.util.Element(listItemId); + li.set('innerHTML',newInnerHTML); + var search_label = new YAHOO.util.Element("search_label_"+listItemId); + search_label.set('innerHTML',label); + var view_label = new YAHOO.util.Element("view_label_"+listItemId); + view_label.set('innerHTML',label); + }; + + var handleFailure = function(o) { + alert("Submission failed: " + o.status); + }; + + var handleSubmit = function() { + this.submit(); + }; + var handleCancel = function() { + this.cancel(); + this.destroy(); + }; + function optionalFields() { + initOptionalFields("edit_"+fieldId+"_Dialog",fieldId); + } + editFieldDialog = new YAHOO.widget.Dialog("dialog2", { width:"460px", visible:false, draggable:true, close:true, fixedcenter:true, zIndex:11001, + buttons : [ { text:"Submit", handler:handleSubmit, isDefault:true }, + { text:"Cancel", handler:handleCancel } ] + } ); + + editFieldDialog.setHeader("Edit Field"); + editFieldDialog.setBody(o.responseText); + editFieldDialog.render(document.body); + editFieldDialog.callback = { success: handleSuccess, failure: handleFailure }; + editFieldDialog.show(); + YAHOO.util.Event.onContentReady("dialog2", optionalFields); + + + }; + + var handleGetFormFailure = function(o) { + alert("Getting edit field dialog failed: " + o.status); + }; + + var callbackGetForm = + { + success:handleGetFormSuccess, + failure:handleGetFormFailure, + cache:false + }; + + var request = YAHOO.util.Connect.asyncRequest('GET', url, callbackGetForm); +} + + +function initAddFieldDialog() { + + var handleSuccess = function(o) { + var response = o.responseText; + var listItemId = response.slice(0,22); + var newInnerHTML = response.slice(22); + var label = addFieldDialog.getData().label; + + var ul1 = new YAHOO.util.Element('ul1'); + var li = document.createElement('li'); + li.id = listItemId; + li.className = 'list1'; + li.innerHTML = newInnerHTML; + ul1.appendChild(li); + var newListItem = Dom.get(listItemId); + new YAHOO.draglist.DDList(newListItem); + + // Add table row to fields on search tab + var search_fields_table = new YAHOO.util.Element('search_fields_table'); + var search_tr = document.createElement('tr'); + search_tr.id = "search_tr_"+listItemId; + search_fields_table.appendChild(search_tr); + + var label_td = document.createElement('td'); + label_td.id = "search_label_"+listItemId; + label_td.className = 'formDescription'; + label_td.innerHTML = label; + search_tr.appendChild(label_td); + + var displayInSearch_td = document.createElement('td'); + displayInSearch_td.id = "search_label_"+listItemId; + displayInSearch_td.className = 'tableData'; + displayInSearch_td.innerHTML = ""; + search_tr.appendChild(displayInSearch_td); + + var searchIn_td = document.createElement('td'); + searchIn_td.id = "search_label_"+listItemId; + searchIn_td.className = 'tableData'; + searchIn_td.innerHTML = ""; + search_tr.appendChild(searchIn_td); + + var sortBy_td = document.createElement('td'); + sortBy_td.id = "search_label_"+listItemId; + sortBy_td.className = 'tableData'; + sortBy_td.innerHTML = ""; + search_tr.appendChild(sortBy_td); + + // Add table row to fields on view tab + var view_fields_table = new YAHOO.util.Element('view_fields_table'); + var view_fields_table_rows = view_fields_table.getElementsByTagName("tr"); + var view_tr = document.createElement('tr'); + view_tr.id = "view_tr_"+listItemId; + view_fields_table.appendChild(view_tr); + + var view_label_td = document.createElement('td'); + view_label_td.id = "view_label_"+listItemId; + view_label_td.className = 'formDescription'; + view_label_td.innerHTML = label; + view_tr.appendChild(view_label_td); + + var display_td = document.createElement('td'); + display_td.id = "search_label_"+listItemId; + display_td.className = 'tableData'; + display_td.innerHTML = ""; + view_tr.appendChild(display_td); + + var viewScreenTitle_td = document.createElement('td'); + viewScreenTitle_td.id = "search_label_"+listItemId; + viewScreenTitle_td.className = 'tableData'; + + // only the first field should be checked by default + if (view_fields_table_rows.length == 2){ + viewScreenTitle_td.innerHTML = ""; + }else{ + viewScreenTitle_td.innerHTML = ""; + } + view_tr.appendChild(viewScreenTitle_td); + }; + + var handleFailure = function(o) { + alert("Submission failed: " + o.status); + }; + + var handleSubmit = function() { + this.submit(); + }; + var handleCancel = function() { + this.cancel(); + }; + + var addFieldDialog = new YAHOO.widget.Dialog("dialog1", { width:"460px", visible:false, + draggable:true, close:true, fixedcenter:true, zIndex:11002, + buttons : [ { text:"Submit", handler:handleSubmit, isDefault:true }, + { text:"Cancel", handler:handleCancel } ] + } ); + addFieldDialog.callback = { success: handleSuccess, failure: handleFailure }; + addFieldDialog.render(); + + initOptionalFields("addDialog"); + + YAHOO.util.Event.addListener("showAddFormButton", "click", addFieldDialog.show, addFieldDialog, true); + +} + +YAHOO.util.Event.addListener(window, "load", initAddFieldDialog); + + +function deleteListItem (url,listItemId,thingId) { + +if (confirm("Are you sure you want to delete this field?")){ + + var handleSuccess = function(o){ + + var ul1 = new YAHOO.util.Element('ul1'); + var removeElement = YAHOO.util.Dom.get(listItemId); + ul1.removeChild(removeElement); + + var search_fields_table = new YAHOO.util.Element('search_fields_table'); + removeElement = YAHOO.util.Dom.get("search_tr_"+listItemId); + search_fields_table.removeChild(removeElement); + + var view_fields_table = new YAHOO.util.Element('view_fields_table'); + removeElement = YAHOO.util.Dom.get("view_tr_"+listItemId); + view_fields_table.removeChild(removeElement); + + }; + + var handleFailure = function(o) { + alert("Submission failed: " + o.status); + }; + + var callback = + { + success:handleSuccess, + failure:handleFailure + }; + + var postData = "func=deleteFieldConfirm;fieldId=" + listItemId + ";thingId=" + thingId; + var request = YAHOO.util.Connect.asyncRequest('POST', url, callback, postData); + + } +} + +var Dom = YAHOO.util.Dom; +var Event = YAHOO.util.Event; +var DDM = YAHOO.util.DragDropMgr; +YAHOO.namespace ("draglist"); + +(function() { + + +YAHOO.draglist.DDApp = { + init: function() { + + + new YAHOO.util.DDTarget("ul1"); + var ul1=Dom.get("ul1"); + var items = ul1.getElementsByTagName("li"); + for (i=0;i this.lastY) { + this.goingUp = false; + } + + this.lastY = y; + }, + + onDragOver: function(e, id) { + + var srcEl = this.getEl(); + var destEl = Dom.get(id); + + // We are only concerned with list items, we ignore the dragover + // notifications for the list. + if (destEl.nodeName.toLowerCase() == "li") { + var orig_p = srcEl.parentNode; + var p = destEl.parentNode; + destination = destEl.id; + if (this.goingUp) { + direction = 'up'; + p.insertBefore(srcEl, destEl); // insert above + } else { + direction = 'down'; + p.insertBefore(srcEl, destEl.nextSibling); // insert below + } + + DDM.refreshCache(); + } + } +}); + +Event.onDOMReady(YAHOO.draglist.DDApp.init, YAHOO.draglist.DDApp, true); + +})(); \ No newline at end of file