|
The Gravey 2.5 Framework and AIM RIA | |||||||
| PREV NEXT | FRAMES NO FRAMES | |||||||
Collection of Editable Domain Object framework classes.
This library builds on the MVC framework and adds support for EDOs
(Editable Domain Objects) including undo-able select/edit/delete/insert
operations.
Version: 2.5
Requires:
| Class Summary | |
| EDO | This class defines a framework for Editable Domain Objects. Note that subclasses MUST override the clone() method. |
| EDOAppPanelView | This class produces the view of the entire application page. |
| EDOButtonController | This class is a button controller for EDO "edit" buttons which shouldn't be enabled while app is in "read only" mode. |
| EDOCmd | This is the abstract base class for EDO commands. |
| EDOControlPanelView | This class produces the view of the top control panel. |
| EDOCountersView | This class produces a view of the current selection and total size of a selection model (ie "I of N"). |
| EDOCreateCmd | This class implements the append and insert EDO cmds. |
| EDODeleteCmd | This class implements the delete EDO cmd. |
| EDOEditCmd | This class implements the edit EDO cmd. |
| EDOHolderCancelAllChangesCmd | This class implements the "revert" command. |
| EDOHolderCloseWindowIfSavedCmd | This class implements the "close this window if all EDOs in the global EDOHolder are saved" command. |
| EDOHolderLoadReplyCmd | This Command processes the reply of the "load EDOHolder data" request. |
| EDOHolderModel | This abstract class encapsulates the functionality of a data model managing a set of editable domain objects (EDOs). |
| EDOHolderSaveAllChangesCmd | This class implements the "save all changes made to EDOs in the global EDOHolder" command. |
| EDOHolderSelectCmd | This class implements the "select new EDO Holder" command. |
| EDOHolderSelectInitialCmd | This class implements the "select initially specified EDOHolder" command. |
| EDOHolderSelectionItem | This class defines the interface expected for items appearing in the list model watched by EDOHolderSelectionModel. |
| EDOHolderSelectionModel | This class encapsulates the data model for "which EDOHolder is currently selected" from list of EDOHolderSelectionItem. |
| EDOHolderSelectMenuController | This class manages a popup menu controller for the Selection List that chooses the current EDOHolder. |
| EDOHolderView | This class produces the view of an EDOHolderModel. |
| EDOImgButtonController | This class is an MVCImgButtonController for EDO "edit" buttons which shouldnt be enabled while app is in "read only" mode. |
| EDOIndex | This simple class encapsulates an EDO index to allow more complex composite indexes to be defined as subclasses. |
| EDOListModel | This class encapsulates a list model for EDOs. |
| EDOListView | This class produces a view of a List of EDOs. |
| EDOSelectedModel | This class encapsulates the data model for the flag indicating whether an editable domain object (EDO) is selected from a set of EDOs in an EDOHolderModel. |
| EDOSuperMenuCmd | This abstract class is a base for menu commands that affect other EDO attributes. |
| EDOToggleExpandCmd | This class implements the toggle EDO display cmd. |
| EDOToggleSelectCmd | This class implements the toggle select EDO cmd. |
| EDOView | This abstract class produces a view of an EDO. |
| Method Summary | |
static void
|
EDOInitialize( <EDOHolderModel> edoHolder, <Function> edoIndexClass, <Function> edoHolderViewClass, optCounterViewClass, <PopupMenuController> optMenuCtrlr )
Initialize EDO Framework global variables. |
static void
|
onEDOAddClick( <event> e, <EDOIndex> xi )
handle event for 'click on an EDO Add Button' |
static void
|
onEDOClick( <event> e, <EDOIndex> xi )
handle event for 'click on an EDO' |
static void
|
onEDODeleteBtnPressed()
handle event for 'delete EDO button pressed' |
static void
|
onEDOEditBtnPressed()
handle event for 'edit EDO button pressed' |
static void
|
onEDOHolderCancelBtnPressed()
handle event for 'cancel button pressed' |
static void
|
onEDOHolderExitBtnPressed()
handle event for 'exit button pressed' |
static void
|
onEDOHolderLoadReply( <grvXMLreq> xmlReq )
handle AJAX event for 'reply received from "load EDOHolder data" server-request' |
static Object
|
onEDOHolderPageBeforeUnLoad()
|
static void
|
onEDOHolderPageLoad()
handle event for 'entering EDOHolder web page' |
static void
|
onEDOHolderSaveBtnPressed()
handle event for 'save button pressed' |
static void
|
onEDOHolderSaveReply( <grvXMLreq> xmlReq )
handle AJAX event for 'reply received from "save EDOHolder data" server-request' |
static void
|
onEDOHolderSelect( <event> e, <int> selectedHolderIndex )
handle event for 'user selects from the select menu which loads a new EDOHolder' |
static void
|
onEDOInsertBtnPressed()
handle event for 'insert EDO button pressed' |
static void
|
onEDOToggle( <event> e, <EDOIndex> xi )
handle event for 'toggle an EDO' |
// This file uses JSDoc-friendly comments [ http://jsdoc.sourceforge.net/ ] /** * @file grvEDO.js * @fileoverview Collection of Editable Domain Object framework classes. * This library builds on the MVC framework and adds support for EDOs * (Editable Domain Objects) including undo-able select/edit/delete/insert * operations. * * @todo EDO and EDOHolderModel and EDOListModel should be combined * into an EDO that supports the Composite Design Pattern. Of course, to * do this, all of the MVC "Model" family should be reworked to do the same. * The MVC "View" family DOES support Composites but for some reason the * Models didnt start out that way. [...sigh...] * * @author Bruce Wallace (PolyGlotInc.com) * @requires grvMVC.js * @version 2.5 */ ////////////////////////////////////////////////////////////////// // GRAVEY LEXICAL CODING CONVENTIONS: // (*) All private variables or functions start with "_" // (*) All variables and functions start with a lowercase letter // (*) All Classes start with an uppercase letter // (*) All Class methods and instance variables start with lowercase // (*) All Class "static" methods and variables start with uppercase // (*) All constants start with "k" // (*) All global variables start with "g" // (*) All event handler functions start with "on" // // (*) All Gravey utility global variables start with "gGrv" // (*) All Gravey MVC global variables start with "gMVC" // (*) All Gravey EDO global variables start with "gEDO" // (*) All Gravey utility functions start with "grv" // (*) All Gravey MVC functions start with "mvc" // (*) All Gravey MVC event handler functions start with "onMVC" // (*) All Gravey EDO event handler functions start with "onEDO" // (*) All Gravey MVC classes start with "MVC" // (*) All Gravey EDO classes start with "EDO" ////////////////////////////////////////////////////////////////// grvTraceCmp("grvEDO.js: Begin"); //////////////////////////////////////////// /////////// Global Variables /////////////// //////////////////////////////////////////// /** Global Server Error Messages Model */ var gEDOServerError = null; /** Global EDO Selection Model */ var gEDOSelected = null; //new EDOSelectedModel(...); /** Global EDO Holder Model */ var gEDOHolder = null; //new EDOHolderModel(...); /** Global EDO Holder Selector Model */ var gEDOHolderSelected = null; //new EDOHolderSelectionModel(...); /** Initialize EDO Framework global variables. * @param {EDOHolderModel} edoHolder wrapper model for set of EDOs * @param {Function} edoIndexClass class of index used with EDOHolder * @param {Function} edoHolderViewClass "class" of EDOHolderView to use * @param {Function} counterViewClass "class" of EDOCountersView to use * @param {PopupMenuController} optMenuCtrlr optional menu override * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOInitialize ( edoHolder, edoIndexClass, edoHolderViewClass, optCounterViewClass, optMenuCtrlr ) { gEDOHolder = edoHolder; gEDOHolderSelected = edoHolder.model; // DATA MODEL: which "Editable Domain Object" is Selected gEDOSelected = new EDOSelectedModel( gEDOHolder, edoIndexClass ); // DATA MODEL: Server Error Messages gEDOServerError = new MVCScalarModel(); gEDOServerError.setValue(""); if (gGrvTraceMVC) gEDOHolderSelected.model.dumpSubscribers(); if (gGrvTraceMVC) gEDOHolderSelected .dumpSubscribers(); if (gGrvTraceMVC) gEDOHolder .dumpSubscribers(); // DATA VIEW: EDO Framework Application Panel View. gMVCRootView.addSubView( "EDOAppPanel", new EDOAppPanelView( gEDOHolder, edoHolderViewClass, optCounterViewClass, optMenuCtrlr ) ); } //////////////////////////////////////////// //////////// Domain Objects //////////////// //////////////////////////////////////////// Class(EDOIndex,["index into EDO list"]); /** * @class This simple class encapsulates an EDO index to allow more * complex composite indexes to be defined as subclasses. * @extends GrvObject * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOIndex() { /** @param {int} optXI optional "index" of which EDO is selected. * If not specified or if null then this represents "no selection". */ this.konstructor = function( optXI ){ this.xi = optXI===undefined ? null : optXI; } /** return "this" as event handler arg list string @type String */ this.asEventArgs = function(){ return this.xi; } /** return "this" as a description string @type String */ this.asString = function(){ return "EDO["+this.xi+"]"; } /** return whether "this" contains a selection @type boolean */ this.hasSelection = function(){ return this.xi!=null; } /** return whether "this" equals given EDOIndex @type boolean */ this.equals = function(edoIndex){ return this.xi==edoIndex.xi; } } Class(EDO, [ "edo Class","parent holder model", "property values array", "edit Date","edit User","unique Key" ]); /** * @class This class defines a framework for Editable Domain Objects.<p> * Note that subclasses MUST override the {@link #clone} method. * @extends GrvObject * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDO() { // init "static" Class methods/elements if (!EDO.kMsgSep){//keep this line above jsdoc comments! EDO.kMsgSep = "~"; /** message separator character */ } /** * @param {Function} CLAZZ this EDO's "class" * @param {EDOHolderModel} parentHolder holder model containing this * @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 Oracle primary 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 ( CLAZZ, parentHolder, propValues, editDate, editUser, theKey, optEditStatus, optName ){ // immutable instance variables this.clazz = CLAZZ; this.rulez = CLAZZ.EditRules ? CLAZZ.EditRules.join('') : null;//backwards compatibility w/RATS // init fixed instance variables this.holder= parentHolder; this.date = editDate; this.whom = editUser; this.key = theKey; if (optName) this.name = optName; //0=no-change; 1=delete; 2=create; 3=hidden; 4=update this.editStatus = optEditStatus?optEditStatus:0; //display expanded/collapsed this.expanded = true; // define variable instance variables... // each of these has a "validity" attribute associated with it var propNames = CLAZZ.Properties; for (var i=0; i<propNames.length; ++i) this[ propNames[i] ] = propValues ? propValues[i] : ""; } /** return a clone of "this" object. * <p>ABSTRACT: sub classes of EDO should override this.</p> * @type EDO */ this.clone = function() { grvMustOverride("EDO.clone"); /* return new <<your subclass name goes here>>( this.propValues(), this.date, this.whom, this.key, this.editStatus ); */ } /** push into given array the editable property values URI encoded * @return resultant array * @type Array */ this.pushEncodedValues = function( pArray ) { var propz = this.clazz.Properties; for (var i=0; i<propz.length; ++i) pArray.push( encodeURIComponent(this[ propz[i] ]) ); return pArray; } /** push into given array the editable property values * @return resultant array * @type Array */ this.pushValues = function( pArray ) { var propz = this.clazz.Properties; for (var i=0; i<propz.length; ++i) pArray.push( this[ propz[i] ] ); return pArray; } /** convert all property edit rules into "read-only" */ this.makeReadOnly = function() { var N = this.rulez.length; this.rulez = ""; for (var i=0; i<N; ++i) this.rulez += MVCEditRule.kRO; } /** generate array of editable property values @return value array @type Array */ this.propValues = function() { return this.pushValues( new Array() ); } /** return "this" as human-readable string @type String */ this.toString = function() { return this.propValues().join("-"); } /** return the DEFAULT tooltip for "this" @type String * @param {EDOIndex} xi edo index */ this.edoToolTip = function( xi ){ return xi.asString()+" \nState:"+this.state()+" Key="+this.key; } /** return the tooltip for "this" @type String * @param {EDOIndex} xi edo index */ this.toolTip = function( xi ){ return this.edoToolTip( xi ); } /** return whether this EDO has validated data @type boolean */ this.isValid = function() { //if I am deleted then I am not invalid. if ( !this.isActive() ) return true; var propz = this.clazz.Properties; for (var i=0; i<propz.length; ++i) if ( this.getValidity( propz[i] ) ) return false; return true; } /** return the debug details of "this" @type String */ this.dump = function() { var dStr = new Array(); dStr.push( this.clazz.UpdateID+">>>[" ); dStr.push( "date="+this.date ); dStr.push( "whom="+this.whom ); dStr.push( "key ="+this.key ); dStr.push( "edit="+this.editStatus ); var propz = this.clazz.Properties; for (var i=0; i<propz.length; ++i){ var prop = propz[i]; dStr.push( prop +"="+ this[prop] ); } dStr.push( "]<<<"+this.name ); return dStr.join("\n"); } /** return an UpdateItem Message (as a POST argument) * for (just) this particular EDO formatted as:<pre> * "UPDATES={class}~{key}~{action}~{content}~END_UPDATE" * where the fields are defined as follows... * {class} = the entity's type * {key} = the entity's unique key number * {action} = the entity's action code * (encode as strings 'C','D', and 'U' for values create, delete, and update.) * {content}= the EDO's specific content in EDO-specific-format *</pre> * @type String */ this.buildUpdateItemPost = function() { var uFields = new Array(); uFields.push( "UPDATES=" + this.clazz.UpdateID ); uFields.push( this.key ? this.key : "0" ); uFields.push( this.action() ); this.pushUpdateFields( uFields ); uFields.push( "END_UPDATE" ); return uFields.join( EDO.kMsgSep ); } /** push into given array all EDO-specific fields of the UpdateItem message. * This default implementation generates content formatted as<pre> * "{property1}~{property2}~...~{propertyN}~" * where the fields are defined as follows... * {propertyI} = the i-th editable property of this EDO *</pre> * @param {Array} uFields string array containing Update Msg fields */ this.pushUpdateFields = function( uFields ) { this.pushEncodedValues( uFields ); } /** push into given array all AJAX SAVE Post params for this model * @param {Array} posts string array containing POST params */ this.pushPosts = function( posts ) { if (this.inEdit()) posts.push( this.buildUpdateItemPost() ); } /** return the edit/validation rule for the specified property. * If no property is specified then return entire set of rules * for this EDO. Each Rule is one character long. * @see MVCDualStringController * @type String * @param {String} optPropID optional property ID */ this.getEditRule = function( optPropID ) { //if no rules specified then anything goes if (!this.rulez) return MVCEditRule.kEdit; //if optional property ID not specified then return all rules if (grvIsEmpty(optPropID)) return this.rulez; //optional property ID was specified so return specific rule var propz = this.clazz.Properties; for (var i=0; i<propz.length; ++i) if (optPropID==propz[i]) return this.rulez.charAt(i); throw "bad Property ID["+optPropID+"] in getEditRule()"; } /** set the validity code of the specified attribute * @param {String} ID repayment attribute name * @param {String} v validity "code" (actually an error message or null) */ this.setValidity = function(ID,v){ this[ID+MVCScalarModel.kValiditySuffix] = v; } /** return the validity "code" of the specified attribute * @param {String} ID repayment attribute name * @type String */ this.getValidity = function(ID){ return this[ID+MVCScalarModel.kValiditySuffix]; } /** Is it legal to delete "this"? * @return errmsg or null * @type String */ this.canDelete = function(){ if ( this.isActive() ) return null; return "This is already deleted."; } /** mark this EDO as deleted */ this.deleteMe = function(){ this.preDeleteExpand = this.expanded; this.preDeleteStatus = this.editStatus; this.editStatus = this.editStatus==2 ? 3 : 1; this.collapse(); } /** restore this EDO to its pre-deleted state */ this.undeleteMe = function(){ this.editStatus = this.preDeleteStatus; if (this.preDeleteExpand) this.expand(); delete this.preDeleteStatus; delete this.preDeleteExpand; } /** Is it legal to create a new one of "this/these"? * @param {boolean} appendFlag if true then append else insert * @return errmsg or null * @type String */ this.canCreate = function(appendFlag){ return null; }//override me /** If created, can we undo creation? @type boolean * @param {boolean} appendFlag if true then append else insert */ this.canUncreate = function(appendFlag){ return true; }//override me /** mark this entity as being newly added */ this.addMe = function(){ this.editStatus = 2; } /** is this entity newly added? @type boolean */ this.isNew = function(){ return this.editStatus==2; } /** is this entity newly added? @type boolean */ this.isDeleted = function(){ return this.editStatus==1; } /** return whether this entity has been changed since last save @type boolean */ this.inEdit = function(){ return this.editStatus > 0 && this.editStatus!=3; } /** 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 null; return "This is deleted."; } /** mark this entity as having been edited */ this.editMe = function() { this.preExpand = this.expanded; this.preEdit = this.clone();//save previous state this.editStatus = this.editStatus==2 ? 2 : 4; this.expanded = true;//alway expand on edit this.whom = kUserID; this.date = grvGetTodayAsMMDDYYYY(); } /** restore this EDO to its pre-edited state */ this.uneditMe = function() { var propz = this.clazz.Properties; for (var i=0; i<propz.length; ++i){ var prop = propz[i]; this[ prop ] = this.preEdit[ prop ]; } this.date = this.preEdit.date; this.whom = this.preEdit.whom; this.key = this.preEdit.key; this.editStatus = this.preEdit.editStatus; this.expanded = this.preExpand; delete this.preEdit; } /** force this EDO to be collapsed */ this.collapse = function(){ this.expanded=false; } /** force this EDO to be expanded */ this.expand = function(){ this.expanded=true; } /** return whether this EDO is collapsed or open * @return true if open * @type boolean */ this.isExpanded = function(){ return this.expanded; } /** can this EDO toggle the "expanded" flag? @type boolean * @param {boolean} doAllFlag if true, all EDOs are to be set */ this.canToggleExpand = function( doAllFlag ) { return this.isActive(); /* override as needed */ } /** toggle (or set) the "expanded" flag of this EDO. * @param {boolean} optValue if specified, set flag to it, else toggle */ this.toggleExpand = function( optValue ) { if ( this.canToggleExpand() ) this.expanded = (optValue===undefined||optValue==null) ? (!this.expanded) : optValue; } /** Is this EDO active and editable? (i.e not deleted or in limbo) * @return true if active * @type boolean */ this.isActive = function(){ return this.editStatus!=1 && this.editStatus!=3; } /** Is this EDO undead? (i.e in limbo) * @return true if in Limbo * @type boolean */ this.inLimbo = function(){ return this.editStatus==3; } /** return whether this EDO can be viewed if desired @type boolean */ // this.isViewable = function(){ return this.isActive(); } /** return whether this EDO can be viewed if desired @type boolean */ this.isViewable = function(){ return this.isActive() || this.inEdit(); } /** return the formatted version of our edit state @type String */ this.state = function() { switch( this.editStatus ) { case 0: return "Unchanged"; case 1: return "Deleted"; case 2: return "Added"; case 3: return "Limbo"; case 4: return "Updated"; } return "unknown state:["+this.editStatus+"]"; } /** return our edit state translated to a broadcast message code @type String */ this.action = function() { switch( this.editStatus ) { case 1: return "D"; case 2: return "C"; case 4: return "U"; } return ""; } } //////////////////////////////////////////// ///////////////// MODELS /////////////////// //////////////////////////////////////////// Class(EDOListModel,["EDO Class"]).Extends(MVCListModel); /** * @class This class encapsulates a list model for EDOs. * @extends MVCListModel * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOListModel() { /** @param {Function} edoClass the class of the EDO * @param {String} optName optional name of this instance */ this.konstructor = function( edoClass, optName ) { this.souper( optName ); // init instance variables this.itemType = edoClass; } /** return the count of viewable EDOs associated with "this" @type int */ this.getVisibleCount = function() { var count = 0; this.iterate( function(i,edo){ if (edo.isViewable()) ++count; } ); return count; } /** return the count of active EDOs associated with "this" @type int */ this.getActiveCount = function() { var count = 0; this.iterate( function(i,edo){ if (edo.isActive()) ++count; } ); return count; } /** return whether any EDOs are changed for this list @type boolean */ this.isDirty = function(){ var changed = false; this.iterate( function(i,edo){ if (edo.inEdit()) return changed = true; } ); return changed; } /** return whether all EDOs are valid for this model @type boolean */ this.isValid = function(){ var valid = true; this.iterate( function(i,edo){ if (!edo.isValid()){valid = false; return true;} } ); return valid; } /** 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.iterate( function(i,edo){ edo.pushPosts(posts); } ); } /** toggle the "expanded" flag of the EDO. * @param {boolean} newVal value to set all of the EDO flags to */ this.toggleExpandAll = function( newVal ) { this.iterate( function(i,edo){ edo.toggleExpand(newVal); } ); } } Class(EDOHolderModel,["Holder Selection Model","Load XSL DOM","Entity Name"]) .Extends(MVCModel); /** * @class This abstract class encapsulates the functionality of * a data model managing a set of editable domain objects (EDOs). * <ul>The following methods MUST be overridden * <li>{@link #isDirty}</li> * <li>{@link #isValid}</li> * <li>{@link #_resetEDOs}</li> * <li>{@link #keysMatch}</li> * <li>{@link #propMatch}</li> * <li>{@link #hasEDO}</li> * <li>{@link #_newEDO}</li> * <li>{@link #getEDO}</li> * <li>{@link #createEDO}</li> * <li>{@link #appendEDO}</li> * <li>{@link #pushPosts}</li> * <li>{@link #getUpdatedProperty}</li> * <li>{@link #createSelectionItem}</li> *</ul><p> * Second, this model implements the {@link MVCBoolModel#isTrue} * interface where the value reflects whether this model is "dirty". * @extends MVCModel * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 * @see EDOIndex * @see EDOSelectedModel */ function EDOHolderModel() { // init "static" Class methods/elements if (!EDOHolderModel.AjaxRequest){//keep this line above jsdoc comments! /** Make a REST-style AJAX request to the server.</br> * @param {String} theType requested entity name * @param {String} theKey unique key of requested entity * @param {Function} replyHandler reply event handler static function * @param {String} optPostData optional string to pass as POST data * @param {boolean} optWaitFlag optional flag that if true says * call synchronously (i.e. wait for reply) */ EDOHolderModel.AjaxRequest = function( theType, theKey, replyHandler, optPostData, optWaitFlag ) { grvWAIT(); var url = kXMLPath + theType + theKey + ".xml"; if (!_kGrvAjaxTestData) { var requestName = (optPostData?"Update":"GetXML") + theType + "DATA"; var parms = new Array(); parms.push( requestName ); parms.push( 'user=' + grvGetArg("user") ); parms.push( 'testing=' + grvGetArg("testing") ); parms.push( theType.toUpperCase() + '_KEY=' + theKey ); // var requestPrefix = "?CONTROLLER=funb.cat.reconcile.controller."; // var requestPrefix = "?CONTROLLER=funb.cat.bass.controller."; var requestPrefix = "?action="; url = location.pathname + requestPrefix + parms.join("&"); } return new grvXMLreq( url, replyHandler, optPostData, optWaitFlag ); } } /** @param {MVCSelectionModel} holderSelectionModel model of which edoHolderModel is selected * @param {Object} loadXslDOM XSL DOM that transforms newly loaded XML data into "this" * @param {String} entityName entity name of this instance */ this.konstructor = function( holderSelectionModel, loadXslDOM, entityName ) { this.souper( entityName ); // init instance variables this.subscribe( holderSelectionModel ); this.loadXslDOM = loadXslDOM; } /** {@link MVCBoolModel} API: return "I am modified" flag @type boolean */ this.isTrue = function(){ return this.isDirty(); } /** return whether any EDOs are changed for this model @type boolean * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this.isDirty = function() { grvMustOverride("EDOHolderModel.isDirty"); } /** return whether all EDOs are valid for this model @type boolean * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this.isValid = function() { grvMustOverride("EDOHolderModel.isValid"); } /** clear EDOs * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this._resetEDOs = function() { grvMustOverride("EDOHolderModel._resetEDOs"); } /** clear EDOs and update timestamp but dont publish */ this._reset = function(){ this._resetEDOs(); this.updateStamp(); } /** clear list and publish */ this.reset = function(){ this._reset(); this.publish(true); } /** return whether there is currently an EDO @type boolean * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this.hasEDO = function() { grvMustOverride("EDOHolderModel.hasEDO"); } /** return a new blank EDO of the type implied by EDOIndex @type EDO * @param {EDOIndex} xi edo index * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this._newEDO = function(xi) { grvMustOverride("EDOHolderModel._newEDO"); } /** return a new blank EDO of the type implied by EDOIndex @type EDO * @param {EDOIndex} xi edo index */ this.newEDO = function(xi) { var edo = this._newEDO(xi); edo.addMe(); return edo; } /** return reference to the specified editable domain object * @param {EDOIndex} xi edo index * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this.getEDO = function(xi) { grvMustOverride("EDOHolderModel.getEDO"); } /** return the specified EDO with the intent to change its attributes * @type EDO * @param {EDOIndex} xi edo index */ this.openEDO = function(xi){ this.publish(); return this.getEDO(xi); } /** return whether the specified EDO is collapsed or open * @param {EDOIndex} xi edo index * @return true if open * @type boolean */ this.isExpandedEDO = function(xi){ return this.getEDO(xi).isExpanded(); } /** can we toggle the "expanded" flag of the specified EDO? @type boolean * @param {boolean} doAllFlag if true, set all of the EDOs to new value * @param {EDOIndex} xi edo index */ this.canToggleExpand = function( doAllFlag, xi ) { // OVERRIDE TO implement doAllFlag return this.getEDO(xi).canToggleExpand(); } /** toggle the "expanded" flag of the specified EDO. * @param {boolean} doAllFlag if true, set all of the EDOs to new value * @param {EDOIndex} xi edo index */ this.toggleExpand = function( doAllFlag, xi ) { // OVERRIDE TO implement doAllFlag this.getEDO(xi).toggleExpand(); this.updateStamp(); } /** Is it legal to delete selected EDO? * @return errmsg or null * @type String * @param {EDOIndex} xi edo index */ this.canDeleteEDO = function(xi){ return this.getEDO(xi).canDelete(); } /** Is it legal to edit selected EDO? * @return errmsg or null * @type String * @param {EDOIndex} xi edo index */ this.canEditEDO = function(xi){ return this.getEDO(xi).canEdit(); } /** Is it legal to create a new EDO? * @return errmsg or null * @type String * @param {EDOIndex} xi edo index * @param {boolean} appendFlag if true then append else insert */ this.canCreateEDO = function(xi,appendFlag){ var edo = this.getEDO(xi); return edo ? edo.canCreate(appendFlag) : null; } /** If created, can we undo creation? @type boolean * @param {EDOIndex} xi edo index * @param {boolean} appendFlag if true then append else insert */ this.canUncreateEDO = function(xi,appendFlag){ var edo = this.getEDO(xi); return edo ? edo.canUncreate(appendFlag) : true; } /** delete the specified EDO * @param {EDOIndex} xi edo index */ this.deleteEDO = function(xi){ this.openEDO(xi).deleteMe(); } /** undelete the specified EDO * @param {EDOIndex} xi edo index */ this.undeleteEDO = function(xi){ this.openEDO(xi).undeleteMe(); } /** enable editing on the specified EDO * @param {EDOIndex} xi edo index */ this.editEDO = function(xi){ this.openEDO(xi).editMe(); } /** rollback edit on the specified EDO * @param {EDOIndex} xi edo index */ this.uneditEDO = function(xi){ this.openEDO(xi).uneditMe(); } /** create new EDO which is inserted after selected EDO * @return EDOIndex of new EDO * @type EDOIndex * @param {EDOIndex} xi edo index * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this.createEDO = function(xi) { grvMustOverride("EDOHolderModel.createEDO"); } /** create new EDO which is appended at end of EDO list * @return EDOIndex of new EDO * @type EDOIndex * @param {EDOIndex} xi edo index * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this.appendEDO = function(xi) { grvMustOverride("EDOHolderModel.appendEDO"); } /** create a new item for the selection list from current EDO * @type EDOHolderSelectionItem * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this.createSelectionItem = function() { grvMustOverride("EDOHolderModel.createSelectionItem"); } /** return the updated properties from the current EDO needed for select list update * @return arbitrary value as needed @type Object * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this.getUpdatedProperty = function() { grvMustOverride("EDOHolderModel.getUpdatedProperty"); } /** handle CRUD event: "just created EDOHolder" */ this.justCreated = function(){ this.model.createSelection( this.createSelectionItem() ); } /** handle CRUD event: "just updated EDOHolder" */ this.justUpdated = function() { this.model.updateSelection( this.getUpdatedProperty() ); } /** handle CRUD event: "just deleted EDOHolder" */ this.justDeleted = function() { this.model.deleteSelection( true ); } /** handle CRUD event: "just loaded EDOHolder" */ this.justRead = function(){ /* do nothing special */ } /** return whether current EDO matches selection item "key" * @type boolean * @param {EDOHolderSelectionItem} item selection menu item * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this.keysMatch = function(item) { grvMustOverride("EDOHolderModel.keysMatch"); } /** return whether current EDO matches selection item "properties" * @type boolean * @param {EDOHolderSelectionItem} item selection menu item * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this.propMatch = function(item) { grvMustOverride("EDOHolderModel.propMatch"); } /** return the type of CRUD event that caused EDOHolder reload. * @type String * @return type of CRUD event encoded as char 'C' or 'R' or 'U' or 'D' */ this.getCRUDtype = function() { var listEmpty = (this.model.getCount()<1); var hasSelection= listEmpty ? false : this.model.hasSelection(); if (this.hasEDO()) { if (listEmpty) return 'C'; grvASSERT(hasSelection,"menu list exists with no selection"); var selection = this.model.getSelection(); var keysMatch = this.keysMatch(selection); var propMatch = this.propMatch(selection); if (keysMatch) return propMatch ? 'R' : 'U'; grvASSERT(!propMatch,"EDO was saved with duplicate Properties"); return 'C'; } else { if (listEmpty) return 'R'; grvASSERT(hasSelection,"menu list exists with no selection"); return 'D'; } } /** handle "EDOHolder reloaded" event. */ this.reloaded = function() { if (gGrvTraceEvt) grvDebugWindow( this.dump() );//look at the updated data // HACK: this normally should have been accomplished via // subscriptions, but it would have set up a circular dependency. switch( this.getCRUDtype() ) { case 'C': this.justCreated(); break; case 'R': this.justRead(); break; case 'U': this.justUpdated(); break; case 'D': this.justDeleted(); break; default: grvError("bad CRUD code"); } // grvUNWAIT(); } /** Make a Load-Data request to the AJAX server. * @param {Object} edoHolderSelected selected item in observed model */ this.requestLoad = function( edoHolderSelected ){ //Note: nothing selected when a new EDO is needed if (edoHolderSelected) EDOHolderModel.AjaxRequest( this.name, edoHolderSelected.key, onEDOHolderLoadReply ); } /** Make a Save-Data request to the AJAX server. * @param {Object} edoHolderSelected selected item in observed model * @param {String} updates string of EDO update POSTs */ this.requestSave = function( edoHolderSelected, updates ){ //Note: nothing selected when saving new EDO var theKey = edoHolderSelected ? edoHolderSelected.key : null; EDOHolderModel.AjaxRequest( this.name, theKey, onEDOHolderSaveReply, updates ); } /** push into given array all AJAX SAVE Post params for this model * @param {Array} posts string array containing POST params * <p>ABSTRACT: sub classes of EDOHolderModel should override this</p> */ this.pushPosts = function( posts ) { grvMustOverride("EDOHolderModel.pushPosts"); } /** handle update events from the EDOHolder Selection Model */ this.update = function() { // clear out old data now so that user doesnt keep seeing // old data while new data is being requested and loaded this.reset(); // TODO make gMVCUndoCmds watch gEDOHolderSelected gMVCUndoCmds.reset();//must reset here because cmds in queue //can refer to EDOs that dont exist //at this point because of this.reset() // request EDOHolder data from server (after small delay) this.requestLoad( this.model.getSelection() ); } /** save all of the edits into the database via service layer */ this.save = function() { var postArgs = new Array(); postArgs.push( "USER_ID=" + kUserID ); this.pushPosts( postArgs ); // immediate invocation of AJAX request with asynch reply handling this.requestSave( this.model.getSelection(), postArgs.join('&') ); } } Class(EDOSelectedModel,["EDO Holder model","EDO Index Class"]) .Extends(MVCBoolModel); /** * @class This class encapsulates the data model for the flag * indicating whether an editable domain object (EDO) is selected * from a set of EDOs in an EDOHolderModel. One and only one * EDO can be selected at a time. This model also keeps track * of which EDO is selected. * If a new EDOHolder is selected (thus loading new data) * "this" gets reset to false (i.e nothing selected). * @extends MVCBoolModel * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOSelectedModel() { /** @param {EDOHolderModel} edoHolder model containing EDO set * @param {Function} edoIndexClass the class/function of the EDOIndex to use * @param {String} optName optional name of this instance */ this.konstructor = function( edoHolderModel, edoIndexClass, optName ) { this.souper( optName ? optName : "EDOSelected Flag" ); // init instance variables this.subscribe( edoHolderModel.model ); this.edoHolder = edoHolderModel; this.xiClass = edoIndexClass; this._unselect(); } /** return whether an EDO is selected @type boolean */ this.hasSelection = function(){ return this.xi.hasSelection(); } /** return the selected EDO or null if none selected @type EDO */ this.getSelected = function(){ if ( !this.hasSelection() ) return null; return this.edoHolder.getEDO( this.xi ); } /** return the specified EDO (or current selection if not specified) @type EDO * @param {EDOIndex} optXI optional edo index */ this.getEDO = function(optXI) { return optXI ? this.edoHolder.getEDO(optXI) : this.getSelected(); } /** return the selected EDOIndex @type EDOIndex */ this.getIndex = function(){ return this.xi; } /** force the "something is selected" flag to specified value and publish */ this.forceFlag = function(f){ this.setFlag(f); } /** change to "nothing selected" */ this._unselect = function(){ this._select( new this.xiClass() ); } /** {@link #_unselect} and publish */ this.unselect = function(){ this._unselect(); this.publish(); } /** handle update events from the EDOHolder Selection Model */ this.update = function(){ /*if (this.model.hasChanged)*/ this.unselect(); } /** select the specified EDO * @param {EDOIndex} edoIndex edo index */ this._select = function( edoIndex ) { this.xi = edoIndex; this._setValue( this.hasSelection() ); } /** select (and publish) the specified EDO * @param {EDOIndex} xi edo index */ this.select = function(xi){ this._select(xi); this.publish(); } /** return whether specified EDO is selected @type boolean * @param {EDOIndex} edoIndex edo index */ this.isSelected = function( edoIndex ) { return this.xi.equals(edoIndex); } /** Make the specified EDO selected, unless it is * currently selected then merely deselect it. * @param {EDOIndex} xi edo index */ this.toggleSelect = function(xi) { if ( this.isSelected(xi) ) this.unselect(); else this.select(xi); } /** Is it legal to delete selected EDO? @return errmsg or null @type String */ this.canDeleteSelected = function() { return this.edoHolder.canDeleteEDO( this.xi ); } /** Is it legal to edit selected EDO? @return errmsg or null @type String */ this.canEditSelected = function() { return this.canEdit( this.xi ); } /** Is it legal to edit specified EDO? @return errmsg or null @type String * @param {EDOIndex} xi edo index */ this.canEdit = function(xi) { return this.edoHolder.canEditEDO( xi ); } /** Is it legal to create selected EDO? @return errmsg or null @type String * @param {boolean} appendFlag iff true this is an append else insert * @param {EDOIndex} optIndex optional index to use */ this.canCreateSelected = function(appendFlag,optIndex) { return this.edoHolder.canCreateEDO( optIndex?optIndex:this.xi, appendFlag ); } /** If created, can we undo creation? @type boolean * @param {boolean} appendFlag iff true this is an append else insert * @param {EDOIndex} optIndex optional index to use */ this.canUncreateSelected = function(appendFlag,optIndex) { return this.edoHolder.canUncreateEDO( optIndex?optIndex:this.xi, appendFlag ); } /** delete selected editable domain object */ this.deleteSelected = function() { this.edoHolder.deleteEDO( this.xi ); this.unselect(); } /** undelete specified editable domain object * @param {EDOIndex} xi edo index */ this.undelete = function(xi) { this.edoHolder.undeleteEDO(xi); } /** edit selected editable domain object */ this.editSelected = function() { this.edoHolder.editEDO( this.xi ); } /** return whether specified editable is in edit mode @type boolean * @param {EDOIndex} optXI optional edo index */ this.inEdit = function(optXI) { var selected = this.getEDO(optXI); return selected==null ? false : selected.inEdit(); } /** unedit selected editable */ this.uneditSelected = function() { this.edoHolder.uneditEDO( this.xi ); } /** insert new EDO after selected EDO and select it */ this.newAfterSelected = function() { this.select( this.edoHolder.createEDO( this.xi ) ); } /** insert new EDO at end of EDO list and select it * @param {EDOIndex} xi edo index */ this.appendSelected = function( xi ) { this.select( this.edoHolder.appendEDO( xi ) ); } } Class(EDOHolderSelectionItem); /** * @class This class defines the interface expected for items appearing in * the list model watched by {@link EDOHolderSelectionModel}. * This class implements the {@link MVCMenuItem} interface. * @extends GrvObject * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOHolderSelectionItem() { /** quietly update the specified attributes * @param {Object} args arbitrary list of args as needed * <p>ABSTRACT: sub classes of EDOHolderSelectionItem should override this</p> */ this.updateProperties = function( args ) { grvMustOverride("EDOHolderSelectionItem.updateProperties"); } /** return "this" formatted for menu item @type String * <p>ABSTRACT: sub classes of EDOHolderSelectionItem should override this</p> */ this.getDescription = function() { grvMustOverride("MenuItem.getDescription"); } } Class(EDOHolderSelectionModel,["EDOHolderSelectionItem List Model"]) .Extends(MVCSelectionModel); /** * @class This class encapsulates the data model for * "which EDOHolder is currently selected" from list of {@link EDOHolderSelectionItem}. * @extends MVCSelectionModel * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOHolderSelectionModel() { /** @param {MVCListModel} listModel list of main menu items * @param {String} optName optional name of this instance */ this.konstructor = function( listModel, optName ){ this.souper( listModel, optName ); } /** Select the "initially selected" EDOHolder. * This is intended to be overridden. * @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 ) { if (this.model && this.model.getCount()>0) { if ( selectFirst ) this.select( 0 ); } else this.selectNothing(); //NO DATA IN MENU LIST!! } /** quietly update the specified attributes of the selected item * @param {Object} args arbitrary list of args as needed */ this.updateSelection = function( args ) { // we jump thru hoops here to get observers/watchers to notice // that the listModel item has changed but not think that // "which item is selected" has changed (which would trigger // reloading already-loaded EDOHolder data). this.getSelection().updateProperties( args ); this.updateStamp(); // this.publish(true); } /** quietly delete the selected item from the parent list * @param {boolean} selectFirst if true select first item in list */ this.deleteSelection = function( selectFirst ) { this.model._del( this.getIndex() ); if (selectFirst) this.select(0,true); } /** quietly append the given item into the parent list and select it * @param {EDOHolderSelectionItem} item list item to append/select */ this.createSelection = function( item ) { // we jump thru hoops here to get observers/watchers to notice // that the listModel has changed but not think that // "which item is selected" has changed (which would trigger // reloading already-loaded EDOHolder data). this._select( this.model._push( item ) ); this.updateStamp(); } } //////////////////////////////////////////// ///////////////// VIEWS /////////////////// //////////////////////////////////////////// Class(EDOListView,["EDO ListModel","EDO View Class"]) .Extends(MVCListView); /** * @class This class produces a view of a List of EDOs. * @extends MVCListView * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOListView() { /** @param {EDOListModel} edoListModel EDO list we are to observe * @param {Function} edoViewClass View Class for individual EDOs */ this.konstructor = function( edoListModel, edoViewClass ) { this.souper(); // init instance variables this.itemView = edoViewClass; this.watchModel( edoListModel ); } this.currentContext = function() { return new MVCContext( this.model ? this.model.getActiveCount() : 0 ); } /** return the EDOIndex appropriate for the given list index and EDO type. * <p>ABSTRACT: sub classes of EDOListView should override this.</p> * @param {int} index index into ListModel * @type EDOIndex */ this.itemEDOIndex = function( index ) { return new EDOIndex(index); } this.itemHTMLstr = function( index, item, itemID ) { var HTML = new Array(); var xi = this.itemEDOIndex( index ); HTML.push( this.embedHTML( itemID, new this.itemView(item,xi) ) ); return HTML.join(''); } this.headHTMLstr = function() { if (this.model && this.model.getVisibleCount()>0) return ""; return EDOView.ShellHTML( this.itemEDOIndex(0), this.model.itemType ); } } Class(EDOView,["EDO object","EDO index object","inner view"]) .Extends(MVCView); /** * @class This abstract class produces a view of an {@link EDO}. * Subclasses should override {@link #buildFields}. * @extends MVCView * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.5 */ function EDOView() { // init "static" Class methods/elements if (!EDOView.ShellHTML) {//keep this line above jsdoc comments! EDOView.kImgExpanded = 'expandedX.gif'; EDOView.kImgCollapsed = 'collapsedX.gif'; /** Static method to generate the shell HTML for given future EDO. * @param {EDOIndex} xi index of EDO * @param {Function} itemClazz "class" of EDO */ EDOView.ShellHTML = function( xi, EDOclazz ) { if (kReadOnly) return ""; var title = "Create New " + EDOView.Title( EDOclazz ); var evtHandlerStr = "onEDOAddClick(event,"+ xi.asEventArgs() +")"; var HTML = new Array(); HTML.push( '<tr><td><fieldset class="edoFieldset">' ); HTML.push( '<legend class="edoFieldsetLegend">' ); HTML.push( '<span class="edoFieldsetLegendTitleSpan" onclick="'+evtHandlerStr+'">'+title+'</span></legend>' ); HTML.push( ' ' ); HTML.push( "</fieldset></td></tr>" ); return HTML.join(''); } EDOView.Title = function( EDOclazz ){ return EDOclazz.Title ? EDOclazz.Title : EDOclazz.UpdateID; } } /** @param {EDO} edo EDO we are to observe * @param {EDOIndex} edoIndex composite EDO index */ this.konstructor = function( edo, edoIndex, innerView ) { this.souper(); // init instance variables this.xi = edoIndex; this.watchModel( edo ); this.inner = innerView; } /** return the view ID of our clickable panel @type String */ this.clickID = function(){ return this.getWidgetID() + ".clik"; } /** return the view ID of our set of attribute fields @type String */ this.innerID = function(){ return this.getWidgetID() + ".attr"; } /** set the "can edit" status of the specified attribute * @param {boolean} enableEdit if true enable editor else viewer * @param {String} attrID object element name specifying desired attribute */ this.updateEditMode = function( enableEdit, attrID ) { var dual = this[ attrID ];//originally set in embedAttr() if (dual) dual.setEditMode( this.model.getEditRule(attrID), enableEdit ); } /** * Select the value of the given attribute into the given select model. * Since global shared menu data models are just temp utility models, * shared by all menu instances, we must manually set each to the * current value of the REAL data model (iff this is the ONE * AND ONLY currently-being-edited EDO). In other words, this * trick of sharing a single data model is possible because we * only allow one menu of this type to be editable at a time. * @param {MVCSelectionModel} selectModel the shared menu model * @param {String} attrID object element name specifying desired attribute */ this.cascadedMenuSelect = function(selectModel,attrID) { this[attrID].editor.watchModel( selectModel ); selectModel._select( this.model[ attrID ], true ); // selectModel._select( this.model[ attrID ] ); // selectModel._setValue( this.model[ attrID ] ); // this[attrID].setModels( this.model[ attrID ] ); } /** * Select the value of the given attribute into the given select model. * Since global shared menu data models are just temp utility models, * shared by all menu instances, we must manually set each to the * current value of the REAL data model (iff this is the ONE * AND ONLY currently-being-edited EDO). In other words, this * trick of sharing a single data model is possible because we * only allow one menu of this type to be editable at a time. * @param {MVCSelectionModel} selectModel the shared menu model * @param {String} attrID object element name specifying desired attribute */ this.sharedMenuSelect = function(selectModel,attrID) { selectModel._select( this.model[ attrID ], true ); } this.preSelect = function(edo){ return; /*override as needed*/ } this.paintHTML = function() { var widget = this.getWidget(); if (!widget) {grvError("no["+this.getWidgetID()+"]");return;} var edo = this.model; var isSelected = gEDOSelected.isSelected( this.xi ); var isDirty = edo && edo.inEdit(); var isBeingEdited = isSelected && isDirty; var isVisible = edo && edo.isViewable(); this.setVisible( isVisible ); if ( isVisible ) { widget.title = edo.toolTip( this.xi ); grvSelectElem( widget, isSelected, kReadOnly ? kROUnselectedColor : kUnSelectedColor ); if (edo.expanded) { this.setSubViewsVisible(true); if (isBeingEdited) this.preSelect(); } else { this.setSubViewsVisible(false); grvSetVisibility( this.innerID(), false ); } //set the edit rule for each attribute var propz = edo.clazz.Properties; for (var i=0; i<propz.length; ++i) this.updateEditMode( isBeingEdited, propz[i] ); grvEditElem( grvGetHook(this.clickID()), isSelected, isDirty, !edo.isValid(), kColorDaffodil ); } } this.currentContext = function(){ return new MVCContext( this.model ); } this.fieldWrapper = function( dual,f,newrow,optSpan ){ var colSpan = optSpan ? (' colspan="'+optSpan+'"') : ''; var s = '<td'+colSpan+' class="edoInnerTD">' +'<label class="edoFieldlabel">'+f+'</label><br/>'+dual+' </td>'; return s + (newrow?'</tr><tr class="edoInnerTR">':''); } this.buildNulField = function( newrow, optSpan ){ var colSpan = optSpan ? (' colspan="'+optSpan+'"') : ''; var s = '<td'+colSpan+' class="edoBlankInnerTD"><br/> </td>'; return s + (newrow?'</tr><tr class="edoBlankInnerTR">':''); } this.buildTxtField = function( f,rows,cols,max,newrow,optSpan ){ var dual = mvcEmbedTextDualEditor( this, f, rows, cols, max, 'edoFieldStrVal' ); return this.fieldWrapper(dual,f,newrow,optSpan); } this.buildYN_Field = function( f,newrow,optSpan ){ var dual = mvcEmbedBoolDualEditor( this, f, 5, 'edoFieldStrVal' ); return this.fieldWrapper(dual,f,newrow,optSpan); } this.buildBoxField = function( f,newrow,optSpan ){ var dual = mvcEmbedChkBoxDualEditor( this, f, 5, 'edoFieldStrVal' ); return this.fieldWrapper(dual,f,newrow,optSpan); } this.buildStrField = function( f,min,max,newrow,optSpan ){ var dual = mvcEmbedStringDualEditor( this, f, min, max, 'edoFieldStrVal' ); return this.fieldWrapper(dual,f,newrow,optSpan); } this.buildPopField = function( f,newrow,listModel,optSpan,optEvtHandlerName,optInitDesc ){ var dual = mvcEmbedDualMenu( this, f, listModel, 'edoFieldPopVal',optEvtHandlerName,optInitDesc ); return this.fieldWrapper(dual,f,newrow,optSpan); } this.buildUprField = function( f,min,max,newrow,optSpan ){ var dual = mvcEmbedStringDualEditor( this, f, min, max, 'edoFieldStrVal', grvUpperKeyFilter ); return this.fieldWrapper(dual,f,newrow,optSpan); } this.buildDayField = function( f,newrow,optSpan ){ var dual = mvcEmbedDateDualEditor( this, f, 'edoFieldStrVal' ); return this.fieldWrapper(dual,f,newrow,optSpan); } this.buildAmtField = function( f,newrow,optSpan ){ var dual = mvcEmbedDollarDualEditor( this, f, 'edoFieldAmtVal',grvFormatDollar ); return this.fieldWrapper(dual,f,newrow,optSpan); } this.buildPctField = function( f,newrow,optSpan ){ var dual = mvcEmbedDollarDualEditor( this, f, 'edoFieldPctVal',grvFormatPercent ); return this.fieldWrapper(dual,f,newrow,optSpan); } /** push into given array the HTML needed for all EDO fields * <p>ABSTRACT: sub classes of EDOView should override this</p> */ this.buildFields = function( HTML ) { grvMustOverride("EDOView.buildFields"); } this.buildToggle = function() { var img = grvIs_IE_Pre7() ? this.model.isExpanded() ? "<font face='Wingdings'>Ú</font>" : "<font face='Wingdings'>Ø</font>" : this.model.isExpanded() ? "▼" : "►"; return '<span title="Click to Toggle; Ctrl-Click to toggle all." onclick="' +this.buildToggleEvent()+'">'+img+' </span>'; } this.buildTitle = function(){ var edo = this.model; var title = EDOView.Title( edo.clazz ); if (!edo.isExpanded()){ var suffix = edo.toString(); if ( grvIsEmpty(suffix) ) suffix = edo.toolTip( this.xi ); else if (edo.inEdit()) suffix += (" (Status:"+edo.state()+")"); title += (": "+suffix); } return '<fieldset class="edoFieldset" id="'+this.getWidgetID()+'">' +'<legend class="edoFieldsetLegend" id="'+this.clickID()+'">' + this.buildToggle() +'<span class="edoFieldsetLegendTitleSpan" onclick="'+this.buildClickEvent()+'">'+title+'</span></legend>'; } this.buildClickEvent = function(){ return "onEDOClick(event, "+ this.xi.asEventArgs() +")"; } this.buildToggleEvent = function(){ return "onEDOToggle(event, "+ this.xi.asEventArgs() +")"; } this.buildHTMLstr = function() { var vwID = this.getWidgetID(); var HTML = new Array(); HTML.push( '<tr><td>' ); HTML.push( this.buildTitle() ); HTML.push( '<table id="' + this.innerID()+ '" cellspacing=5 class="edoInnerTABLE"><tr class="edoInnerTR">' ); if (this.model.isExpanded()) this.buildFields( HTML ); HTML.push( "</tr></table></fieldset></td></tr>" ); return HTML.join(''); } } Class(EDOHolderView,["EDOHolderModel"]) .Extends(MVCView); /** * @class This class produces the view of an EDOHolderModel. * @extends MVCView * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOHolderView() { /** @param {EDOHolderModel} edoHolderModel EDOHolderModel we are to observe */ this.konstructor = function( edoHolderModel ) { this.souper("Main Data Panel View"); // init instance variables this.watchModel( edoHolderModel ); } this.currentContext = function(){ return new MVCContext( this.model.timestamp ); } /** push into given array the HTML needed for all EDOs in holder * <p>ABSTRACT: sub classes of EDOHolderView should override this</p> */ this.buildFields = function( HTML ) { grvMustOverride("EDOHolderView.buildFields"); } this.buildHTMLstr = function() { var vwID = this.getWidgetID(); var HTML = new Array(30); var clas = "edoDatapanel" + (kReadOnly ? "RO" : ""); HTML.push( '<table class="'+clas+'" cellpadding="5" cellspacing="0" width="100%">' ); this.buildFields( HTML ); HTML.push( '</table>' ); return HTML.join(''); } } Class(EDOCountersView,["EDOHolder Selection Model"]) .Extends(MVCView); /** * @class This class produces a view of the current selection * and total size of a selection model (ie "I of N"). * @extends MVCView * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOCountersView() { /** @param {EDOHolderSelectionModel} sModel selection model */ this.konstructor = function( sModel ) { this.souper(); // init instance variables this.watchModel( sModel ); } this.currentContext = function(){ return new MVCContext( this.model.timestamp ); } this.buildHTMLstr = function(){ var sModel = this.model; var x = sModel.hasSelection() ? (sModel.getIndex()+1) : 0; return sModel.name+x+" of "+sModel.getCount(); } } Class(EDOControlPanelView,["EDOHolder data model"]) .Extends(MVCView); /** * @class This class produces the view of the top control panel. * @extends MVCView * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOControlPanelView() { // init "static" Class methods/elements if (!EDOControlPanelView.kImgBtnSave){//keep this line above jsdoc comments! EDOControlPanelView.kImgBtnSave = 'save.gif'; EDOControlPanelView.kImgBtnCancel = 'cancel.gif'; EDOControlPanelView.kImgBtnDelete = 'delete.gif'; EDOControlPanelView.kImgBtnEdit = 'edit.gif'; EDOControlPanelView.kImgBtnExit = 'exit.gif'; EDOControlPanelView.kImgBtnInsert = 'insert.gif'; EDOControlPanelView.kImgBtnUndo = 'undo.gif'; EDOControlPanelView.kImgBtnRedo = 'redo.gif'; } /** @param {EDOHolderModel} edoHolderModel EDOHolder we are to observe * @param {Function} optCounterViewClass optional "class" of CountersView to use * @param {MVCPopupMenuController} optMenuCtrlr optional menu override */ this.konstructor = function( edoHolderModel, optCounterViewClass, optMenuCtrlr ) { this.souper("Main Control Panel View"); // init instance variables this.watchModel( edoHolderModel ); this.cntrPanelClass = optCounterViewClass; this.optMenuOveride = optMenuCtrlr; } this.buildHTMLstr = function() { var vwID = this.getWidgetID(); var HTML = new Array(30); HTML.push('<table class="edoControlPanel"><tr>'); //SAVE BTNS PANEL HTML.push( '<td>' ); HTML.push( this.embedHTML( vwID+".save", new MVCFormButtonController( "Save", "Save changes", "onEDOHolderSaveBtnPressed", this.model, "Save" ) ) ); HTML.push( this.embedHTML( vwID+".cancel", new MVCFormButtonController( "Cancel", "Cancel changes", "onEDOHolderCancelBtnPressed", this.model, "Cancel" ) ) ); HTML.push( this.embedHTML( vwID+".exit", new MVCFormButtonController( "Exit", "Exit "+kAppName, "onEDOHolderExitBtnPressed", null, "Exit" ) ) ); HTML.push( '</td>' ); //UNDO BTNS PANEL HTML.push( '<td>' ); HTML.push( this.embedHTML( vwID+".undo", new MVCCmdButtonController( true ) ) ); HTML.push( this.embedHTML( vwID+".redo", new MVCCmdButtonController( false ) ) ); HTML.push( '</td>' ); //EDIT BTNS PANEL HTML.push( '<td>' ); HTML.push( this.embedHTML( vwID+".delete", new EDOButtonController( "Delete", "Delete Selected Item", "onEDODeleteBtnPressed", gEDOSelected, kReadOnly, "Delete" ) ) ); HTML.push( this.embedHTML( vwID+".edit", new EDOButtonController( "Edit", "Edit Selected Item", "onEDOEditBtnPressed", gEDOSelected, kReadOnly, "Edit", true ) ) ); HTML.push( this.embedHTML( vwID+".insert", new EDOButtonController( "Insert", "Insert Item", "onEDOInsertBtnPressed", gEDOSelected, kReadOnly, "Insert" ) ) ); HTML.push( '</td>' ); //TOP MENU PANEL HTML.push( '<td align="center" nowrap="nowrap">' ); HTML.push( this.embedHTML( vwID+".topMenu", ( this.optMenuOveride ? this.optMenuOveride : new EDOHolderSelectMenuController("top menu") ) ) ); HTML.push( '</td>' ); //COUNTERS PANEL HTML.push( '<td>' ); //sneaky...add a debug controller wrapper HTML.push( '<span>' ); HTML.push( this.embedHTML( vwID+".counter", ( this.cntrPanelClass ? this.cntrPanelClass : new EDOCountersView( this.model.model ) ) ) ); HTML.push( '</span></td>' ); HTML.push( '</tr></table>' ); return HTML.join(''); } } Class(EDOAppPanelView,["EDOHolderModel","EDOHolderView Class"]) .Extends(MVCView); /** * @class This class produces the view of the entire application page. * @extends MVCView * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOAppPanelView() { /** @param {EDOHolderModel} edoHolderModel EDOHolder we are to observe * @param {Function} edoHolderViewClass "class" of EDOHolderView to use * @param {Function} optCounterViewClass optional "class" of EDOCountersView to use * @param {MVCPopupMenuController} optMenuCtrlr optional menu override */ this.konstructor = function( edoHolderModel, edoHolderViewClass, optCounterViewClass, optMenuCtrlr ) { this.souper("EDOAppPageView"); // init instance variables this.watchModel( edoHolderModel ); this.cntrPanelClass = optCounterViewClass; this.optMenuOveride = optMenuCtrlr; this.dataPanelClass = edoHolderViewClass; } this.buildHTMLstr = function() { var vwID = this.getWidgetID(); var HTML = new Array(100); document.body.className = kReadOnly ? "body-readonly" : "body-readwrite"; // HTML.push( '<body bgcolor="red" onLoad="onEDOHolderPageLoad()" onbeforeUnload="onEDOHolderPageBeforeUnLoad()" onKeyPress="onMVCGlobalKeyPress()">' ); HTML.push( '<form method="POST" onsubmit="return false" action="foo">' );//WHY IS THIS NEEDED? HTML.push( this.embedHTML( vwID+".ctrl", new EDOControlPanelView( this.model, this.cntrPanelClass, this.optMenuOveride ) ) ); /* UNCOMMENT THIS TO SEE HOW UI COMPARES TO STD WINDOW SIZES */ // HTML.push( mvcREDSPACER600() + "<br/>" + mvcREDSPACER768() ); HTML.push( '<div style="width:100%; ">' ); HTML.push( this.embedHTML( vwID+".err", new MVCScalarView( gEDOServerError, grvFormatErrorStr, "Server Error View" ) ) ); HTML.push( '</div>' ); <!-- DATA PANEL --> HTML.push( '<div style="width:100%; "' + 'style="overflow-x:auto; overflow-y:auto; width:100%; height:expression(document.body.clientHeight-80);">' ); HTML.push( this.embedHTML( vwID+".data", new this.dataPanelClass( this.model ) ) ); HTML.push( '</div>' ); HTML.push( '</form>' ); // HTML.push( '</body>' ); return HTML.join(''); } } //////////////////////////////////////////// ////////////// Controllers ///////////////// //////////////////////////////////////////// Class(EDOButtonController,["button image filename", "descriptive text", "event handler","enable model","readonly flag"]) .Extends(MVCFormButtonController); /** * @class This class is a button controller for EDO "edit" buttons * which shouldn't be enabled while app is in "read only" mode. * @extends MVCFormButtonController * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOButtonController() { /** * @param {String} label label of the button * @param {EDOSelectedModel} enableModel "is enabled" data model * @param {String} evtHandlerName name of event handler function * @param {String} desc tooltip description for this button * @param {boolean} roFlag read-only mode flag * @param {String} optName optional name of this instance * @param {boolean} optIsEdit editor flag says dont enable if already editing */ this.konstructor = function ( label, desc, evtHandler, enableModel, roFlag, optName, optIsEdit ) { this.souper( label, desc, evtHandler, enableModel, optName ); this.isEdit = optIsEdit; this.readOnly = roFlag; } /** Return whether this button should be enabled. * If in readonly mode then never enable. * If an entity is selected then enable * UNLESS this is the edit button and we are already editing. * @type boolean */ this.isEnabled = function() { var enabled = this.readOnly ? false : this.model.isTrue(); //anything selected? if (enabled && this.isEdit && this.model.inEdit()) enabled = false; return enabled; } } Class(EDOImgButtonController,["button image filename", "descriptive text", "event handler","enable model","readonly flag"]) .Extends(MVCImgButtonController); /** * @class This class is an MVCImgButtonController for EDO "edit" buttons * which shouldnt be enabled while app is in "read only" mode. * @extends MVCImgButtonController * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOImgButtonController() { /** * @param {EDOSelectedModel} enableModel "is enabled" data model * @param {String} evtHandlerName name of event handler function * @param {String} imgFN filename of the (enabled) button image * @param {String} desc tooltip description for this button * @param {boolean} roFlag read-only mode flag * @param {String} optName optional name of this instance * @param {boolean} optIsEdit editor flag says dont enable if already editing */ this.konstructor = function ( imgFN, desc, evtHandler, enableModel, roFlag, optName, optIsEdit ) { this.souper( imgFN, desc, evtHandler, enableModel, optName ); this.isEdit = optIsEdit; this.readOnly = roFlag; } /** Return whether this button should be enabled. * If in readonly mode then never enable. * If an entity is selected then enable * UNLESS this is the edit button and we are already editing. * @type boolean */ this.isEnabled = function() { var enabled = this.readOnly ? false : this.model.isTrue(); //anything selected? if (enabled && this.isEdit && this.model.inEdit()) enabled = false; //grvTraceMVC("Btn["+this.altText+"].enabled="+enabled); return enabled; } } Class(EDOHolderSelectMenuController) .Extends(MVCPopupMenuController); /** * @class This class manages a popup menu controller for * the Selection List that chooses the current EDOHolder. * @extends MVCPopupMenuController * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.5 */ function EDOHolderSelectMenuController() { /** @param {String} optName optional name of this instance */ this.konstructor = function( optName ) { this.souper( gEDOHolderSelected, optName ); } this.currentContext = function(){ return new MVCContext( this.model.timestamp ); } /** return event handler invocation string specific to this controller @type String */ this.getEvtHandlerStr = function(){ return "onEDOHolderSelect(event,this.value)"; } } //////////////////////////////////////////// //////////////// Commands ////////////////// //////////////////////////////////////////// Class(EDOSuperMenuCmd,["view ID"]).Extends(MVCScalarEditCmd); /** * @class This abstract class is a base for menu commands that affect other EDO attributes. * <ul>The following methods MUST be overridden * <li>{@link #updateEDO}</li> *</ul><p> * @extends MVCScalarEditCmd * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ function EDOSuperMenuCmd() { /** @param {String} viewID viewID of menu generating this event */ this.konstructor = function( viewID ) { this.souper( viewID ); this.edo = this.dual.model.base; this.oldEDO = this.edo.clone(); } /** copy values that can change when menu selection is changed * @param {EDO} exemplar where to copy attributes from * @param {boolean} isRedo redo if true else undo */ this.updateEDO = function( exemplar, isRedo ) { grvMustOverride("EDOSuperMenuCmd.updateEDO"); } /** initialize EDO attributes if needed. */ this.prefillEDO = function(){} this.updateOtherController = function( attrID, value ) { this.dual.parentView[attrID].setModels( value );//HACK!! } this.doit = function(){ this.updateController( this.newValue ); this.prefillEDO(); } this.undo = function(){ this.newEDO = this.edo.clone(); this.updateEDO( this.oldEDO, false ); this.updateController( this.oldValue ); } this.redo = function(){ this.updateEDO( this.newEDO, true ); this.updateController( this.newValue ); } } Class(EDOHolderCloseWindowIfSavedCmd).Extends(MVCCommand); /** * @class This class implements the "close this window * if all EDOs in the global EDOHolder are saved" command. * NOTE: It isnt undoable (because we may close this window!). * @extends MVCCommand * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOHolderCloseWindowIfSavedCmd() { /** @param {String} optName optional name of this instance */ this.konstructor = function( optName ) { this.souper( optName, (gEDOHolder.isDirty() ? "You must Save or Cancel data changes before leaving." : null ) ); this.canUndo = false; } this.doit = function() { if (history.length) history.go(-1); else window.close(); } } Class(EDOHolderCancelAllChangesCmd).Extends(MVCCommand); /** * @class This class implements the "revert" command. * NOTE: It isnt undoable (because we lose all edits!). * @extends MVCCommand * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOHolderCancelAllChangesCmd() { /** @param {String} optName optional name of this instance */ this.konstructor = function( optName ) { this.souper( optName ); this.canUndo = false; if (!confirm("Are you sure you want to cancel all changes since last Save?")) this.state = -1; } //causes reload of original data this.doit = function(){ gEDOHolderSelected.reselect(); } } Class(EDOHolderSaveAllChangesCmd).Extends(MVCCommand); /** * @class This class implements the "save all changes * made to EDOs in the global EDOHolder" command. * NOTE: It isnt undoable (because we lose all edits!). * @extends MVCCommand * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOHolderSaveAllChangesCmd() { /** @param {String} optName optional name of this instance */ this.konstructor = function( optName ) { this.souper( optName, (gEDOHolder.isValid() ? null : "Can't save while any data is invalid." ) ); this.canUndo = false; } this.doit = function() { gEDOSelected.unselect(); gEDOHolder.save();//which implies a reload of data } } Class(EDOHolderSelectCmd,["selected holder Index"]).Extends(MVCCommand); /** * @class This class implements the "select new EDO Holder" command. * NOTE: It isnt undoable (because we lose all edits!). * @extends MVCCommand * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOHolderSelectCmd() { /** @param {Object} selectedHolderIndex index of EDOHolder * @param {String} optName optional name of this instance */ this.konstructor = function( selectedHolderIndex, optName ) { this.souper( optName, (gEDOHolder.isTrue() ? "You must Save or Cancel data changes first." : null ) ); this.theIndex = selectedHolderIndex; this.canUndo = false; } this.doit = function(){ gEDOHolderSelected.select( this.theIndex ); } } Class(EDOHolderSelectInitialCmd).Extends(MVCCommand); /** * @class This class implements the "select initially specified EDOHolder" command. * NOTE: It isnt undoable (because we dont need it to be). * @extends MVCCommand * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOHolderSelectInitialCmd() { /** @param {String} optName optional name of this instance */ this.konstructor = function( optName ){ this.souper( optName ); this.canUndo = false; } this.doit = function(){ gEDOHolderSelected.selectInitial(true); } } Class(EDOHolderLoadReplyCmd,["xml request object"]).Extends(MVCAJAXReplyCmd); /** * @class This Command processes the reply of the "load EDOHolder data" request. * NOTE: It isnt undoable (because we lose all edits!). * @extends MVCAJAXReplyCmd * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOHolderLoadReplyCmd() { /** @param {grvXMLreq} xmlReq the XML request being replied to * @param {String} optName optional name of this instance */ this.konstructor = function( xmlReq, optName ) { this.souper( xmlReq, gEDOHolder.loadXslDOM, optName ); } } /////////////////////////////////////////////////////////////////////// Class(EDOCmd).Extends(MVCCommand); /** * @class This is the abstract base class for EDO commands. * @extends MVCCommand * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOCmd() { /** @param {String} cmdDesc general description of this command * @param {String} optErrMsg if not null then cancel this cmd */ this.konstructor = function( cmdDesc, optErrMsg ){ this.souper( cmdDesc, optErrMsg ); if (optErrMsg) return; //save current EDO selection this.cmdX = this.oldX = gEDOSelected.getIndex(); } /** return details portion of command description @type String */ this.details = function(){ return this.cmdX.asString(); } } Class(EDOToggleSelectCmd,["edo index"]).Extends(EDOCmd); /** * @class This class implements the toggle select EDO cmd. * @extends EDOCmd * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOToggleSelectCmd() { /** @param {boolean} autoEdit if true then automatically put EDO in edit mode * @param {EDOIndex} xi index of EDO to toggle selection */ this.konstructor = function( autoEdit, xi ) { this.souper( "toggle selection"+(autoEdit?" and edit":"") ); this.cmdX = xi; this.doEdit = autoEdit ? this.canEdit() : false; } /** @return true iff we can put selection into edit mode @type boolean */ this.canEdit = function() { //if we are about to "deselect" EDO then we cant edit if ( gEDOSelected.isSelected(this.cmdX) ) return false; //if we are not allowed to edit EDO then we cant edit var err = gEDOSelected.canEdit(this.cmdX); if (err) { alert(err); return false; } //if EDO is already in edit mode then we cant (re)edit if (gEDOSelected.inEdit(this.cmdX)) return false; return true; } this.doit = function() { gEDOSelected.toggleSelect( this.cmdX ); if (this.doEdit) gEDOSelected. editSelected(); } this.undo = function() { if (this.doEdit) gEDOSelected.uneditSelected(); gEDOSelected.toggleSelect( this.oldX ); } } Class(EDOToggleExpandCmd,["toggle all flag","edo index"]).Extends(EDOCmd); /** * @class This class implements the toggle EDO display cmd. * @extends EDOCmd * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOToggleExpandCmd() { /** @param {boolean} toggleAll if true then toggle all EDOs in EDOHolder * @param {EDOIndex} xi index of EDO to toggle collapse */ this.konstructor = function( toggleAll, xi ) { this.souper("toggle display"); if ( gEDOHolder.canToggleExpand( toggleAll, xi ) ) { this.all = toggleAll; this.cmdX = xi; } else this.state = -1; } this.doit = function(){ gEDOHolder.toggleExpand( this.all, this.cmdX ); } this.undo = function(){ this.doit(); } this.details = function(){ return this.all ? "ALL" : this.cmdX.asString(); } } Class(EDOEditCmd).Extends(EDOCmd); /** * @class This class implements the edit EDO cmd. * @extends EDOCmd * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOEditCmd() { this.konstructor = function(){ this.souper("edit selection", gEDOSelected.canEditSelected()); } this.doit = function(){ gEDOSelected. editSelected(); } this.undo = function(){ gEDOSelected.uneditSelected(); } } Class(EDODeleteCmd).Extends(EDOCmd); /** * @class This class implements the delete EDO cmd. * @extends EDOCmd * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDODeleteCmd() { this.konstructor = function(){ this.souper("delete selection", gEDOSelected.canDeleteSelected()); } this.doit = function(){ gEDOSelected.deleteSelected();//leaves nothing selected } this.undo = function(){ gEDOSelected.undelete( this.oldX ); gEDOSelected.select ( this.oldX ); } } Class(EDOCreateCmd,["append flag"]).Extends(EDOCmd); /** * @class This class implements the append and insert EDO cmds. * NOTE: If this is creating a new EDOholder, this command won't * be undoable (because we havent made EDO/EDOholder the same * via the Composite design pattern!). * @extends EDOCmd * @see #konstructor * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function EDOCreateCmd() { //Static "Class" constants EDOCreateCmd.kAppend = true; EDOCreateCmd.kInsert = false; /** @param {boolean} appendFlag if true then append else insert EDO * @param {EDOIndex} optIndex optional index of EDO to insert after */ this.konstructor = function( appendFlag, optIndex ) { var edoSelected = gEDOSelected;//for future un-globaling this.souper((appendFlag?"append":"insert")+" new ", edoSelected.canCreateSelected(appendFlag,optIndex)); if (kReadOnly) grvError("CreateCmd in read-only mode"); this.append = appendFlag; this.cmdX = optIndex ? optIndex : edoSelected.getIndex(); this.canUndo = edoSelected.canUncreateSelected(appendFlag,this.cmdX); } this.doit = function() { //create new EDO if (this.append) gEDOSelected.appendSelected( this.cmdX ); else gEDOSelected.newAfterSelected(); //save new state this.newX = gEDOSelected.getIndex(); } this.undo = function(){ gEDOSelected.deleteSelected(); gEDOSelected.select( this.oldX ); } this.redo = function(){ gEDOSelected.undelete( this.newX ); gEDOSelected.select ( this.newX ); } } //////////////////////////////////////////// ////////// Static Event Handlers /////////// //////////////////////////////////////////// /** handle event for 'click on an EDO Add Button' * @param {event} e browser event * @param {EDOIndex} xi index of EDO to append after * @author Bruce Wallace (PolyGlotInc.com) * @version 2.5 */ function onEDOAddClick( e, xi ){ mvcDoCmd( new EDOCreateCmd( EDOCreateCmd.kAppend, xi ) ); } /** handle event for 'click on an EDO' * @param {event} e browser event * @param {EDOIndex} xi index of EDO clicked * @author Bruce Wallace (PolyGlotInc.com) * @version 2.5 */ function onEDOClick( e, xi ){ var ev = e || window.event; var cmdKey = (typeof ev.metaKey == "undefined") ? false : ev.metaKey; mvcDoCmd( new EDOToggleSelectCmd( ev.ctrlKey || cmdKey, xi ) ); } /** handle event for 'toggle an EDO' * @param {event} e browser event * @param {EDOIndex} xi index of EDO to collapse/expand * @author Bruce Wallace (PolyGlotInc.com) * @version 2.5 */ function onEDOToggle( e, xi ){ var ev = e || window.event; var cmdKey = (typeof ev.metaKey == "undefined") ? false : ev.metaKey; mvcDoCmd( new EDOToggleExpandCmd( ev.ctrlKey || cmdKey, xi ) ); } /** handle event for 'delete EDO button pressed' * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function onEDODeleteBtnPressed(){ mvcDoCmd( new EDODeleteCmd() ); } /** handle event for 'edit EDO button pressed' * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function onEDOEditBtnPressed(){ mvcDoCmd( new EDOEditCmd() ); } /** handle event for 'insert EDO button pressed' * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function onEDOInsertBtnPressed() { // TODO dont insert until fix is found for insert goofing up the // EDO indexes lodged in all those UNDO/REDO command objects!!! // mvcDoCmd( new EDOCreateCmd( EDOCreateCmd.kInsert ) ); mvcDoCmd( new EDOCreateCmd( EDOCreateCmd.kAppend ) ); } /** handle event for 'save button pressed' * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function onEDOHolderSaveBtnPressed(){ mvcDoCmd( new EDOHolderSaveAllChangesCmd() ); } /** handle event for 'cancel button pressed' * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function onEDOHolderCancelBtnPressed(){ mvcDoCmd( new EDOHolderCancelAllChangesCmd() ); } /** handle event for 'exit button pressed' * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function onEDOHolderExitBtnPressed(){ mvcDoCmd( new EDOHolderCloseWindowIfSavedCmd() ); } /** handle event for 'user selects from the select menu * which loads a new EDOHolder' * @param {event} e browser event * @param {int} selectedHolderIndex the new menu-selection * @author Bruce Wallace (PolyGlotInc.com) * @version 2.5 */ function onEDOHolderSelect( e, selectedHolderIndex ){ mvcDoCmd( new EDOHolderSelectCmd( selectedHolderIndex ) ); } /** handle AJAX event for 'reply received from "load EDOHolder data" server-request' * @param {grvXMLreq} xmlReq the XML request being replied to * @author Bruce Wallace (PolyGlotInc.com) * @version 2.5 */ function onEDOHolderLoadReply( xmlReq ){ mvcDoCmd( new EDOHolderLoadReplyCmd( xmlReq ) ); } /** handle AJAX event for 'reply received from "save EDOHolder data" server-request' * @param {grvXMLreq} xmlReq the XML request being replied to * @author Bruce Wallace (PolyGlotInc.com) * @version 2.5 */ function onEDOHolderSaveReply( xmlReq ) { //since we get back official new version of EDOHolder Data, just //do the same thing as asking for data load in the first place! mvcDoCmd( new EDOHolderLoadReplyCmd( xmlReq ) ); } /** handle event for 'entering EDOHolder web page' * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function onEDOHolderPageLoad() { gMVCRootView.enable(); // HACK! windows get goofed up if we dont suppress // the "please wait" window on launch... _gGrvHackStartupInhibitWait = true; mvcDoCmd( new EDOHolderSelectInitialCmd() ); //_gGrvHackStartupInhibitWait = false;//modern browsers are a pain with popups now..retire this technique } /** handle event for 'about to leave EDOHolder web page'; * warn if attempting to leave with unsaved changes in the EDOHolder * @author Bruce Wallace (PolyGlotInc.com) * @version 2.5 */ var _gEDOClosingWindow = true; function onEDOHolderPageBeforeUnLoad() { //This cant be done in a Command since this logic must be completed //by the time that we return. [A Command may be queued and finished //later, and that is out of the callers control.] if (_gEDOClosingWindow) //e.g. calendar window launch { if ( gEDOHolder.isTrue() ) // i.e. unsaved data return "Edits are NOT saved. Are you sure you want to abandon your changes?"; } else _gEDOClosingWindow = true; } grvTraceCmp("grvEDO.js: End");
|
The Gravey 2.5 Framework and AIM RIA | |||||||
| PREV NEXT | FRAMES NO FRAMES | |||||||