@qooxdoo/framework
Version:
The JS Framework for Coders
349 lines (298 loc) • 9.82 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() {
super();
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() {
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(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() {
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(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() {
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() {
return this.getHeight() / this.getVisibleItems();
},
/**
* Handler for <code>changeSelection</code> event on picker list.
* @param evt {qx.event.type.Data} the events data.
*/
_onChangeSelection(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(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(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(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() {
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(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(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() {
window.setTimeout(
function () {
this.refresh();
}.bind(this),
0
);
}
},
destruct() {
this._pickerModel.dispose();
this._slots.dispose();
qx.util.DisposeUtil.destroyContainer(this);
}
});