Overview | File | Class | Tree | Index | Help
| The Gravey 2.5 Framework and AIM RIA
PREV NEXT | FRAMES NO FRAMES

## aimauctions.js

#### Summary

Collection of application level classes.
This collection implements the rich-internet-application tier of the Auction Module for AIM (Auction Inventory Management), which is a demonstration of the Gravey framework.
Version: 2.0
Requires:

- grvEDO.js
- grvAJAX.js

Author: Bruce Wallace (PolyGlotInc.com)

Class Summary
ALEDO | This is the abstract base class for Auction/Lot EDOs.
ALIndex | This class encapsulates an EDO index for Auctions/Lots.
Auction | This class encapsulates an Auction record.
AuctionModel | This class encapsulates the data model of a particular Auction.
AuctionModelView | This class produces the view of the entire data panel.
AuctionSelectionModel | This class encapsulates the data model for "which Auction is currently selected".
AuctionSummary | This class encapsulates the identifying attributes of an Auction.
AuctionView | This class produces a view of a Auction.
BidderLoadReplyCmd | This Command processes the reply of the "load Bidder data" request.
BidderMenuCmd | This class implements the bidder menu edit command.
Lot | This class encapsulates a Auction "lot" record.
LotListView | This class produces a view of a List of Lot EDOs.
LotView | This class produces a view of a Lot.
NextPhaseCmd | This class implements the Move to Next Auction Phase cmd.
PhaseButtonController | This class is a Button Controller that manages the button that "moves" an auction from one phase to the next.

Method Summary
`static Object` | `_ContactsSelected( bidderKey )`
`static void` | `_GetBidderLists( <long> bidderKey )` Load in contacts and shippings list from specified bidder NOTE: this is a Command helper function. NEVER call this from outside the context of a Command object!
`static Object` | `_ShippingSelected( bidderKey )`
`static void` | `onBidderLoadReply( <grvXMLreq> xmlReq )` handle AJAX event for 'reply received from "load Bidder data" server-request'
`static Object` | `onBidderSelect( <event> e, <String> viewID )` handle event for 'user selects from the bidder menu'
`static void` | `onPhaseBtnPressed()` handle event for 'next phase' button press

    // This file uses JSDoc-friendly comments [ http://jsdoc.sourceforge.net/ ]

    /**
     * @file         aimauction.js
     * @fileoverview Collection of application level classes.<br/>
     * This collection implements the rich-internet-application tier of
     * the Auction Module for AIM (Auction Inventory Management),
     * which is a demonstration of the Gravey framework.
     * @author       Bruce Wallace  (PolyGlotInc.com)
     * @requires     grvEDO.js
     * @requires     grvAJAX.js
     * @version      2.0
     */

    ////////////////////////////////////////////
    //////////// Domain Objects ////////////////
    ////////////////////////////////////////////

    Class(AuctionSummary,["unique Key","auction ID","item count"])
    .Extends(EDOHolderSelectionItem);
    /**
     * @class This class encapsulates the identifying attributes of an Auction.
     * @extends EDOHolderSelectionItem
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function AuctionSummary()
    {
    	/** @param {int} theKey unique key of this record
    	 *  @param {String} theID auction ID
    	 *  @param {int} itemCount count of items attached to this auction
    	 */
    	this.konstructor = function( theKey, theID, itemCount )
    	{
    		// define instance variables
    		this.key	= theKey;
    		this.bsID	= theID;
    		this.count  = itemCount;
    	}

    	/** return "this" formatted for main menu item @type String */
    	this.getDescription = function() {
    		return grvDiamond(this.count)+this.bsID;
    	}

    	/** return "this" as human-readable string @type String */
    	this.toString = function()
    	{
    		var		s = new Array();
    				s.push( this.key );
    				s.push( this.bsID );
    		return	s.join( "-" );
    	}

    	/** set name to given value */
    	this.updateProperties = function( ID ){
    		this.bsID = ID;
    	}
    }

    Class(ALIndex).Extends(EDOIndex);
    /**
     * @class This class encapsulates an EDO index for Auctions/Lots.
     * @extends EDOIndex
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function ALIndex()
    {
      if (!ALIndex.Auction){//keep this line above jsdoc comments!

    	/** Static factory method to generate Auction-flavored index
    	 * @param {int} index Auction index
    	 * @type ALIndex
    	 */
    	ALIndex.Auction = function() {
    		return new ALIndex(0,null);
    	}
    	/** Static factory method to generate Lot-flavored index
    	 * @param {int} index Lot index
    	 * @type ALIndex
    	 */
    	ALIndex.Lot = function( index ) {
    		return new ALIndex(0,index);
    	}
      }

    	/** @param {int} optA index into auctions list for current Auction
    	 *  @param {int} optL index into lots list for specified Auction
    	 * If args not specified or if all are null then this represents "no selection".
    	 */
    	this.konstructor = function( optA,optL )
    	{
    		// define instance variables
    		this.a = optA===undefined ? null : optA;
    		this.l = optL===undefined ? null : optL;
    	}

    	/** return "this" as event handler arg list string @type String */
    	this.asEventArgs = function() {
    		return " new ALIndex("+this.a+","+this.l+") ";
    	}

    	this.asString = function() {
    		return this.invoke( this, this._noString, this._lotString )
    		     + this._auctionString( this.a );
    	}

    	this._noString = function(){ return ""; }

    	/** return auction description @type String */
    	this._auctionString = function( aindex ){
    		var a = gAuctionData._getAuction( aindex );
    		return (a && a[ kStrIdAuctionID ]) ? a[ kStrIdAuctionID ] : "New Auction";
    	}
    	/** return lot description @type String */
    	this._lotString = function( lindex ){
    		lindex -= 0; //type cast to int
    		return "Lot["+(lindex+1)+"] of ";
    	}

    	/** return whether "this" contains a selection @type boolean */
    	this.hasSelection = function(){ return this.a!=null
    	                                    || this.l!=null; }

    	/** return whether "this" equals given EDOIndex @type boolean */
    	this.equals = function(x){
    		return x ? (this.a==x.a && this.l==x.l) : false;
    	}

    	/** Invoke the appropriate method given the index type and
    	 * return its result. Methods are expected to have the signature<pre>
    	 * self.method(this.subindex,optionalArgument)
    	 *</pre>
    	 * @param {Object} self the parent object of the method
    	 * @param {Function} sMethod method to call if xi is Auction type
    	 * @param {Function} lMethod method to call if xi is Lot     type
    	 * @param {Object} optArg optional extra param to pass to method
    	 * @return the result of the called method
    	 */
    	this.invoke = function(self,sMethod,lMethod,optArg){
    		var aMethod;
    		var i;
    		if (this.l!=null) { aMethod = lMethod; i = this.l; } else
                              { aMethod = sMethod; i = this.a; }
    		return aMethod.call( self, i, optArg );
    	}

    }

    ////////////////////////////////////////////////////////////////////////////////
    // Constants defining property names for the auction/lot properties
    ////////////////////////////////////////////////////////////////////////////////

    var kStrIdAuctionID   = 'Auction ID';
    var kDateIdCreate     = 'Create Date';
    var kDateIdLaunch     = 'Launch Date';
    var kDateIdLockdown   = 'Lockdown Date';
    var kDateIdCutoff     = 'Cutoff Date';
    var kDateIdAward      = 'Bid Award Date';
    var kDateIdClosed     = 'Closed Date';

    // Lot fields
    var kIntIdLotNum      = 'Lot#';	//should not be null
    var kStrIdLotName     = 'Lot Name';
    var kDateIdPayDate    = 'Effective Pay Date';
    var kDateIdClosed     = 'Closed Date';
    var kAmtIdExpPerItem  = 'Expenses/Item';
    var kPctIdActualBid   = 'Actual Bid %';
    var kPctIdCommission  = 'Commission %';
    var kPctIdEstTarget   = '% of Est Target %';
    var kIntIdContactsKey = 'Contact';
    var kIntIdShippingKey = 'Shipping';
    // transient Lot field(s)
    var kIntIdBidderKey   = 'Bidder';

    Class(ALEDO,["parent AuctionModel","item count",
    	"edo Class","property values array",
    	"edit Date","edit User","unique Key"])
    .Extends(EDO);
    /**
     * @class This is the abstract base class for Auction/Lot EDOs.
     * @extends EDO
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function ALEDO()
    {
    	/**
    	 *  @param {AuctionModel} holder parent EDOHolderModel
    	 *  @param {int} itemcount how many items are linked to this
    	 *  @param {Function} CLAZZ this EDO's "class"
    	 *  @param {array}  propValues array of property initial values
    	 *  @param {String} editDate date of last edit
    	 *  @param {String} editUser ID of last user to edit
    	 *  @param {int} theKey unique key of this record
    	 *  @param {int} optEditStatus optional edit status where the
    	 * status codes are: 0=no-change; 1=delete; 2=create; 3=hidden; 4=update
    	 *  @param {String} optName optional name of this instance
    	 */
    	this.konstructor = function
    	(
    		holder,
    		itemcount,
    		CLAZZ,
    		propValues,
    		editDate,
    		editUser,
    		theKey,
    		optEditStatus,
    		optName
    	){
    		this.souper( CLAZZ, holder, propValues, editDate, editUser,
    					theKey, optEditStatus, optName );

    		// define instance variables
    		this.itemCount = itemcount;
    	}

    	this.toolTip = function( xi ){
    		return this.edoToolTip(xi) + " Items="+this.itemCount;
    	}

    	this.toString = function() {
    		return this[ kStrIdAuctionID ];
    	}

    	this.canDelete = function(){
    		if (!this.isActive())
    		  return "This is already deleted.";

    		var c = this.itemCount;
    		if (c>0)
    		  return "This can't be deleted. It is referenced by "
    		            +c+" Item"+(c==1?".":"s.");

    		if (this.isLotZero && this.isLotZero())
    		  return "Lot 0 must always exist.";

    		return null;
    	}

    	/** push into given array all ALEDO-specific fields of the UpdateItem message
    	 * formatted as<pre>
    	 * "{parentAuctionID}~{property1}~...~{propertyN}"
    	 * where the fields are defined as follows...
    	 *     {parentAuctionID} = "my" parent auction ID
    	 *     {propertyI}       = the i-th editable property of this EDO
    	 *</pre>
    	 * @param {Array} uFields  string array containing Update Msg fields
    	 */
    	this.pushUpdateFields = function( uFields )
    	{
    		uFields.push( encodeURIComponent(this.holder.getID()) );
    		this.pushEncodedValues( uFields );
    	}
    }

    Class(Auction,["property values array","edit Date","edit User",
    			 "unique Key","parent holder","lot count"])
    .Extends(ALEDO);
    /**
     * @class This class encapsulates an Auction record.
     * @extends ALEDO
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function Auction()
    {
    	// init "static" Class methods/elements
    	if (!Auction.Properties) {//keep this line above jsdoc comments!

    		/** Static factory method to generate blank Auction @type Auction */
    		Auction.Factory = function(index,holder)
    		{
    			var x = new Auction( null, grvGetTodayAsMMDDYYYY(),kUserID,null,holder,0 );
    			x[ kDateIdCreate ] = x.date;
    			return x;
    		}

    		// init static member variables
    		Auction.UpdateID   = "Auction";
    		Auction.Properties = [ kStrIdAuctionID,
    				kDateIdCreate, kDateIdLaunch, kDateIdLockdown,
    				kDateIdCutoff, kDateIdAward, kDateIdClosed ];

    		Auction.EditRules  = [ MVCEditRule.kALNO,
    				MVCEditRule.kDATE, MVCEditRule.kDate, MVCEditRule.kDate,
    				MVCEditRule.kDate, MVCEditRule.kDate, MVCEditRule.kDate ];

    		Auction.States     = [ kDateIdCreate, kDateIdLaunch, kDateIdLockdown,
    				kDateIdCutoff, kDateIdAward, kDateIdClosed ];
    	}

    	/** @param {array} array of editable property values in same order as .Properties
    	 *  @param {String} editDate date of last edit
    	 *  @param {String} editUser ID of last user to edit
    	 *  @param {int} theKey unique key of this record
    	 *  @param {AuctionModel} holder parent EDOHolderModel
    	 *  @param {int} itemcount how many Items are linked to this
    	 *  @param {int} optEditStatus optional edit status
    	 *  @param {String} optName optional name of this instance
    	 */
    	this.konstructor = function
    	( propArray, editDate, editUser, theKey, holder, itemcount, optEditStatus, optName )
    	{
    		//Cant edit ID if items are already assigned to auction
    		Auction.EditRules[0] = (itemcount>0) ? MVCEditRule.kRO : MVCEditRule.kALNO;

    		this.souper( holder, itemcount, Auction,
    		 propArray, editDate, editUser,	theKey, optEditStatus, optName );

    		//if new object then init a few fields
    		if (!propArray) this[kDateIdCreate] = editDate;

    		//set up special validations
    		this[ kStrIdAuctionID+MVCAttributeModel.kValidateSuffix ] = this.validateBSID;

    		for (var i=0; i<Auction.States.length; ++i)
    		  this[ Auction.States[i]+MVCAttributeModel.kValidateSuffix ] = this.validateDate;
    	}

    	/** custom validation method to verify legality of a phase date
    	 * @type String
    	 * @return error message or null if no error
    	 */
    	this.validateDate = function( dateID )
    	{
    		var dateStr = this[ dateID ];      if ( grvIsEmpty(dateStr) ) return null;
    		var date    = Date.parse(dateStr); if ( date == null        ) return null;

    		switch ( dateID )
    		{
    	      case kDateIdCreate:
    			if (grvAfterNow(dateStr))
    			  return "Create date can't be in the future.";
    			break;

    	      case kDateIdLaunch:
    	        dateStr = this[kDateIdCreate];
    			if (grvIsEmpty(dateStr) || grvAfter(dateStr,date+1))
    			  return "Launch date must be after Create date";
    			break;

    	      case kDateIdLockdown:
    	        dateStr = this[kDateIdLaunch];
    			if (grvIsEmpty(dateStr) || grvAfter(dateStr,date+1))
    			  return "Lockdown date must be after Launch date";
    			break;

    	      case kDateIdCutoff:
    	        dateStr = this[kDateIdLockdown];
    			if (grvIsEmpty(dateStr) || grvAfter(dateStr,date+1))
    			  return "Cutoff date must be after Lockdown date";
    			break;

    	      case kDateIdAward:
    	        dateStr = this[kDateIdCutoff];
    			if (grvIsEmpty(dateStr) || grvAfter(dateStr,date+1))
    			  return "Bid Award date must be after Cutoff date";
    			break;

    	      case kDateIdClosed:
    	        dateStr = this[kDateIdAward];
    			if (grvIsEmpty(dateStr) || grvAfter(dateStr,date+1))
    			  return "Close date must be after Bid Award date";
    			break;

    	      default:
    	      	return "Illegal Auction State";
    		}

    		return null;	//no error
    	}

    	/** return the current auction phase or null if in an illegal state @type String */
    	this.nextState = function()
    	{
    		if (this.isValid()){
    		  for (var i=0; i<Auction.States.length; ++i){
    		    var stateID = Auction.States[i];
    			if ( grvIsEmpty(this[stateID]) ) return stateID;
    		  }
    		}
    		return null;//illegal state
    	}

    	/** custom validation method to verify uniqueness of auction ID
    	 * @type String
    	 * @return error message or null if no error
    	 */
    	this.validateBSID = function()
    	{
    		if ( this.hasDuplicateBSID()) return "Duplicate Auction IDs are not allowed.";
    		return null;
    	}

    	/** verify uniqueness of Auction ID (as best we can)
    	 * @type boolean
    	 * @return true iff our auction ID duplicates any in parent auction summary list
    	 */
    	this.hasDuplicateBSID = function() {
    		var key = this.holder.model.auctionKey( this[kStrIdAuctionID] );
    		return (key>0) && (key!=this.key);
    	}

    	/** return a clone of this object @type Auction */
    	this.clone = function() {
    		return new Auction( this.propValues(), this.date, this.whom,
    			this.key, this.holder, this.itemCount, this.editStatus );
    	}

    	this.canCreate = function(appendFlag) {
    	  return this.holder.isTrue()
    		 ? "Can't add a new Auction until pending changes have been saved"
    		 : null;
    	}

    	/** If created, can we undo creation? @type boolean
    	 * @param {boolean} appendFlag if true then append else insert
    	 */
    	this.canUncreate = function(appendFlag){ return false; }//override me
    }

    ////////////////////////////////////////////////////////////////////////////////

    var kSpecialLotName = "special unassigned items lot";

    Class(Lot,["property values array","edit Date","edit User",
    				"unique Key","parent holder","item count"])
    .Extends(ALEDO);
    /**
     * @class This class encapsulates a Auction "lot" record.
     * @extends ALEDO
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function Lot()
    {
    	// init "static" Class methods/elements
    	if (!Lot.Properties) {//keep this line above jsdoc comments!

    		/** Static factory method to generate blank Lot @type Lot */
    		Lot.Factory = function(index,holder)
    		{
    			var x = new Lot( null,grvGetTodayAsMMDDYYYY(),kUserID,null,holder,0 );
    			x[ kAmtIdExpPerItem ] = 0;
    			x[ kPctIdActualBid  ] = 0;
    			x[ kPctIdCommission ] = 0;
    			x[ kPctIdEstTarget  ] = 0;
    			x[ kIntIdBidderKey  ] = 0;
    			x.expanded = true;
    			return x;
    		}

    		// init static member variables
    		Lot.UpdateID   = "Lot";
    		Lot.Properties = [ kIntIdLotNum, kStrIdLotName,
    				kDateIdPayDate, kDateIdClosed, kAmtIdExpPerItem,
    				kPctIdActualBid, kPctIdCommission, kPctIdEstTarget,
    				kIntIdContactsKey, kIntIdShippingKey,
    				//transient field(s)
    				kIntIdBidderKey
    				 ];
    		Lot.EditRules  = [ MVCEditRule.kINT, MVCEditRule.kEdit,
    				MVCEditRule.kDate, MVCEditRule.kDate, MVCEditRule.kDec,
    				MVCEditRule.kDec, MVCEditRule.kDec, MVCEditRule.kDec,
    				MVCEditRule.kInt, MVCEditRule.kInt,
    				//transient field(s)
    				MVCEditRule.kEdit
    				 ];
    	}

    	/** @param {array} array of editable property values in same order as .Properties
    	 *  @param {String} editDate date of last edit
    	 *  @param {String} editUser ID of last user to edit
    	 *  @param {int} theKey unique key of this record
    	 *  @param {AuctionModel} holder parent EDOHolderModel
    	 *  @param {int} itemcount how many Items are linked to this
    	 *  @param {int} optEditStatus optional edit status
    	 *  @param {String} optName optional name of this instance
    	 */
    	this.konstructor = function
    	( propArray, editDate, editUser, theKey, holder, itemcount, optEditStatus, optName )
    	{
    		this.souper( holder, itemcount, Lot,
    		 propArray, editDate, editUser,	theKey, optEditStatus, optName );

    		this[ kIntIdLotNum+MVCAttributeModel.kValidateSuffix ] = this.validateLotNum;
    		this.expanded = false;
    	}

    	this.hasLotNum = function( n ){ return n == this[kIntIdLotNum]; }

    	this.isLotZero = function(){
    		return grvIsEmpty(this[kIntIdLotNum]) ? false
    		 : (this[kIntIdLotNum]==0 && this[kStrIdLotName]==kSpecialLotName);
    	}

    	/** custom validation method to verify uniqueness of Lot number
    	 * @type String
    	 * @return error message or null if no error
    	 */
    	this.validateLotNum = function()
    	{
    		if ( this.isLotZero()         ) return null;
    		if ( this[kIntIdLotNum]==0    ) return "Lot number zero is only for special lot.";
    		if ( this.hasDuplicateLotNum()) return "Duplicate Lot numbers are not allowed.";
    		return null;
    	}

    	/** custom validation method to verify uniqueness of Lot number
    	 * @type boolean
    	 * @return true iff our lot number duplicates any in parent auction
    	 */
    	this.hasDuplicateLotNum = function() {
    		return this.holder.lotCount( this[kIntIdLotNum] ) > 1;
    	}

    	/** return a clone of this object @type Lot */
    	this.clone = function() {
    		return new Lot( this.propValues(), this.date, this.whom,
    			this.key, this.holder, this.itemCount, this.editStatus );
    	}

    	this.toString = function() {
    		var s = grvIsEmpty(this[kIntIdLotNum ]) ? "" : ("#"+this[kIntIdLotNum]);
    		var t = grvIsEmpty(this[kStrIdLotName]) ? "" : (" "+this[kStrIdLotName]);
    		return s+t;
    	}

    	/** Is it legal to edit "this"?
    	 * @return errmsg or null
    	 * @type String
    	 */
    	this.canEdit = function(){
    		if ( kReadOnly ) return "Not allowed in read-only mode.";
    		if (!this.isActive()) return "This is deleted.";
    		return this.isLotZero() ? "Lot 0 is not editable." : null;
    	}

    	/** mark this entity as having been edited */
    	this.editMe = function()
    	{
    		this.souper();
    		_GetBidderLists( this[kIntIdBidderKey] );
    	}
    }

    ////////////////////////////////////////////
    ////////////// Data Models /////////////////
    ////////////////////////////////////////////

    Class(AuctionModel,["Auction Selection Model"]).Extends(EDOHolderModel);
    /**
     * @class This class encapsulates the data model of a particular Auction.
     * This model subscribes to a {@link AuctionSelectionModel}
     * so that new Lot lists can be downloaded whenever a new Auction is selected.
     * <p>NOTE: Other parts of AIM assume that the lot lists will never be null;
     * zero items is ok though.</p>
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function AuctionModel()
    {
    	/** @param {AuctionSelectionModel} auctionSelectionModel model of which Auction is selected
    	 *  @param {String} optName optional name of this instance
    	 */
    	this.konstructor = function( auctionSelectionModel, optName )
    	{
    		// init static DOM (must do this here instead of at static load time!)
    		if (!AuctionModel.LoadXslDOM) AuctionModel.LoadXslDOM = grvLoadXslDOM( kXSLPath+"AIMaucToJS.xsl" );
    		var holderName = optName ? optName : "Auction";
    		this.souper( auctionSelectionModel, AuctionModel.LoadXslDOM, holderName );

    		// init instance variables
    		this._resetEDOs();
    	}

    	/** return the parent Auction ID for this model @type String */
    	this.getID = function(){
    		return this.auction ? this.auction[kStrIdAuctionID] : null;
    	}

    	/** return whether any EDOs are changed for this model @type boolean */
    	this.isDirty = function()
    	{
    		if (this.auction && this.auction.inEdit()) return true;
    		if (this.lList.isDirty()) return true;
    		return false;
    	}

    	/** return whether all EDOs are valid for this model @type boolean */
    	this.isValid = function()
    	{
    		if (!this.auction || !this.auction.isValid()) return false;

    		//special case: if we are deleting auction then other errs dont matter
    		if (this.auction.isDeleted()) return true;

    		return this.lList.isValid();
    	}

    	/** clear EDOs */
    	this._resetEDOs = function( optAuction )
    	{
    		this.auction = optAuction ? optAuction : null;

    		if ( this.lList ) this.lList.reset();
    		else this.lList = new EDOListModel( Lot );
    	}

    	/** set our Auction object   but dont publish */
    	this._setAuction = function(o){ this.auction = o; }

    	/** get a new Lot list @type ListModel */
    	this._newLots = function(){ return this.lList.reset(); }

    	/** return the debug details of "this" @type String */
    	this.dump = function()
    	{
    		var		dStr = new Array();
    				dStr.push( "AuctionModel>>>[" );
    				dStr.push( "auction=" +(this.auction ?this.auction .dump():"null") );
    				dStr.push( "lots="    +(this.lList   ?this.lList   .dump():"null") );
    				dStr.push( "]" );
    		return	dStr.join("\n");
    	}

    	/** create a new item for the selection list from current EDO
    	 * @type EDOHolderSelectionItem
    	 */
    	this.createSelectionItem = function() {
    		return new AuctionSummary( this.auction.key, this.auction[kStrIdAuctionID], 0 );
    	}
    	/** return the updated properties from the current EDO needed for select list update
    	 * @return arbitrary value as needed @type Object
    	 */
    	this.getUpdatedProperty = function() {
    		return this.getID();
    	}

    	/** return how many lots have the given lot number @type int */
    	this.lotCount = function( lotnum )
    	{
    		var count = 0;
    		this.lList.iterate( function(i,lot){ if (lot.hasLotNum(lotnum)) ++count; } );
    		return count;
    	}

    	/** return whether there is currently an EDO @type boolean */
    	this.hasEDO = function(){ return this.auction!=null; }

    	/** return whether current EDO matches selection item "key"
    	 * @type boolean
    	 * @param {EDOHolderSelectionItem} item selection menu item
    	 */
    	this.keysMatch = function(item){ return this.auction.key==item.key; }

    	/** return whether current EDO matches selection item "properties"
    	 * @type boolean
    	 * @param {EDOHolderSelectionItem} item selection menu item
    	 */
    	this.propMatch = function(item){ return this.getID()==item.bsID; }

    	/** push into given array all AJAX SAVE Post params for this model
    	 * @param {Array} posts  string array containing POST params
    	 */
    	this.pushPosts = function( posts )
    	{
    		this.auction.pushPosts( posts );	//THIS **MUST** BE FIRST!!
    		this.lList  .pushPosts( posts );
    	}

    	/** return a new blank EDO of the type implied by EDOIndex @type EDO
    	 * @param {EDOIndex} xi edo index
    	 */
    	this._newEDO = function(xi) {
    		return xi.invoke( this, Auction.Factory, Lot.Factory, this );
    	}

    	/** return the specified lot @type Lot
    	 * @param {int} i index into lot list
    	 */
    	this._getLot = function( i ) {
    	  return (i!=null && i>=0
    	          && i<this.lList.getCount())
    				 ? this.lList.getItem( i ) : null;
    	}

    	/** return the specified auction @type Auction
    	 * @param {int} i index into auction list
    	 */
    	this._getAuction = function( i ) {
    	  return (i==0 && this.auction)
    	                ? this.auction : null;
    	}
    	/** return reference to the specified editable domain object
    	 * @param {ALIndex} xi edo index
    	 */
    	this.getEDO  = function(xi){
    		return xi.invoke( this, this._getAuction, this._getLot );
    	}

    	/** insert a new lot
    	 * @param {int} i lot list index
    	 * @param {EDO} edo the shipping
    	 */
    	this._insertLot = function( xi ) {
    	    this.lList.addBefore( i, edo );
    	}
    	/** create new EDO which is inserted after selected EDO
    	 * @return EDOIndex of new EDO
    	 * @type EDOIndex
    	 * @param {EDOIndex} xi edo index
    	 */
    	this.createEDO = function(xi){
    		xi.invoke( this, this._newAuction, this._insertLot, this.newEDO(xi) );
    		return xi;
    	}

    	/** append a new lot
    	 * @return EDOIndex of new EDO
    	 * @type EDOIndex
    	 * @param {int} i lot list index
    	 * @param {EDO} edo the lot
    	 */
    	this._appendLot = function( i, edo ) {
    	    return ALIndex.Lot( this.lList.addItem( edo ) );
    	}
    	/** create a new auction
    	 * @return EDOIndex of new EDO
    	 * @type EDOIndex
    	 * @param {int} i auction list index
    	 * @param {EDO} edo the auction
    	 */
    	this._newAuction = function( i, auctionEDO )
    	{
    		this._resetEDOs( auctionEDO );

    		//auto-create special lot zero
    		var lotEDO = this.newEDO(ALIndex.Lot(0));
    		lotEDO[ kIntIdLotNum  ] = 0;
    		lotEDO[ kStrIdLotName ] = kSpecialLotName;
    		lotEDO.makeReadOnly();
    		this._appendLot( 0, lotEDO );

    		this.updateStamp();
    		return ALIndex.Auction();
    	}

    	/** create new EDO which is appended at end of EDO list
    	 * @return EDOIndex of new EDO
    	 * @type EDOIndex
    	 * @param {EDOIndex} xi edo index
    	 */
    	this.appendEDO = function(xi){
    		return xi.invoke( this, this._newAuction, this._appendLot, this.newEDO(xi) );
    	}

    	/** toggle the "expanded" flag of the specified EDOs.
    	 * @param {boolean} doAllFlag if true, set all of the EDOs to new value
    	 * @param {EDOIndex} xi edo index
    	 */
    	this.toggleExpand = function( doAllFlag, xi )
    	{
    		var edo = this.getEDO(xi);
    		if (doAllFlag)
    		{
    			var newVal = !edo.isExpanded();
    			this.lList  .toggleExpandAll( newVal );
    			this.auction.toggleExpand   ( newVal );
    		}
    		else edo.toggleExpand();
    		this.updateStamp();
    	}
    }

    Class(AuctionSelectionModel,["AuctionSummary List Model"]).Extends(EDOHolderSelectionModel);
    /**
     * @class This class encapsulates the data model for
     * "which Auction is currently selected".
     * @extends EDOHolderSelectionModel
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function AuctionSelectionModel()
    {
    	/** @param {ListModel} listModel {@link AuctionSummary} list */
    	this.konstructor = function( listModel ){
    		this.souper( listModel, "Auction " );
    	}

    	/** Return the list index of the specified Auction or <0 if not found. @type int */
     	this.findAuction = function( auctionID, auctionKey )
    	{
    		var list = this.model;
    		var N    = list.getCount();
    		if (N<1) return -2;//NO DATA IN auction SUMMARY LIST!!

    		for (var i=0; i<N; ++i)
    		  if (list.getItem(i).bsID == auctionID
    		  ||  list.getItem(i).key  == auctionKey) return i;

    		return -1;
    	}

    	/** return the key of the auction with the given auction ID @type int */
    	this.auctionKey = function( auctionID )
    	{
    		var key = -1;
    		this.model.iterate( function(i,ss){ if (ss.bsID==auctionID) key = ss.key; } );
    		return key;
    	}

    	/** Select the "initially selected" EDOHolder<br>
    	 * @param {boolean} selectFirst if selection critera has no match then
    	 * if selectFirst==true then select the first in list
    	 *                      else leave selection alone
    	 */
     	this.selectInitial = function( selectFirst )
    	{
    		var i = this.findAuction( kAuctionID, kAuctionKey );
    		if (i==-2){ this.selectNothing(); return; }//EMPTY LIST!!
    		if (i>= 0){ this.select(i);       return; }//found it
    		if (selectFirst) this.select(0);
    	}
    }

    ////////////////////////////////////////////
    ////////////// Controllers /////////////////
    ////////////////////////////////////////////

    Class(PhaseButtonController,["button text model"])
    .Extends(MVCTxtButtonController);
    /**
     * @class This class is a Button Controller that manages the button that
     * "moves" an auction from one phase to the next.
     * @extends MVCTxtButtonController
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function PhaseButtonController()
    {
    	/** @param {Auction} auction Auction we are to observe
    	 */
    	this.konstructor = function( auction ) {
    		this.souper( this, "Declare Phase as met", "onPhaseBtnPressed" );

    		// init instance variables
    		this.auction = auction;
    		this.enabld  = false;
    	}

    	/** Return whether this button should be enabled. @type boolean */
    	this.isEnabled = function() {
    		return kReadOnly ? false : (this.enabld && this.auction.inEdit());
    	}

    	/** simulate MVCScalarModel interface enough to supply button text @type String */
    	this.getValue = function()
    	{
    		this.enabld = true;
    		switch ( this.auction.nextState() )
    		{
    	      case kDateIdLaunch:	return "Launch Auction";
    	      case kDateIdLockdown:	return "Lockdown Auction";
    	      case kDateIdCutoff:	return "Cutoff Auction";
    	      case kDateIdAward:	return "Award Bids";
    	      case kDateIdClosed:	return "Close Auction";
    		}
    		this.enabld = false;
    		return "N/A";
    	}
    }

    ////////////////////////////////////////////
    ////////////// Data Views  /////////////////
    ////////////////////////////////////////////

    Class(AuctionView,["Auction object"])
    .Extends(EDOView);
    /**
     * @class This class produces a view of a {@link Auction}.
     * @extends EDOView
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function AuctionView()
    {
    	/** @param {Auction} auction Auction we are to observe
    	 */
    	this.konstructor = function( auction ) {
    		this.souper( auction, ALIndex.Auction() );
    	}

    	this.buildFields = function( HTML )
    	{
    		HTML.push( this.buildUprField( kStrIdAuctionID, 10, 10, false ) );

    		HTML.push( this.buildDayField( kDateIdCreate  ,         false ) );
    		HTML.push( this.buildDayField( kDateIdLaunch  ,         false ) );
    		HTML.push( this.buildDayField( kDateIdLockdown,         false ) );

    		HTML.push( this.buildDayField( kDateIdCutoff  ,         false ) );
    		HTML.push( this.buildDayField( kDateIdAward   ,         false ) );
    		HTML.push( this.buildDayField( kDateIdClosed  ,         false ) );

    		HTML.push( "<td>"+ this.embedHTML( this.getWidgetID()+".btn",
    							new PhaseButtonController( this.model ) )
    				  +"</td>" );

    	}
    }

    Class(LotView,["Lot object","EDOIndex of Lot"])
    .Extends(EDOView);
    /**
     * @class This class produces a view of a {@link Lot}.
     * @extends EDOView
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function LotView()
    {
    	/** @param {Lot} edo EDO we are to observe
    	 *  @param {EDOIndex} edoIndex index to EDO
    	 */
    	this.konstructor = function( edo, edoIndex ) {
    		this.souper( edo, edoIndex );
    	}

    	this.preSelect = function()
    	{
    		var bk = this.model[ kIntIdBidderKey ];
    		this  .sharedMenuSelect(   gBidderSelected    , kIntIdBidderKey );
    		this.cascadedMenuSelect( _ContactsSelected(bk), kIntIdContactsKey );
    		this.cascadedMenuSelect( _ShippingSelected(bk), kIntIdShippingKey );
    	}

    	this.buildFields = function( HTML )
    	{
    		var bidderKey = this.model[kIntIdBidderKey];

    		HTML.push( this.buildStrField( kIntIdLotNum      ,  3,  3, false ) );
    		HTML.push( this.buildStrField( kStrIdLotName     , 50, 50, false, 3 ) );
    //		HTML.push( this.buildStrField( kIntIdBidderKey   , 10, 10, true  ) );
    		HTML.push( this.buildPopField( kIntIdBidderKey   ,         true,
    			gBidderSelected, 1, "onBidderSelect" ) );

    		HTML.push( this.buildNulField(                             false ) );
    		HTML.push( this.buildDayField( kDateIdPayDate    ,         false ) );
    		HTML.push( this.buildPctField( kPctIdActualBid   ,         false ) );
    		HTML.push( this.buildAmtField( kAmtIdExpPerItem  ,         false ) );
    //		HTML.push( this.buildStrField( kIntIdContactsKey , 10, 10, true  ) );
    		HTML.push( this.buildPopField( kIntIdContactsKey ,         true,
    			_ContactsSelected(bidderKey),null,null,this.model.contName   ) );

    		HTML.push( this.buildNulField(                             false ) );
    		HTML.push( this.buildDayField( kDateIdClosed     ,         false ) );
    		HTML.push( this.buildPctField( kPctIdCommission  ,         false ) );
    		HTML.push( this.buildPctField( kPctIdEstTarget   ,         false ) );
    //		HTML.push( this.buildStrField( kIntIdShippingKey , 10, 10, true  ) );
    		HTML.push( this.buildPopField( kIntIdShippingKey ,         true,
    			_ShippingSelected(bidderKey),null,null,this.model.shipName ) );
    	}
    }

    Class(LotListView,["EDO ListModel"])
    .Extends(EDOListView);
    /**
     * @class This class produces a view of a List of Lot EDOs.
     * @extends EDOListView
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function LotListView()
    {
    	/** @param {EDOListModel} edoListModel EDO list we are to observe
    	 */
    	this.konstructor = function( edoListModel ) {
    		this.souper( edoListModel, LotView );
    	}

    	this.itemEDOIndex = function( index ) {
    		return ALIndex.Lot( index );
    	}
    }

    Class(AuctionModelView,["Auction data model"])
    .Extends(EDOHolderView);
    /**
     * @class This class produces the view of the entire data panel.
     * @extends EDOHolderView
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function AuctionModelView()
    {
    	/** @param {AuctionModel} auctionModel Auction/lots we are to observe */
    	this.konstructor = function( auctionModel ) {
    		this.souper( auctionModel );
    	}

    	this.buildFields = function( HTML )
    	{
    	  var vwID = this.getWidgetID();

    	  if ( !this.model.auction || this.model.auction.inLimbo() )
    	  {
    		if (!grvWAITING())
    		HTML.push( EDOView.ShellHTML( ALIndex.Auction(), Auction ) );
    	  }
    	  else if ( this.model.auction.isActive() )
          {
    		HTML.push( this.embedHTML( vwID+".auctionWdgt",
    						new AuctionView( this.model.auction ) ) );

    		HTML.push( this.embedHTML( vwID+".lotWdgt",
    		                new LotListView( this.model.lList   ) ) );
          }
          else HTML.push( '<thead>This Auction is deleted. You must Cancel, Save, or Undo.</thead>' );
    	}
    }
    				////////////////////////////////////////////
    				//////////////// Commands //////////////////
    				////////////////////////////////////////////

    /** Load in contacts and shippings list from specified bidder<br>
     *  NOTE: this is a Command helper function.<br>
     *  NEVER call this from outside the context of a Command object!
     * @param {long} bidderKey unique key of bidder
     */
    function _GetBidderLists( bidderKey )
    {
    	if (_ContactsSelected(bidderKey).loaded) return;//already loaded
    	_gGrvHackStartupInhibitWait = true;
    	EDOHolderModel.AjaxRequest( "Bidder", bidderKey, onBidderLoadReply );
    }

    function _ContactsSelected( bidderKey )
    {
    	if (gContactsSelected[bidderKey]){/*already created*/} else
    	{
    		var bs = "#"+bidderKey;
    		var L  = new MVCMapModel(bs+":Contacts List");
    		L.map.addItem( 0, new MVCDecode( "Contact", "0", "", 1 ) );
    		gContactsSelected[bidderKey] = new MVCSelectionModel( L, bs+":shared contact selection model" );
    		gContactsSelected[bidderKey].loaded = (bidderKey==0);
    	}
    	return gContactsSelected[bidderKey];
    }

    function _ShippingSelected( bidderKey )
    {
    	if (gShippingSelected[bidderKey]){/*already created*/} else
    	{
    		var bs = "#"+bidderKey;
    		var L  = new MVCMapModel(bs+":Shipping List");
    		L.map.addItem( 0, new MVCDecode( "Shipping", "0", "", 1 ) );
    		gShippingSelected[bidderKey] = new MVCSelectionModel( L, bs+":shared shipping selection model" );
    		gShippingSelected[bidderKey].loaded = (bidderKey==0);
    	}
    	return gShippingSelected[bidderKey];
    }

    Class(BidderMenuCmd,["view ID"]).Extends(EDOSuperMenuCmd);
    /**
     * @class This class implements the bidder menu edit command.
     * @extends EDOSuperMenuCmd
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function BidderMenuCmd()
    {
    	/** @param {String} viewID viewID of menu generating this event */
    	this.konstructor = function( viewID ) {
    		this.souper( viewID );
    	}

    	this.updateEDO = function( exemplar, isRedo )
    	{
    		this.edo[ kIntIdContactsKey ] = exemplar[ kIntIdContactsKey ];
    		this.edo[ kIntIdShippingKey ] = exemplar[ kIntIdShippingKey ];
    	}

    	this.prefillEDO = function()
    	{
    		_GetBidderLists( this.newValue );
    		this.updateOtherController( kIntIdContactsKey, 0 );
    		this.updateOtherController( kIntIdShippingKey, 0 );
    	}
    }

    Class(BidderLoadReplyCmd,["xml request object"]).Extends(MVCAJAXReplyCmd);
    /**
     * @class This Command processes the reply of the "load Bidder data" request.
     * NOTE: It isnt undoable (because we lose all edits!).
     * @extends MVCAJAXReplyCmd
     * @see #konstructor
     * @deprecated ajax call was made synchronous to make undo possible
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function BidderLoadReplyCmd()
    {
    	/** @param {grvXMLreq} xmlReq the XML request being replied to
    	 *  @param {String} optName optional name of this instance
    	 */
    	this.konstructor = function( xmlReq, optName ) {
    		if (!BidderLoadReplyCmd.DOM)  BidderLoadReplyCmd.DOM = grvLoadXslDOM( kXSLPath+"AIMbidListsToJS.xsl" );
    		this.souper( xmlReq, BidderLoadReplyCmd.DOM, optName );
    	}
    }

    Class(NextPhaseCmd).Extends(EDOCmd);
    /**
     * @class This class implements the Move to Next Auction Phase cmd.
     * @extends EDOCmd
     * @see #konstructor
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function NextPhaseCmd()
    {
    	this.konstructor = function(){
    		this.souper("move to next phase", gEDOSelected.canEditSelected());
    		this.auctionEDO = gEDOSelected.getSelected();
    		this.dateID     = this.auctionEDO.nextState();
    		if (this.dateID==null) this.state = -1;
    		this.dateStr    = grvFormatDate( new Date(), "mm/dd/yyyy" );
    	}

    	this.doit = function(){ this.auctionEDO[ this.dateID ] = this.dateStr; }
    	this.undo = function(){ this.auctionEDO[ this.dateID ] =           ""; }
    }

    ////////////////////////////////////////////
    ////////// Static Event Handlers ///////////
    ////////////////////////////////////////////

    /** handle event for 'user selects from the bidder menu'
     * @param {event} e browser event
     * @param {String} viewID ID of the controller generating this event
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.5
     */
    function onBidderSelect( e, viewID ){
    	mvcDoCmd( new BidderMenuCmd( viewID ) );
    	return true;
    }

    /** handle AJAX event for 'reply received from "load Bidder data" server-request'
     * @param {grvXMLreq} xmlReq the XML request being replied to
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function onBidderLoadReply( xmlReq ){
    	//replace async with sync to allow undo
    	//mvcDoCmd( new BidderLoadReplyCmd( xmlReq ) );

    	if (!onBidderLoadReply.DOM) onBidderLoadReply.DOM = grvLoadXslDOM( kXSLPath+"AIMbidListsToJS.xsl" );

    	//translate received XML into javascript (via XSL) and save
    	onBidderLoadReply.script = xmlReq.xform2( onBidderLoadReply.DOM );
    	if (gGrvTraceEvt) grvDebugWindow( onBidderLoadReply.script );
    	eval( onBidderLoadReply.script );
    }

    /** handle event for 'next phase' button press
     * @author Bruce Wallace  (PolyGlotInc.com)
     * @version 2.0
     */
    function onPhaseBtnPressed(){
    	mvcDoCmd( new NextPhaseCmd() );
    }

Overview | File | Class | Tree | Index | Help
| The Gravey 2.5 Framework and AIM RIA
PREV NEXT | FRAMES NO FRAMES

Documentation generated by JSDoc on Thu Jan 6 12:46:39 2011