Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/html/lib/layout/list/source/FlyweightRepeater.js
diff options
context:
space:
mode:
Diffstat (limited to 'html/lib/layout/list/source/FlyweightRepeater.js')
-rw-r--r--html/lib/layout/list/source/FlyweightRepeater.js175
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