@qooxdoo/framework
Version:
The JS Framework for Coders
336 lines (269 loc) • 9.7 kB
JavaScript
/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2011-2014 1&1 Internet AG, Germany, http://www.1und1.de
License:
MIT: https://opensource.org/licenses/MIT
See the LICENSE file in the project's top-level directory for details.
Authors:
* Christopher Zuendorf (czuendorf)
************************************************************************ */
/**
*
* The picker widget gives the user the possibility to select a value out of an array
* of values. The picker widget can be added to a {@link qx.ui.mobile.dialog.Popup} or to any other container.
*
* The picker widget is able to display multiple picker slots, for letting the user choose
* several values at one time, in one single control.
*
* You can add an array with objects which contain the keys <code>title</code>, a <code>subtitle</code> or an <code>image</code> (all optional).
*
* <pre>
* var picker = new qx.ui.mobile.control.Picker();
* picker.setHeight(200);
* picker.addListener("changeSelection", function(evt) {
* var data = evt.getData();
* },this);
*
* var slotData1 = [{title:"Windows Phone"}, {title:"iOS",subtitle:"Version 7.1"}, {title:"Android"}];
* var slotData2 = [{title:"Tablet"}, {title:"Smartphone"}, {title:"Phablet"}];
*
* picker.addSlot(new qx.data.Array(slotData1));
* picker.addSlot(new qx.data.Array(slotData2));
* </pre>
*
*/
qx.Class.define("qx.ui.mobile.control.Picker",
{
extend : qx.ui.mobile.container.Composite,
construct : function()
{
this.base(arguments);
this._pickerModel = new qx.data.Array();
this._slots = new qx.data.Array();
this.addListener("appear", this._onAppear, this);
this.initVisibleItems();
},
events :
{
/**
* Fired when the selection of a slot has changed.
* Example:
* <code> {
* index: 0,
* item: [Object],
* slot: 0
* }</code>
*/
changeSelection : "qx.event.type.Data"
},
properties :
{
// overridden
defaultCssClass :
{
refine : true,
init : "picker"
},
/**
* Controls how much visible items are shown inside the picker.
*/
visibleItems : {
init : 5,
check : [3,5,7,9],
apply : "_applyVisibleItems"
},
/**
* Controls the picker height.
*/
height : {
init : 200,
check : "Number"
}
},
members :
{
_slots : null,
_pickerModel : null,
/**
* Handler for <code>appear</code> event of this widget.
*/
_onAppear: function() {
var itemHeight = this._calcItemHeight();
this._slots.forEach(function(slot, index) {
qx.bom.AnimationFrame.request(function() {
slot.container.scrollTo(0, slot.selectedIndex * itemHeight);
});
}, this);
},
// property apply
_applyVisibleItems : function(value) {
this._setAttribute("data-items",value);
},
/**
* Returns the internal used picker model which contains one or more picker slot models.
* @return {qx.data.Array} the picker model.
*/
getModel : function() {
return this._pickerModel;
},
/**
* Creates a picker slot.
* @param slotModel {qx.data.Array} the picker slot model.
* @param slotIndex {Number} the index of this slot.
* @param delegate {qx.ui.mobile.list.IListDelegate?null} the list delegate object for this slot list.
* @return {qx.ui.mobile.container.Scroll} the picker slot as a scroll container.
*/
_createPickerSlot : function(slotModel, slotIndex, delegate) {
var scrollContainer = new qx.ui.mobile.container.Scroll({
"snap": ".list-item",
"vScrollbar" : false
});
scrollContainer.setWaypointsY([".list-item"]);
qx.bom.element.Style.set(scrollContainer.getContentElement(), "height", this.getHeight() + "px");
var slot = {
container: scrollContainer,
selectedIndex: 0
};
this._slots.push(slot);
scrollContainer.addListener("waypoint", this._onWaypoint, {
self: this,
slot : slot,
slotIndex : slotIndex,
slotModel : slotModel
});
var list = new qx.ui.mobile.list.List(delegate);
list.setItemHeight(this._calcItemHeight());
list.addListener("changeSelection", this._onChangeSelection, {
self: this,
slotIndex: slotIndex
});
list.setModel(slotModel);
var slotWrapper = new qx.ui.mobile.container.Composite();
// Generate placeholder items at before and after picker data list,
// for making sure the first and last item can be scrolled
// to the center of the picker.
var placeholderItemCount = Math.floor(this.getVisibleItems() / 2);
for (var i = 0; i < placeholderItemCount; i++) {
slotWrapper.add(this._createPlaceholderItem());
}
slotWrapper.add(list);
for (var j = 0; j < placeholderItemCount; j++) {
slotWrapper.add(this._createPlaceholderItem());
}
scrollContainer.add(slotWrapper);
this.add(scrollContainer);
scrollContainer.refresh();
return scrollContainer;
},
/**
* Creates a placeholder list item, for making sure the selected item is vertically centered.
* @return {qx.ui.mobile.container.Composite} the placeholder list item.
*/
_createPlaceholderItem : function() {
var placeholderItem = new qx.ui.mobile.container.Composite();
qx.bom.element.Style.set(placeholderItem.getContentElement(), "minHeight", this._calcItemHeight() + "px");
placeholderItem.addCssClass("list-item");
placeholderItem.addCssClass("placeholder-item");
return placeholderItem;
},
/**
* Calculates the item height of a picker item.
* @return {Number} height of the picker item.
*/
_calcItemHeight : function() {
return this.getHeight() / this.getVisibleItems();
},
/**
* Handler for <code>changeSelection</code> event on picker list.
* @param evt {qx.event.type.Data} the events data.
*/
_onChangeSelection: function(evt) {
qx.Bootstrap.bind(this.self.setSelectedIndex, this.self, this.slotIndex, evt.getData()).call();
},
/**
* Handler for <code>waypoint</code> event on scroll container.
* @param evt {qx.event.type.Data} the waypoint data.
*/
_onWaypoint: function(evt) {
var elementIndex = evt.getData().element;
this.slot.selectedIndex = elementIndex;
this.self.fireDataEvent("changeSelection", {
index: elementIndex,
item: this.slotModel.getItem(elementIndex),
slot: this.slotIndex
});
},
/**
* Getter for the selectedIndex of a picker slot, identified by its index.
* @param slotIndex {Integer} the index of the target picker slot.
* @return {Integer} the index of the target picker slot, or null if slotIndex is unknown.
*/
getSelectedIndex : function(slotIndex) {
return this._slots.getItem(slotIndex).selectedIndex;
},
/**
* Setter for the selectedIndex of a picker slot, identified by its index.
* @param slotIndex {Integer} the index of the target picker slot.
* @param selectedIndex {Integer} the selectedIndex of the slot.
*/
setSelectedIndex: function(slotIndex, selectedIndex) {
var slot = this._slots.getItem(slotIndex);
slot.selectedIndex = selectedIndex;
if (this.isVisible()) {
slot.container.scrollTo(0, selectedIndex * this._calcItemHeight());
}
},
/**
* Returns the picker slot count, added to this picker.
* @return {Integer} count of picker slots.
*/
getSlotCount : function() {
return this._pickerModel.getLength();
},
/**
* Adds an picker slot to the end of the array.
* @param slotModel {qx.data.Array} the picker slot model to display.
* @param delegate {qx.ui.mobile.list.IListDelegate?null} the list delegate object for this slot.
*/
addSlot : function(slotModel, delegate) {
if(slotModel !== null && slotModel instanceof qx.data.Array) {
this._pickerModel.push(slotModel);
var slotIndex = this._pickerModel.length - 1;
var scrollContainer = this._createPickerSlot(slotModel, slotIndex, delegate);
slotModel.addListener("changeBubble", this._onSlotDataChange, scrollContainer);
slotModel.addListener("change", this._onSlotDataChange, scrollContainer);
}
},
/**
* Removes the picker slot at the given slotIndex.
* @param slotIndex {Integer} the index of the target picker slot.
*/
removeSlot : function(slotIndex) {
if(this._pickerModel.length > slotIndex && slotIndex > -1) {
var slotModel = this._pickerModel.getItem(slotIndex);
var scrollContainer = this._slots.getItem(slotIndex).container;
slotModel.removeListener("changeBubble", this._onSlotDataChange, scrollContainer);
slotModel.removeListener("change", this._onSlotDataChange, scrollContainer);
qx.util.DisposeUtil.destroyContainer(scrollContainer);
this._pickerModel.removeAt(slotIndex);
this._slots.removeAt(slotIndex);
}
},
/**
* Handles the <code>changeBubble</code> and <codechange></code> event on a picker slot model.
*/
_onSlotDataChange : function() {
window.setTimeout(function() {
this.refresh();
}.bind(this), 0);
}
},
destruct : function()
{
this._pickerModel.dispose();
this._slots.dispose();
qx.util.DisposeUtil.destroyContainer(this);
}
});