baselist.lzx
<library>
<include href="base/baseformitem.lzx"/>
<include href="base/listselector.lzx"/>
<include href="base/datalistselector.lzx"/>
<class name="baselist" extends="baseformitem">
<attribute name="itemclassname" value="
" type="string"/>
<attribute name="__itemclass" value="null
"/>
<attribute name="defaultselection" value="null
"/>
<attribute name="multiselect" value="false
"/>
<attribute name="toggleselected" value="false
"/>
<attribute name="dataoption" value="none
" type="string"/>
<attribute name="_hiliteview" value="null
"/>
<attribute name="_contentview" value="null
"/>
<attribute name="_initialselection" value="null
"/>
<attribute name="_selector" value="null
"/>
<attribute name="__focusfromchild" value="false
" type="boolean"/>
<event name="onselect"/>
<event name="onitemclassname"/>
<method name="doEnterDown">
// TODO: [hqm 2006-09] LPP-2819 _hiliteview is null sometimes, why?
if ( this._hiliteview is lz.view && this._hiliteview.enabled) {
this._hiliteview.setAttribute('selected', true);
}
</method>
<method name="doEnterUp">
return;
</method>
<method name="init">
super.init();
//assign target if defaultplacement defined
if ( this._contentview == null ) {
if ( this.defaultplacement != null ){
this._contentview = this.searchSubnodes( "name" , this.defaultplacement );
} else {
this._contentview = this;
}
}
if (this.dataoption == "lazy" || this.dataoption == "resize") {
this._selector = new lz.datalistselector(this,
{multiselect:this.multiselect, toggle:toggleselected});
} else {
this._selector = new lz.listselector(this,
{multiselect:this.multiselect, toggle:toggleselected});
}
if (this._initialselection != null) {
this.select(this._initialselection);
} else if (this.defaultselection != null) {
selectItemAt(defaultselection);
}
</method>
<handler name="onfocus" method="_doFocus"/>
<method name="_doFocus" args="ignore">
// the hiliteview is used for keyboard nav hiliting
if (this['_selector'] != null) {
var sel = this._selector.getSelection();
if (sel && sel.length > 0) {
if (sel[0] is lz.view) {
this._hiliteview = sel[0];
this._hiliteview.setHilite(true);
}
}
}
</method>
<handler name="onblur" method="_doblur"/>
<method name="_doblur" args="ignore">
if (this._hiliteview is lz.view) {
this._hiliteview.setHilite(false);
}
this._hiliteview = null;
</method>
<method name="setHilite" args="v">
if (this._selector.allowhilite(v)) {
if ( this._hiliteview is lz.view ) this._hiliteview.setHilite(false);
this._hiliteview = v;
if (v is lz.view ) {
v.setHilite(true);
}
}
</method>
<handler name="onkeydown" method="_dokeydown"/>
<method name="_dokeydown" args="kc">
/* select item on 'space' key */
var s = this._hiliteview;
if (s == null) {
s = getSelection();
// [2009-03-05 ptw] If you lost the highlight because
// you extended the selection, you want to pick up from
// there
if (this.multiselect) s = s[s.length - 1];
}
if (this.focusable && kc == 32) {
if (s is lz.view && s.enabled) {
s.setAttribute('selected', true);
// [2009-03-05 ptw] Don't lose the hilite because you selected
s.setHilite(true);
this._hiliteview = s;
}
return;
}
/* handle arrow key navigation
37 = left arrow, 38 = up arrow
39 = right arrow, 40 = down arrow
*/
if (this.focusable && kc >= 37 && kc <= 40) {
this.setAttribute( 'doesenter', true );
var next;
if (kc == 39 || kc == 40) {
next = _selector.getNextSubview(s);
}
if (kc == 37 || kc == 38) {
next = _selector.getNextSubview(s, -1);
}
if ( s is lz.view ) {
s.setHilite(false);
}
if (next) {
// If shift is down, extend the selection
if (next.enabled && _selector.isRangeSelect(next)) {
next.setAttribute('selected', true);
}
next.setHilite(true);
}
this._hiliteview = next;
}
</method>
<method name="getValue">
return _selector.getValue();
</method>
<method name="getText">
if ( _initcomplete ) return _selector.getText();
return null;
</method>
<method name="getSelection">
if (this._initcomplete) {
// return a single value or an array
var sel = this._selector.getSelection();
if (multiselect) {
// always return an array for multiselect
return sel;
} else {
// single select, just return item or null
if (sel.length == 0) {
return null;
} else {
return sel[0];
}
}
} else {
return this._initialselection;
}
</method>
<method name="selectNext">
moveSelection(1);
</method>
<method name="selectPrev">
moveSelection(-1);
</method>
<method name="moveSelection" args="dir">
if (!dir) dir = 1;
var sel = this._selector.getSelection();
var next;
if (sel.length == 0) {
next = this._contentview.subviews[0];
} else {
var s = sel[0];
next = this._selector.getNextSubview(s, dir);
}
var current_focus = lz.Focus.getFocus();
select(next);
if (s && current_focus && current_focus.childOf(s)) {
lz.Focus.setFocus(next);
}
</method>
<method name="getNumItems">
if (this['_selector'] == null) return 0; // too early
return this._selector.getNumItems();
</method>
<method name="getItemAt" args="index">
if (_contentview.subviews[index]) {
return getItem(_contentview.subviews[index].getValue());
}
return null;
</method>
<method name="getItem" args="value">
// find the item with the requested value
if (_contentview != null && _contentview.subviews != null) {
for (var i=0; i<_contentview.subviews.length; i++) {
var check = _contentview.subviews[i];
if (check.getValue()==value) {
return check;
}
}
}
return null;
</method>
<method name="addItem" args="text, value=null">
new this.__itemclass(this, {text:text, value:value});
</method>
<setter name="itemclassname" args="tag">
if ($debug) {
if (tag && (! lz[tag])) { Debug.error("Invalid itemclassname %s", tag) }
}
this.itemclassname = tag;
this.__itemclass = lz[tag];
if (onitemclassname.ready) { this.onitemclassname.sendEvent(tag); }
</setter>
<method name="removeItem" args="value">
var item = getItem(value);
if ($debug) {
if (item == null) {
Debug.error("%s.item not found for %s", this, value);
}
}
_removeitem(item);
</method>
<method name="removeItemAt" args="index">
var item = _contentview.subviews[index];
_removeitem(item);
</method>
<method name="removeAllItems">
// Sometimes a single cycle of the for below won't remove
// every subview, so we need to make sure it runs until it
// gets them all.
while(_contentview.subviews.length != 0){
for(var eg = 0; eg < _contentview.subviews.length; eg++){
_removeitem(_contentview.subviews[eg]);
}
}
</method>
<method name="_removeitem" args="item">
if (item) {
if (item.selected) this._selector.unselect(item);
item.destroy();
}
</method>
<method name="selectItem" args="value">
var item = getItem(value);
if (item) {
select(item);
}
</method>
<method name="selectItemAt" args="index">
if (this._selector != null) {
var item = this._selector.getItemByIndex(index);
select(item);
}
</method>
<method name="clearSelection">
if ( this._initcomplete ){
this._selector.clearSelection();
} else {
this._initialselection = null;
this.defaultselection = null;
}
</method>
<method name="select" args="item">
if (item == null) {
//noop
} else if (this._initcomplete) {
this._selector.select(item);
if (!this.multiselect) {
this.setAttribute('value', item.getValue() );
}
} else {
if (multiselect) {
if (this._initialselection == null)
this._initialselection = [];
this._initialselection.push(item);
} else {
this._initialselection = item;
}
}
if ( this._hiliteview is lz.view && this._hiliteview['enabled']) {
this._hiliteview.setHilite(false);
this._hiliteview = null;
}
this.setAttribute( 'doesenter', false );
if ( this.onselect ) this.onselect.sendEvent(item);
</method>
<doc>
<tag name="shortdesc"><text>An abstract class which all list components should subclass.</text></tag>
<text>
<p>This class is a container for a group of
<classname>baselistitem</classname>s. To use
<classname>baselist</classname>, <classname>baselistitem</classname>
must be subclassed to provide a visual representation of the list
item. It supports single select by default. Set
<attribute>multiselect</attribute> to true to allow multiple selection
(shift-click for a range, control-click for an arbitrary set).</p>
<p>Contained list items may be declared inside the list, such as:</p>
<example>
<canvas height="100">
<baselist layout="axis:y;spacing:2">
<baselistitem height="15" width="25" bgcolor="${selected ? 0xffff00 : 0x0000ff}"/>
<baselistitem height="15" width="50" bgcolor="${selected ? 0xffff00 : 0x0000ff}"/>
<baselistitem height="15" width="100" bgcolor="${selected ? 0xffff00 : 0x0000ff}"/>
</baselist>
<text y="70">Click bar to select it.</text>
</canvas>
</example>
<p>or replicated from data: </p>
<example>
<canvas height="90">
<dataset name="items">
<item>one</item>
<item>two</item>
<item>three</item>
</dataset>
<class name="myitem" extends="baselistitem"
bgcolor="${selected ? 0xffff00 : 0xffffff}">
<text text="${parent.value}"/>
</class>
<baselist layout="axis:y; spacing:2">
<myitem datapath="items:/item/text()"/>
</baselist>
<text y="70" >Click on a number to select it.</text>
</canvas>
</example>
<h2>Optimizing Lists</h2>
<p>If your lists represent data from a datapath, there are two
optimizations that you may want to consider:</p>
<dl>
<dt>pooling</dt>
<dd>If you will be changing the data that is represented by the list
after it has been created, you can set
<code>dataoption="pooling"</code>. For more about pooling see the
datapath <xref linkend="LzDatapath.__ivars__.pooling"/> attribute
and the example in <classname library="lz">list</classname>.</dd>
<dt>lazy</dt>
<dd>If there are more items in the list than will be visible and all
list items are the same size (for example, in a scrolling list or
combobox), you should set dataoption="lazy". For more about lazy
replication see the datapath
<xref linkend="LzDatapath.__ivars__.replication"/> attribute,
<classname>LzLazyReplicationManager</classname>, and the example in
<classname library="lz">list</classname>.</dd>
</dl>
</text>
</doc>
</class>
</library>
Cross References
Includes
Classes
- <class name="baselist" extends="baseformitem">