You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xap-commits@incubator.apache.org by mt...@apache.org on 2006/08/17 18:36:03 UTC
svn commit: r432327 -
/incubator/xap/trunk/src/xap/bridges/basic/AbstractBlackBoxWidgetBridge.js
Author: mturyn
Date: Thu Aug 17 11:36:03 2006
New Revision: 432327
URL: http://svn.apache.org/viewvc?rev=432327&view=rev
Log:
Improved the jsdoc.
Modified:
incubator/xap/trunk/src/xap/bridges/basic/AbstractBlackBoxWidgetBridge.js
Modified: incubator/xap/trunk/src/xap/bridges/basic/AbstractBlackBoxWidgetBridge.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/bridges/basic/AbstractBlackBoxWidgetBridge.js?rev=432327&r1=432326&r2=432327&view=diff
==============================================================================
--- incubator/xap/trunk/src/xap/bridges/basic/AbstractBlackBoxWidgetBridge.js (original)
+++ incubator/xap/trunk/src/xap/bridges/basic/AbstractBlackBoxWidgetBridge.js Thu Aug 17 11:36:03 2006
@@ -16,33 +16,51 @@
*/
Xap.provide("xap.bridges.basic.AbstractBlackBoxWidgetBridge");
-// Auto-added---o.k.?
-Xap.require("xap.util.Utils");
-// Auto-added---o.k.?
+Xap.require("xap.util.Utils");
Xap.require("xap.util.Exception");
-
Xap.require("xap.util.LogFactory") ;
Xap.require("xap.taghandling.AbstractTagImpl") ;
- /**
- * @fileoverview
+/**
+ * @fileoverview
*
- * A superclass for the bridges controlling a widget peer obeying a limited interface; treat it
- * as an abstract superclass (note that it doesn't implement a couple of methods it requires).
- */
+ *
+ * A class of intended as an abstract superclass for other bridges.
+**/
+
+
+
+ /*
+ * TO_DO: 1.) Find better names for the methods that return DOM nodes (to be used as parents and children), will
+ * need to create one (am currently using getDisplayDomNode() for parent and container, a bad idea.)
+ *.2.) Rename private methods with leading underscores "_".
+ * 3.) Maybe find a better name for this class; the "BlackBox" is there to make a point about avoiding
+ * making direct calls to peer methods from the bridge, but having been made it might be a bit much.
+*/
/**
* Creates a xap.bridges.basic.AbstractBlackBoxWidgetBridge.
*
- *
- * @class xap.bridges.basic.AbstractBlackBoxWidgetBridge is the bridge between an XML element
- * representing a control and a subclass of AbstractBlackBoxWidget. This class
- * is typically not used directly but is extended by other classes
- * for its subclasses.
+ * A subclass of <code>xap.taghandling.AbstractTagImpl</code>
+ * intended as an abstract<code> </code>superclass for the
+ * other bridges. The goal was to create a class that maps out the
+ * behaviors needed by all bridges without fixing them in stone; to that
+ * end there are many calls to methods which are either not implemented
+ * here at all, or are implemented with lowest common denominator
+ * behaviors that might well need overriding or supplementing in
+ * subclasses. It is hoped (and in the case of Dojo, known) that
+ * a similar abstract class can implement toolkit-specific behaviors
+ * that will allow the actual widget bridges themselves to be relatively lightweight.
+ * <br/>
+ *
+ * @constructor
*
* @author mturyn
+ * @see xap.taghandling.AbstractTagImpl
+ * @see xap.session.ClientSession#createInitialDocument
+ * @see xap.bridges.dojo.DojoWidgetBridge
*/
xap.bridges.basic.AbstractBlackBoxWidgetBridge = function() {
xap.taghandling.AbstractTagImpl.call( this );
@@ -57,10 +75,18 @@
/**
* All bridges to should go through these steps:
- *
- * 1: Create or obtain the peer object
- * 2: Handle all the initial attributes
- * 3: Recursively parse the inititial children
+ * <ol>
+ * <li>: Create or obtain the peer object
+ * <li>: Handle all the initial attributes
+ * <li>: Recursively parse the inititial children
+ * </ol>
+* Here we look at the layout rectangle (if any) as defined by the XAL-spec'd <code>{x,y,width,height}</code>
+ * parameters, and add this information to <code>this._creationProperties</code>
+ * for the subclasses to do with as they will. Then <code>createPeer</code>
+ * (see below) and attribute- and children-parsing routines called, but
+ * these latter two shouldn't need to be
+ * changed from their implementations in <code>xap.taghandling.AbstractTagImpl</code>.</li>
+ * @see xap.session.ClientSession#_createInitialDocument
*
**/
xap.bridges.basic.AbstractBlackBoxWidgetBridge.prototype.init = function() {
@@ -90,20 +116,118 @@
}
}
+/**
+ * @private
+ * @static
+ * Reserved word that will equal the result of applying the <code>typeof</code> operator
+ * on a function object.
+**/
xap.bridges.basic.AbstractBlackBoxWidgetBridge.FUNCTION="function" ;
+/**
+ * @private
+ * @static
+ * String marking the beginning of an event method---not perfect, but a 90/10 rule applies.
+**/
xap.bridges.basic.AbstractBlackBoxWidgetBridge.ON="on" ;
+/**
+ * @static
+ * Determines if an object, typically a member on another object, is a function.
+**/
xap.bridges.basic.AbstractBlackBoxWidgetBridge.s_IsFunction = function(aMember){
var typ = typeof aMember ;
var eqq = (typ== xap.bridges.basic.AbstractBlackBoxWidgetBridge.FUNCTION) ;
return eqq ;
}
-
+/**
+ * @private
+ * @static
+ * List of the names of methods any bridge in this class' subtree should have.
+**/
xap.bridges.basic.AbstractBlackBoxWidgetBridge.interfaceMethods =
- {obtainPeer:null,attributeSet:null,getEventTriggers:null,getDisplayDomNode:null,getRootDomNode:null} ;
+ {obtainPeer:null,attributeSet:null,findPeerEvents:null,getDisplayDomNode:null,getRootDomNode:null} ;
+/**
+ * Actually now more like <code>processPeer</code>, since it now
+ * calls <code>obtainPeer</code> to create or find our underlying widget.
+* <ol>
+ * <li><strong>Peer acquisition and layout</strong>: The core of
+ * the
+ * class is in the (now a bit archaicly named) <code>createPeer()</code>.
+ * <ol type="a">
+ * <li>It finds a peer using the method <code>obtainPeer</code>,
+ * whose implementation is left up to the implementing subclass. <br/>
+ * </li>
+ * <li>This tag's
+ * parent's handler is queried for an HTML DOM node within which to place
+ * a node provided by this bridge (example: the parent wrappers a
+ * SplitPane, this bridge controls a button: the parent provides the
+ * pane's "container" node where children will be inserted, and this
+ * bridge provides a node containing the whole button). <br/>
+ * </li>
+ *
+ * <ol>
+ * (Note that the
+ * bridge will only get as much information as it needs from another
+ * bridge, an HTMLElement---it doesn't need to know <u>anything</u>
+ * else about
+ * the parent bridge's peer, and in fact might well not know how to get
+ * a suitable HTML DOM node from that peer, which might be from whatever
+ * vendor or an HTML DOM
+ * node itself.
+ * </ol>
+ * <li>Alternately, a locator attribute in the XAL is queried
+ * via <code>getSpecifiedDisplayNode()</code>,
+ * and that i.d. used to
+ * find
+ * the parent node.</li>
+ * </ol>
+ * </li>
+ * <li><strong>Event handling</strong>: The goal
+ * is to attach one of our events to each of the peer's events. To do this
+ * by default we indulge in reflection, looking for function members of
+ * the peer with names of the form "onXXX"
+ * and creating our own that just call <code>fireEvent("onXXX")</code>,
+ * if it does not already exist---this means
+ * that subclasses that already implement an <code>onFoo</code> will not
+ * have it supplanted by one of these auto-generated ones.
+ * Admittedly, this could fail or produce extraneous events (what if the
+ * peer had a method <code>oneInstance</code>?);
+ * but if this should be a problem for the subclass's peer, the subclass
+ * can override this. Each of our events is connected
+ * to its equivalent on the peer using <code>dojo.event.connect</code>.
+ * Finally, our own <code>_onCommandEvent</code> call is connected to
+ * whichever event the bridge class specifies
+ * with <code>getOnCommandEvent</code>, so a button can ask that <code>onClick</code>
+ * get this
+ * attention, but a calendar <code>onSetDate</code>.</li>
+ * <li><b>Glue and upgrading: </b>
+ * Finally, the
+ * peer is fixed to this bridge using <code>setPeer</code>,
+ * which both sets the <code>_peer</code> member and (in the superclass)
+ * records this bridge as its peer's handler, which can be used later on
+ * to look this bridge up by its peer (e.g., if we interact with a widget,
+ * we can see if it's one of the
+ * ones we're managing, and if so we then can probably do more things with
+ * it than otherwise. In subclasses, this is also the point at which
+ * extra methods may be attached to the peer to make it easier for the
+ * handler to deal with it.<br/>
+ * </li>
+ * <li><b>Attribute handling</b>:
+ * When a XAL attribute is processed, it triggers a call to <code>attributeSet()</code>;
+ * here lowest-common-denominator behavior dominates----for an attribute <code>bar</code>,
+ * we look for a setter <code>setFoo </code>on the peer, and if it
+ * exists call it. In the case of the namespace attribute <code>xmlns
+ * </code>and the event call <code>onCommand()</code> we do something
+ * smarter---apart from these exceptions, anything more interesting and
+ * widget-specific will have to be handled in subclasses.<br/>
+ * </li>
+ * </ol>
+ * @throws xap.util.Exception if the peer is unobtainable, or if the bridge subclass
+ * is missing, or if the supposed parent XapElement or bridge is not one of those.
+**/
xap.bridges.basic.AbstractBlackBoxWidgetBridge.prototype.createPeer = function() {
// Implemented by subclasses---here, we don't care how they get it: with a simple
// constructor, via a database call, using a JSON-encoded object over the fibre,
@@ -142,17 +266,10 @@
xap.bridges.basic.AbstractBlackBoxWidgetBridge.s_log.error("Bogus parent peer:" + parentPeer );
} else {
- // The candy in the middle of the wrapper:
-
- // is this subclass instance "this" an appropriate bridge---does it fit our "interface"?:
-
// A bit of contractual programming---make sure this is a bridge of the sort we can use:
-
if(!this._peer){
throw new xap.util.Exception("Haven't obtained a source object to manage.") ;
}
-
-
for( var meth in xap.bridges.basic.AbstractBlackBoxWidgetBridge.interfaceMethods){
if(!this[meth] ){
throw new xap.util.Exception("Supposed bridge object does not have member \""+ meth+"\".") ;
@@ -162,34 +279,49 @@
}
}
+ // Connects (and if necessary, creates) the bridge events mirroring the peer's.
this.autoAttachBridgeEventsToPeerEvents() ;
+ // Finds and sets the peer's location in the HTML DOM:
this.setHtmlDomLocation(parentPeerDomNode) ;
-
-
}
}
- //Default behaviour:
+/**
+ * Default behaviour: is that the node used to attach this widget as a child of another one
+ * or of a DOM node is the same one that should be used as a container for child nodes or
+ * widgets. Lowest common denominator.
+ **/
xap.bridges.basic.AbstractBlackBoxWidgetBridge.prototype.getDisplayDomNode = function(){
- return this.getRootDomNode() ;
+ return this.getRootDomNode() ;
}
-
-
+/**
+ * @private
+ * A wrapper for firing an <code>onCommand</code> event, here so that we can hook that
+ * up to the peer event specified by <code>getPeerOnCommandEvent</code> q.v..
+ * @see getPeerOnCommandEvent
+**/
xap.bridges.basic.AbstractBlackBoxWidgetBridge.prototype._onCommandEvent = function( event ) {
this.fireEvent("onCommand");
}
-
+/**
+ * The name of the native peer event to attach to our <code>onCommand</code>---it
+ * should be a major event for the peer, like <code>onSelect</code> for a selection box,
+ * or <code>onSliderMoved</code> for a slider.
+**/
xap.bridges.basic.AbstractBlackBoxWidgetBridge.prototype.getPeerOnCommandEvent = function(){
return "onClick" ;
}
-// Closure to create a default event-handling function---is there still a problem
-// (memory leak) with this in IE?
+/**
+ * @private
+ * Closure to create a default event-handling function for one of the peer's---is there still a problem
+ * (memory leak) with this in IE?
+**/
xap.bridges.basic.AbstractBlackBoxWidgetBridge.prototype.getOnXFunction = function(str){
return function(){
return this.fireEvent(str) ;
@@ -198,9 +330,10 @@
/**
- * Default behavior: transfer all "onXXX" methods to the bridge:
+ * Default behavior: mirror all "onXXX" methods on the bridge using <code>fireEvent</code> calls
+ * ---we can change this in subclasses if we don't like it.
**/
-xap.bridges.basic.AbstractBlackBoxWidgetBridge.prototype.getEventTriggers = function () {
+xap.bridges.basic.AbstractBlackBoxWidgetBridge.prototype.findPeerEvents= function () {
if(! this.eventTriggers ){
var triggerMap = new Object() ;
// Let's transfer all the "onXXX" methods over to the bridge---first find
@@ -214,13 +347,6 @@
// By default, "<bridge>.onFoo" maps to "<peer>.onFoo", but this could
// change, so allow for that:
triggerMap[methodName] = { src: this._peer, methodName: methodName } ;
- // Create the callback for this "on..." method, if we don't explicitly have it:
- if( !this[methodName]){
- // This is the only way I could think of (that worked) to
- // get the name of the event into the callback definition, so
- // "onBlur" --> this.fireEvent("onBlur")
- this[methodName] = this.getOnXFunction(methodName) ;
- }
}
}
this.eventTriggers = triggerMap ;
@@ -228,12 +354,6 @@
return this.eventTriggers ;
};
-/**
- * Default behavior in this abstract superclass: the display dom node is the root dom node.
-**/
-xap.bridges.basic.AbstractBlackBoxWidgetBridge.prototype.getDisplayDomNode = function(){
- return this.getRootDomNode() ;
-}
/**
* @return An HTML object (e.g., a DIV or a TD or...) which this widget can replace---this
@@ -258,9 +378,10 @@
/**
- * This is a default behaviour---subclasses should short-circuit this being called if they want to
+ * This is a default crude behaviour---look for a setter on the peer and use it, otherwise look for
+ * a field of the given name and return it. Subclasses should short-circuit this being called if they want to
* do anything interesting (e.g. aButton.getText--> peer.getCaption) .
- * @param attributeName{string}
+ * @param name{String}
* @return object or primitive from the getter
**/
xap.bridges.basic.AbstractBlackBoxWidgetBridge.prototype.getAttribute = function(name){
@@ -276,6 +397,8 @@
}
/**
+ * @private
+ * @static
* Memoiser to avoid the same string operation's repetition:
**/
xap.bridges.basic.AbstractBlackBoxWidgetBridge._nameToSetterMap = new Object() ;
@@ -342,16 +465,27 @@
xap.bridges.basic.AbstractBlackBoxWidgetBridge.prototype.autoAttachBridgeEventsToPeerEvents = function(){
// O.K., <code>this</code> is an object we can use as a bridge---go on:
- var triggers = this.getEventTriggers() ;
+ var triggers = this.findPeerEvents() ;
// We now have a hash table containing a set of strings (triggers) pointing to
// objects, like "[Foobar.]onBaz"--->aFoobarInstance
for(var aKey in triggers){
+
var source = triggers[aKey].src ;
var triggerPieces = triggers[aKey].methodName.split(".") ;
// handles both "foo" and "Me.foo"
var trigger = triggerPieces[triggerPieces.length - 1] ;
+
+ // Create the callback for this "on..." method, if we don't explicitly have it:
+ if( !this[trigger]){
+ // This is the only way I could think of (that worked) to
+ // get the name of the event into the callback definition, so
+ // "onBlur" --> this.fireEvent("onBlur")
+ this[trigger] = this.getOnXFunction(trigger) ;
+ }
dojo.event.connect(source,trigger, this,trigger);
}
+
+ // Connect "onCommand" to a special event for the widget:
dojo.event.connect(this.getPeer(),this.getPeerOnCommandEvent(),this,"_onCommandEvent") ;
}