not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

175 lines
5.5 KiB

/**
A control that displays a repeating list of rows, suitable for displaying
medium-sized lists (up to ~100 items). A flyweight strategy is employed to
render one set of row controls, as needed, for as many rows as are contained
in the repeater.
The FlyweightRepeater's _components_ block contains the controls to be used
for a single row. This set of controls will be rendered for each row. You
may customize row rendering by handling the _onSetupItem_ event.
The controls inside a FlyweightRepeater are non-interactive. This means that
calling methods that would normally cause rendering to occur (e.g.,
_setContent_) will not do so. However, you can force a row to render by
calling _renderRow(inRow)_.
In addition, you can force a row to be temporarily interactive by calling
_prepareRow(inRow)_. Call the _lockRow_ method when the interaction is
complete.
For more information, see the documentation on
[Lists](https://github.com/enyojs/enyo/wiki/Lists)
in the Enyo Developer Guide.
*/
enyo.kind({
name: "enyo.FlyweightRepeater",
published: {
//* Number of rows to render
count: 0,
//* If true, multiple selections are allowed
multiSelect: false,
//* If true, the selected item will toggle
toggleSelected: false
},
events: {
/**
Fires once per row at render time, with event object:
_{index: <index of row>, selected: <true if row is selected>}_
*/
onSetupItem: ""
},
components: [
{kind: "Selection", onSelect: "selectDeselect", onDeselect: "selectDeselect"},
{name: "client"}
],
rowOffset: 0,
bottomUp: false,
//* @protected
create: function() {
this.inherited(arguments);
this.multiSelectChanged();
},
multiSelectChanged: function() {
this.$.selection.setMulti(this.multiSelect);
},
setupItem: function(inIndex) {
this.doSetupItem({index: inIndex, selected: this.isSelected(inIndex)});
},
//* Renders the list.
generateChildHtml: function() {
var h = "";
this.index = null;
// note: can supply a rowOffset
// and indicate if rows should be rendered top down or bottomUp
for (var i=0, r=0; i<this.count; i++) {
r = this.rowOffset + (this.bottomUp ? this.count - i-1 : i);
this.setupItem(r);
this.$.client.setAttribute("index", r);
h += this.inherited(arguments);
this.$.client.teardownRender();
}
return h;
},
previewDomEvent: function(inEvent) {
var i = this.index = this.rowForEvent(inEvent);
inEvent.rowIndex = inEvent.index = i;
inEvent.flyweight = this;
},
decorateEvent: function(inEventName, inEvent, inSender) {
// decorate event with index found via dom iff event does not already contain an index.
var i = (inEvent && inEvent.index != null) ? inEvent.index : this.index;
if (inEvent && i != null) {
inEvent.index = i;
inEvent.flyweight = this;
}
this.inherited(arguments);
},
tap: function(inSender, inEvent) {
if (this.toggleSelected) {
this.$.selection.toggle(inEvent.index);
} else {
this.$.selection.select(inEvent.index);
}
},
selectDeselect: function(inSender, inEvent) {
this.renderRow(inEvent.key);
},
//* @public
//* Returns the repeater's _selection_ component.
getSelection: function() {
return this.$.selection;
},
//* Gets the selection state for the given row index.
isSelected: function(inIndex) {
return this.getSelection().isSelected(inIndex);
},
//* Renders the row specified by _inIndex_.
renderRow: function(inIndex) {
//this.index = null;
var node = this.fetchRowNode(inIndex);
if (node) {
this.setupItem(inIndex);
node.innerHTML = this.$.client.generateChildHtml();
this.$.client.teardownChildren();
}
},
//* Fetches the DOM node for the given row index.
fetchRowNode: function(inIndex) {
if (this.hasNode()) {
var n$ = this.node.querySelectorAll('[index="' + inIndex + '"]');
return n$ && n$[0];
}
},
//* Fetches the DOM node for the given event.
rowForEvent: function(inEvent) {
var n = inEvent.target;
var id = this.hasNode().id;
while (n && n.parentNode && n.id != id) {
var i = n.getAttribute && n.getAttribute("index");
if (i !== null) {
return Number(i);
}
n = n.parentNode;
}
return -1;
},
//* Prepares the row specified by _inIndex_ such that changes made to the
//* controls inside the repeater will be rendered for the given row.
prepareRow: function(inIndex) {
var n = this.fetchRowNode(inIndex);
enyo.FlyweightRepeater.claimNode(this.$.client, n);
},
//* Prevents rendering of changes made to controls inside the repeater.
lockRow: function() {
this.$.client.teardownChildren();
},
//* Prepares the row specified by _inIndex_ such that changes made to the
//* controls in the row will be rendered in the given row; then performs the
//* function _inFunc_, and, finally, locks the row.
performOnRow: function(inIndex, inFunc, inContext) {
if (inFunc) {
this.prepareRow(inIndex);
enyo.call(inContext || null, inFunc);
this.lockRow();
}
},
statics: {
//* Associates a flyweight rendered control (_inControl_) with a
//* rendering context specified by _inNode_.
claimNode: function(inControl, inNode) {
var n = inNode && inNode.querySelectorAll("#" + inControl.id);
n = n && n[0];
// FIXME: consider controls generated if we found a node or tag: null, the later so can teardown render
inControl.generated = Boolean(n || !inControl.tag);
inControl.node = n;
if (inControl.node) {
inControl.rendered();
} else {
//enyo.log("Failed to find node for", inControl.id, inControl.generated);
}
for (var i=0, c$=inControl.children, c; c=c$[i]; i++) {
this.claimNode(c, inNode);
}
}
}
});