diff options
Diffstat (limited to 'html/lib/layout/list/source/FlyweightRepeater.js')
-rw-r--r-- | html/lib/layout/list/source/FlyweightRepeater.js | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/html/lib/layout/list/source/FlyweightRepeater.js b/html/lib/layout/list/source/FlyweightRepeater.js new file mode 100644 index 0000000..01e6d80 --- /dev/null +++ b/html/lib/layout/list/source/FlyweightRepeater.js @@ -0,0 +1,175 @@ +/** + 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); + } + } + } +});
\ No newline at end of file |