I've attached my document explaining all the new features of DynAPI. It should give everybody a clear explanation of what to change in their code to make it compliant.
It might take a while until I can get the rework of the events complete, so I'd be a go for getting this codebase as-is into the Sourceforge CVS as a new tree. I just have to work in Robs changes to my latest code. I'll get together a package with all the other files, and examples to promote to Sourceforge. Also, with regards to license issues, I'd still like to go ahead with a switch to the BSD license. If anyone who wrote portions of this code objects we take a look through and remove that code. Notable sections that I did not write are some of the Mozilla and DOM support. Loadpanel was largely written by others, but I had trouble with it in this version, and will be including IOElement which can be used as an alternative. BTW - what's gonna be the version number? 2.6? 2.7? 3.0? Regards, Dan Steinman On Thu, Dec 27, 2001 at 01:19:04PM -0500, Robert Rainwater wrote: Content-Description: Mail message body > > I've been messing with Dan's new dynapi code and have made a few minor updates. Dan >posted a > url to his new code base a while back. I thought I would attach it so people could >start looking at > how the new structure will be. This will give widget developers a chance to begin >working on the > new widget structure. I've attached a simple button widget that could be used as a >guide to > creating a widget. > > Here are the few changes I've made to dan's code: > - Replaced the is object with DynAPI.ua across the board > - Fixed DynLayer constructor (test for null not same as undefined in mozilla/was >causing setHTML > to print undefined in mozilla) > - Removed DynImage crap. You can still use the trimmed down version the same way >(may need > some work) > - Moved addpackage/library to dynapi.js. You can now use package files to set the >library names > (look at package.dynapi.js) > - Added test in debug.js to keep from throwing error > - maybe something else too ? > > I believe Dan is going to rewrite the events in the next release, but this should >give you a good start > to start working with the next release. The only major problem needed to be >addressed is the > offsetWidth/Height problems in Mozilla. This is the main reason why the current >widgets don't work > in mozilla/ns6. > > RobTitle: DynAPI 2.7beta ChangeLog
DynAPI 2.7beta ChangeLog
Dan Steinman ([EMAIL PROTECTED])
Source File Structure
Due to object reorganizations and the sake of consistancy, the file structure has changed:
- Removed /api/browser.js, it's included in dynapi.js in the form of DynAPI.ua which replaces both the "is" and "DynAPI.browser" syntax
- Removed /event/ directory:
- /event/listeners.js has been replaced with /api/event.js which must be included before dyndocument.js and dynlayer.js
- /event/mouse.js is moved to /api/mouse.js
- /event/dragevent.js is moved to /ext/event_drag.js
- /event/keyboard.js is moved to /ext/event_keyboard.js
- /ext/inline.js renamed to /ext/dynlayer_inline.js
- Animation/Effects files are now in a new /fx/ directory:
- /fx/circleanim.js
- /fx/glide.js
- /fx/hoveranim.js
- /fx/imganim.js
- /fx/path.js
- /fx/thread.js // note: DynLayer may include a less sophisticated slide mechanism by default so path and thread won't be required for widgets that need to use simple slide animation
The package system does not reflect these changes, so for now it is recommended that you include the core files in this manner:
<script language="JavaScript" src="dynapi/src/dynapi.js"></script> <script language="Javascript"> DynAPI.setLibraryPath('dynapi/src/lib/'); DynAPI.openDebugger(); // see Debugger below </script> <script language="JavaScript" src="dynapi/src/lib/dynapi/api/event.js"></script> <script language="JavaScript" src="dynapi/src/lib/dynapi/api/dyndocument.js"></script> <script language="JavaScript" src="dynapi/src/lib/dynapi/api/dynlayer.js"></script> <script language="JavaScript" src="javascript:void(0);"></script>
The DynAPI Debugger
When DynAPI.openDebugger() is called as above it will include /dynapi/util/debug.js and open the Debugger window. This is a handly tool to help in the debugging process. It captures the browser syntax errors and routes them to it's print output. You can use this output for your own debugging purposes to find logic errors by calling either:
DynAPI.debug.print('my error string'); dprint('my error string'); // short form, much nicer than using alert() for all your debugging
The Status field is meant for debugging values that change rapidly, such as for handling mousemove events. It is updated with DynAPI.debug.status('error string').
The Evaluate field can be used for real-time debugging of your code. Enter javascript code and it will be evaluated in the scope of the frame that opened it (presumably the document where all your objects are located). You could use it to test creation of DynLayers, resizing them, and method testing.
Events and EventListeners
The EventListener object has been deprecated. Replace all instances with a blank object like so:
var eventlistener = { onmousedown : function(e) { }, onmouseup : function(e) { } }
With this change also comes the removal of the Event.getTarget() method (it was the only reason for having an EventListener object). For events that are created by the widget DynLayer itself, you can merely replace instances of e.getTarget() with e.getSource. But for events that are attached to it's children (eg. an object that listens to a mousedown on a child layer) you can replace e.getTarget() in 2 possible ways.
1) Use e.getSource().parent. This works only when the DynLayer receiving the event is a direct child of the widget object.
2) If you need to attach an event to a sub-child (child of a child), and need a pointer back to the widget you can make a variable which points to "this":
function MyWidget() { this.DynLayer = DynLayer; this.Dynlayer(); this.pdlyr = new Dynlayer(); this.dlyr = this.pdlyr.addChild(new DynLayer()); this.dlyr.widget = this; this.dlyr.addEventListener(MyWidget.childEvents); } MyWidget.childEvents = { oncreate : function(e) { e.getSource().widget.update(); } }; MyWidget.prototype = new DynLayer; MyWidget.prototype.update = function() {};
Optionally, you can create the event listener in the constructor and use a local variable:
function MyWidget() { this.DynLayer = DynLayer; this.Dynlayer(); this.pdlyr = new Dynlayer(); this.dlyr = this.pdlyr.addChild(new DynLayer()); var widget = this; var el = { oncreate : function(e) { widget.update(); } } this.dlyr.addEventListener(el); } MyWidget.prototype = new DynLayer; MyWidget.prototype.update = function() {};
The need to include event.js before dyndocument and dynlayer comes from the fact that both objects inherit from a common DynElement object. A new EventObject handles event listeners. You can now create an object that does nothing but listens/invokes events if you inhert from EventObject. DynElement object adds the addChild/removeChild methods that was previously a part of DynObject.
- DynObject
- EventObject
- DynElement
- DynDocument
- DynLayer
- DynElement
- EventObject
There are 2 new Event methods which are of value when using complex bubbling:
e.getOrigin() - returns the DynObject that first recieved the event
e.getBubbleChild() - returns the child DynLayer that the event bubbled from. This is not the same as getOrigin. For example, when you mousedown on DynLayerB which is a child of DynLayerA, DynLayerB will recieve a mousedown event, bubble up to DynLayerA, and bubble again to DynAPI.document. In a listener attached to DynDocument, e.getSource() will return DynAPI.document, e.getBubbleChild() will return DynLayerB, and e.getOrigin() will return DynLayerA.
DynDocument Upgrades
DynAPI.onLoad() has been replaced with a more flexible onLoad handler built into DynDocument. This allows you to easily add any function to the load sequence:
DynAPI.document.onLoad(init); function init() { }
It also supports a string that will be evaluated:
DynAPI.document.onLoad("alert('load')");
Same goes for the onUnload event:
DynAPI.document.onUnload(function() {alert('unload')}); DynAPI.document.onUnload("alert('unload')");
The DynAPI.document object is now always present instead of being created after onLoad.
DynLayer Upgrades
Syntax Changes
These changes weren't altogether necessary except for making things consistant.
DynLayer() Constructor
There were too many arguments getting into the constructor. I'm now restricting it to the following:
new DynLayer(html, x, y, width, height, bgColor)
The first argument used to be the ID. In practice its extremely rare that you need to set any ID's manually. Setting the HTML content is very common, and so it is now the first argument. This won't lead to much problems if you have a lot of code already created using previous versions because they'll probably set the first argument to null or "" anyway.
setLocation(x,y) - replaces moveTo
moveBy() - will be removed, you can do this command manually where needed
setCursor("cursor-type") - to set the IE cursor for the div ("hand", "stop", etc). Ignored by Netscape 4/Mozilla. This is also available to DynDocument.
setZIndex({above:[DynLayer]}) - sets zIndex one above the given DynLayer object
setZIndex({below:[DynLayer]}) - sets zIndex one below the given DynLayer object
setZIndex({topmost:true}) - sets zIndex above all other sibling layers
setPageLocation(x,y) - performs both setPageX() and setPageY()
BeforeLoad Creation
You can now create DynLayer objects and insert their layer/div elements before onLoad. In order to insert the elements before load you must call DynAPI.document.insertAllChildren() inside the body. This will do one massive document.write() inserting all the layer/div tags at once and makes a large impact on how the layers are rendered. If you only add DynLayers to the document and do not call DynAPI.document.insertAllChildren() the layer elements will be created after onLoad, but before any DynAPI.document.onLoad handlers are called.
<script> var dlyr = new DynLayer(); DynAPI.document.addChild(dlyr); DynAPI.document.onLoad(init); function init() { alert(dlyr.elm) } </script> <body> <script> DynAPI.document.insertAllChildren(); </script> </body>
Create Event
The "create" event that DynLayer invokes works notably different now. Previously children DynLayers called the create event before their parents did. At the time we made this decision it made sense, but since we're moving ahead now I've put this back to what it should be. This does impact widget creation in some manners. In cases where a child layer is resized to it's content size during the create sequence this information is no longer available to the parent DynLayer (where previously it was). If your parent DynLayer/widget needs to know the size of its children a recommended workaround is to add a "precreate" event listener which attaches a "create" event to the last child for use in the widget.
function MyWidget() { this.DynLayer = DynLayer; this.DynLayer(); this.dlyr = new DynLayer('hi'); var el = { oncreate : function(e) { e.getSource().parent.update(); } } this.dlyr.addEventListener(el); } MyWidget.prototype = new DynLayer; MyWidget.prototype.update = function() { alert('child done'); }
Resize Event
I've decided to scrap the use of a "resize" event to handle resizing of widgets, it made things unnecessarily cumbersome. When you perform setSize(), setWidth(), or setHeight() no event will be called. For widgets this means if you need to build in resizing functionality of your own you have to overwrite the setSize method:
MyWidget.prototype._DynLayer_setSize = DynLayer.prototype.setSize; MyWidget.prototype.setSize = function(w,h) { var r = this._DynLayer._setSize(w,h); // returns true if the layer has changed size if (r) { // resize children } }
Anchoring
You may not need to overwrite the setSize() method because there is a built-in anchoring system in DynLayer that will automatically handle many common resizing tasks. Anchoring provides an automatic way to align, stretch, or center layer/divs in an absolute position environment. It calculates the positions based on it's parent's size, and updates the dimensions when the parent resizes. It does not update the anchor position when the layer itself is changed though.
It all works through a single setAnchor() method that you pass an "anchor" property object. Depending on what you pass, and what the width/height of the layer is will determine what happens to size and location of the layer.
setAnchor(anchor)
The anchor object can have a combination of the following properties:
- top [int]
- bottom [int]
- left [int]
- right [int]
- centerH [int]
- centerV [int]
Aligning a layer to it's parent's edges is a common task. If you assign one of left or right, and one of top or bottom anchor properties then it will align the layer accordingly. The setAnchor() method should only be called once, you can pass multiple properties if you need.
Given these 2 layers:
var A = new DynLayer('', 10, 10, 100, 100, 'red'); var B = new DynLayer('', 10, 10, 50, 50, 'blue'); // anchor commands go here A.addChild(B); DynAPI.document.addChild(A);
You could do one of the following anchor commands:
B.setAnchor({top:0}); // top align, essentially do the same as setY(0) B.setAnchor({left:0}); // left align, essentially do the same as setX(0) B.setAnchor({bottom:0}); // bottom align, will set the Y position so that the bottom edge of this layer is always at the bottom edget of it's parent B.setAnchor({right:0}); // right align, will set the X position so that the right edge of this layer is always at the right edget of it's parent B.setAnchor({top:10}); // same as setY(10) B.setAnchor({top:-10}); // same as setY(-10) B.setAnchor({bottom:10}); // bottom align, but offset 10px from the bottom edge B.setAnchor({bottom:-10}); // bottom align, but overlapping by 10px B.setAnchor({left:10}); // same as setX(10) B.setAnchor({left:-10}); // same as setX(-10) B.setAnchor({right:10}); // right aligned, but offset 10px from the right edge B.setAnchor({right:-10}); // right aligned, but overlapping by 10px B.setAnchor({top:0,left:0}); // top/left align B.setAnchor({top:0,right:0}); // top/right align B.setAnchor({bottom:0,left:0}); // bottom/left align B.setAnchor({bottom:0,right:0}); // bottom/left alignStretching
Stretching works the same way except you only have to set both the left and right, or both the top and bottom anchor values. This will overwrite any width or height you have assigned to the DynLayer.
B.setAnchor({top:0,bottom:0}); // stretch vertically - performs setY(0), setHeight(parent.h) automatically B.setAnchor({left:0,right:0}); // stretch horizontally B.setAnchor({top:0,bottom:0; right:10}); // stretch vertically, right aligned 10px from the right edge B.setAnchor({left:0,right:0, bottom:0}); // stretch horizontally, bottom aligned B.setAnchor({left:0,right:0,top:0,bottom:0}); // stretch both vertically and horizontally - similar to doing width=100% and height=100% in a relative position environment B.setAnchor({left:0,right:0,top:20,bottom:0}); // leaves 20 pixels at the topCentering
Centering is mutually exclusive to the align/stretch features. If you horizontally center you can only vertically align/stretch, and vica-versa.
B.setAnchor({centerV:0}) // vertically center B.setAnchor({centerH:0}) // horizontally center B.setAnchor({centerV:10}) // vertically center, but offset 10px down B.setAnchor({centerV:-10}) // vertically center, but offset 10px up B.setAnchor({centerH:10}) // horizontally center, but offset 10px right B.setAnchor({centerH:-10}) // horizontally center, but offset 10px left B.setAnchor({centerV:0,left:0,right:0}) // vertically center, stretch horizontally B.setAnchor({centerH:0,top:0,bottom:0}) // horizontally center, stretch vertically B.setAnchor({centerV:0,right:0}) // vertically center, right align B.setAnchor({centerH:0,bottom:0}) // horizontally center, bottom align B.setAnchor({centerV:0,top:0,bottom:0}) // center overrides stretch/align
As mentioned these values will hold true when the DynLayer's parent resizes. So if after these layers are created DynLayer A is resized, the anchored position will be updated automatically. However if the need arises where the DynLayer itself (DynLayer B in this case) is resized you will need to manually call the DynLayer.updateAnchor() method.