Skip to content
This repository has been archived by the owner on Mar 13, 2018. It is now read-only.

Commit

Permalink
upgrade g-selector to match polymer-selector
Browse files Browse the repository at this point in the history
  • Loading branch information
sorvell committed Aug 27, 2013
1 parent 0f85055 commit 05a3a3e
Showing 1 changed file with 258 additions and 2 deletions.
260 changes: 258 additions & 2 deletions elements/g-selector.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
*/
-->
<link rel="import" href="g-selection.html">
<polymer-element name="g-selector" on-tap="activateHandler" attributes="selected selectedClass selectedModel multi valueattr notap">
<!--<polymer-element name="g-selector" on-tap="activateHandler" attributes="selected selectedClass selectedModel multi valueattr notap">
<template>
<g-selection id="selection" multi="{{multi}}" on-select="selectionSelect"></g-selection>
<content id="items" select="*"></content>
Expand Down Expand Up @@ -177,4 +177,260 @@
}
});
</script>
</polymer-element>
</polymer-element>-->
<polymer-element name="g-selector"
attributes="selected multi valueattr selectedClass selectedProperty selectedItem selectedModel notap target itemsSelector activateEvent">
<template>
<g-selection id="selection" multi="{{multi}}" on-select="selectionSelect"></g-selection>
<content id="items" select="*"></content>
</template>
<script>
Polymer('g-selector', {
/**
* Gets or sets the selected element. Default to use the index
* of the item element.
*
* If you want a specific attribute value of the element to be
* used instead of index, set "valueattr" to that attribute name.
*
* Example:
*
* <polymer-selector valueattr="label" selected="foo">
* <div label="foo"></div>
* <div label="bar"></div>
* <div label="zot"></div>
* </polymer-selector>
*
* In multi-selection this should be an array of values.
*
* Example:
*
* <polymer-selector id="selector" valueattr="label" multi>
* <div label="foo"></div>
* <div label="bar"></div>
* <div label="zot"></div>
* </polymer-selector>
*
* this.$.selector.selected = ['foo', 'zot'];
*
* @attribute selected
* @type Object
* @default null
*/
selected: null,
/**
* If true, multiple selections are allowed.
*
* @attribute multi
* @type boolean
* @default false
*/
multi: false,
/**
* Specifies the attribute to be used for "selected" attribute.
*
* @attribute valueattr
* @type string
* @default 'name'
*/
valueattr: 'name',
/**
* Specifies the CSS class to be used to add to the selected element.
*
* @attribute selectedClass
* @type string
* @default 'polymer-selected'
*/
selectedClass: 'selected',
/**
* Specifies the property to be used to set on the selected element
* to indicate its active state.
*
* @attribute selectedProperty
* @type string
* @default 'active'
*/
selectedProperty: 'active',
/**
* Returns the currently selected element. In multi-selection this returns
* an array of selected elements.
*
* @attribute selectedItem
* @type Object
* @default null
*/
selectedItem: null,
/**
* In single selection, this returns the model associated with the
* selected element.
*
* @attribute selectedModel
* @type Object
* @default null
*/
selectedModel: null,
/**
* The target element that contains items. If this is not set
* polymer-selector is the container.
*
* @attribute target
* @type Object
* @default null
*/
target: null,
itemsSelector: '',
activateEvent: 'tap',
notap: false,
created: function() {
this.activateListener = this.activateHandler.bind(this);
this.observer = new MutationObserver(this.updateSelected.bind(this));
if (!this.target) {
this.target = this;
}
},
get items() {
var nodes = this.target !== this ? (this.itemsSelector ?
this.target.querySelectorAll(this.itemsSelector) :
this.target.children) : this.$.items.getDistributedNodes();
return Array.prototype.filter.call(nodes || [], function(n) {
return n && n.localName !== 'template';
});
},
targetChanged: function(old) {
if (old) {
this.removeListener(old);
this.observer.disconnect();
}
if (this.target) {
this.addListener(this.target);
this.observer.observe(this.target, {childList: true});
}
},
addListener: function(node) {
node.addEventListener(this.activateEvent, this.activateListener);
},
removeListener: function(node) {
node.removeEventListener(this.activateEvent, this.activateListener);
},
get selection() {
return this.$.selection.getSelection();
},
selectedChanged: function() {
this.updateSelected();
},
updateSelected: function() {
this.validateSelected();
if (this.multi) {
this.clearSelection();
this.selected && this.selected.forEach(function(s) {
this.valueToSelection(s);
}, this);
} else {
this.valueToSelection(this.selected);
}
},
validateSelected: function() {
// convert to an array for multi-selection
if (this.multi && !Array.isArray(this.selected) &&
this.selected !== null && this.selected !== undefined) {
this.selected = [this.selected];
}
},
clearSelection: function() {
if (this.multi) {
this.selection.slice().forEach(function(s) {
this.$.selection.setItemSelected(s, false);
}, this);
} else {
this.$.selection.setItemSelected(this.selection, false);
}
this.selectedItem = null;
this.$.selection.clear();
},
valueToSelection: function(value) {
var item = (value === null || value === undefined) ?
null : this.items[this.valueToIndex(value)];
this.$.selection.select(item);
},
updateSelectedItem: function() {
this.selectedItem = this.selection;
},
selectedItemChanged: function() {
if (this.selectedItem) {
var t = this.selectedItem.templateInstance;
this.selectedModel = t ? t.model : undefined;
} else {
this.selectedModel = null;
}
},
valueToIndex: function(value) {
// find an item with value == value and return it's index
for (var i=0, items=this.items, c; (c=items[i]); i++) {
if (this.valueForNode(c) == value) {
return i;
}
}
// if no item found, the value itself is probably the index
return value;
},
valueForNode: function(node) {
return node[this.valueattr] || node.getAttribute(this.valueattr);
},
// events fired from <polymer-selection> object
selectionSelect: function(e, detail) {
this.updateSelectedItem();
if (detail.item) {
this.applySelection(detail.item, detail.isSelected)
}
},
applySelection: function(item, isSelected) {
if (this.selectedClass) {
item.classList.toggle(this.selectedClass, isSelected);
}
if (this.selectedProperty) {
item[this.selectedProperty] = isSelected;
}
},
// event fired from host
activateHandler: function(e) {
if (!this.notap) {
var i = this.findDistributedTarget(e.target, this.items);
if (i >= 0) {
var item = this.items[i];
var s = this.valueForNode(item) || i;
if (this.multi) {
if (this.selected) {
this.addRemoveSelected(s);
} else {
this.selected = [s];
}
} else {
this.selected = s;
}
this.asyncFire('activate', {item: item});
}
}
},
addRemoveSelected: function(value) {
var i = this.selected.indexOf(value);
if (i >= 0) {
this.selected.splice(i, 1);
} else {
this.selected.push(value);
}
this.valueToSelection(value);
},
findDistributedTarget: function(target, nodes) {
// find first ancestor of target (including itself) that
// is in nodes, if any
while (target && target != this) {
var i = Array.prototype.indexOf.call(nodes, target);
if (i >= 0) {
return i;
}
target = target.parentNode;
}
}
});
</script>
</polymer-element>

0 comments on commit 05a3a3e

Please sign in to comment.