lazyreplicator.lzx
<library>
<include href="replicator.lzx"/>
<class name="lazyreplicator" extends="replicator">
<attribute name="replicatedsize" value="null
"/>
<attribute name="clonesoffset" value="0
"/>
<attribute name="__emptyArray" value="null
"/>
<attribute name="clonedel" value="null
"/>
<method name="construct" args="p,a">
super.construct( p, a );
// TODO [hqm 2007 09] Lock the parent layout so it can't mess
// up our placement of clones. The implicit lazy
// repl. manager only wraps this inside of _adjustVisibleClones
// but I want to be sure any parent container layout is really
// turned off before any views get instantiated, and stays off
// all the time, it can only cause trouble.
//
var layouts = this.container.layouts;
if (layouts) {
for (var i = 0, len = layouts.length; i < len; i++) {
layouts[i].lock();
}
}
this.__emptyArray = [];
this.clonedel = new LzDelegate( this, '__adjustVisibleClones');
</method>
<method name="init">
this.clonedel.register( this.mask , "on" + this._sizes[ this.axis ] );
this.clonedel.register( this.container , "on" + this.axis );
super.init();
</method>
<attribute name="_lastNodesLength" value="0
"/>
<method name="__adjustVisibleClones" args="ignore=null">
if ( ! this.nodes ) {
while ( this.clones.length ) this.poolClone( this.clones.pop() );
return;
}
if ( !this.replicatedsize ) this._setSize();
var sizeAxis = this._sizes[ this.axis ];
if ( this.nodes.length != null ){
this._lastNodesLength = this.nodes.length;
}
var s = this._lastNodesLength * this.replicatedsize;
if ( this.container[ sizeAxis ] != s ){
//Debug.write( sizeAxis, s, this.container[ sizeAxis ] );
this.container.setAttribute( sizeAxis, s );
}
if (! this.mask) {
Debug.warn("%w: cannot find clipping parent", this);
return;
}
if (! this.mask[ "hasset" + sizeAxis ] )
return;
//Here's the idea. Coming in, we have an old list of clones that
//represents some window into the dataset. Let's say the nodes are
//labelled alphabetically so to start, we have
//this.clones=[ m , n , o , p ]
//When the situation changes, we end up with a situation where we
//want the window to be like
//this.clones=[ l , m , n , o ]
//This algorithm moves the old list of clones to a temporary
//identifier and then constructs a new array for the clones going
//through one by one It keeps an offset, which represents the
//difference in position of the old new data windows. In the case
//above, the offset would be -2.
var newstart = Math.floor( -this.container[ this.axis ] /
this.replicatedsize );
if ( 0 > newstart ) newstart = 0;
var oldptr = 0;
var oldlength = this.clones.length;
var offset = newstart - this.clonesoffset;
var remainder = ( newstart * this.replicatedsize ) +
this.container[ this.axis ];
var newlength= Math.ceil(
Math.min( (this.mask[ sizeAxis ] - remainder )/this.replicatedsize ,
this.container[ sizeAxis ] /this.replicatedsize ) );
//newstart is the new absolute lowerbound of the data window
//newlength is the new length of the data window
if ( newlength + newstart > this.nodes.length ) {
newlength = this.nodes.length - newstart;
}
//no change
if ( offset == 0 && newlength == oldlength ) return;
//_root.lz.Instantiator.enableDataReplicationQueuing( );
var oldclones = this.clones;
//TODO: instead of allocating a new array, use two arrays and
//ping-pong
this.clones = this.__emptyArray;
for ( var i = 0 ; i < newlength; i++ ){
//before the new beginning
var cl = null;
if ( i + offset < 0 ){
//this comes before the old data window
if ( newlength + offset < oldlength && oldlength > 0){
//pull the clone off the end
cl = oldclones[ --oldlength ];
} else {
cl = this.getClone();
}
} else if ( i + offset >= oldlength ){
//this comes after the old data window
if ( oldptr < offset && oldptr < oldlength ){
//pull the clone off the end
cl = oldclones[ oldptr++ ];
} else {
cl = this.getClone();
}
}
if ( cl ){
this.clones[ i ] = cl;
var val = ( i + newstart ) * this.replicatedsize ;
cl.setAttribute( this.axis , val);
this.unbind( cl );
this.bind( cl, newstart + i );
} else {
//otherwise, the oldclone and the newclone match
this.clones[ i ] = oldclones[ i + offset ];
}
}
while ( oldptr < offset && oldptr < oldlength ){
var v = oldclones[ oldptr++ ];
this.poolClone( v );
}
while ( oldlength > newlength + offset && oldlength > 0 ){
var v = oldclones[ --oldlength ];
this.poolClone( v );
}
this.clonesoffset = newstart;
while ( oldclones.length ) oldclones.pop();
this.__emptyArray = oldclones;
//_root.lz.Instantiator.clearDataReplicationQueue( );
</method>
<method name="createChildren" args="c">
this.replicated = c.pop();
// TODO [hqm 2007 09] I need to set ignorelayout option before
// the clone gets instantiated, otherwise it might get placed
// by the parent layout during construction, which we don't
// want to happen.
var attrs;
if ('attrs' in this.replicated) {
attrs = this.replicated.attrs;
} else {
attrs = {};
this.replicated.attrs = attrs;
}
if ('options' in attrs) {
attrs.options.ignorelayout = true;
} else {
attrs.options = {ignorelayout: true};
}
//Debug.write( 'replicated', replicated );
if ( c.length ) {
if ($debug) Debug.warn("%s: only a single child view is replicated", this);
this.container.createChildren( c );
} else {
this.__LZinstantiationDone();
}
</method>
<method name="getClone">
var cl = super.getClone();
cl.setOption( 'ignorelayout', true );
return cl;
</method>
<method name="_setSize">
var c = this.getClone();
this.setAttribute( "replicatedsize", c[ this._sizes[ this.axis ] ] );
this.poolClone( c );
</method>
<method name="getCloneIfVisible" args="n">
var off = Number( n ) - this.clonesoffset;
if ( off >= 0 && off < this.clones.length ) return this.clones[ off ];
else return null;
</method>
<method name="getCloneForOffset" args="n">
this.ensureInView( n );
return this.clones[ n-this.clonesoffset];
</method>
<method name="getCloneForNode" args="datanode,dontmake = false">
var cl = super.getCloneForNode( datanode ) ||
null;
if ( !cl && !dontmake ){
//even though we're going to return this to the pool immediately,
//use the class API to get a clone
cl = this.getClone();
this.setData( cl, datanode );
this.update( cl, datanode );
if (cl.datapath['sel'] != datanode['sel']) {
cl.datapath['sel'] = datanode['sel'] || false;
cl.setSelected(cl.datapath['sel']);
}
if (cl['applyData']) cl.applyData( datanode );
this.poolClone( cl );
}
//cl.setOption( 'ignorelayout', true );
return cl;
</method>
<method name="destroy">
var layouts = this.container.layouts;
if (layouts) {
for (var i = 0, len = layouts.length; i < len; i++) {
layouts[i].unlock();
}
}
super.destroy();
</method>
</class>
</library>
Cross References
Includes
Classes