UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

349 lines (298 loc) 9.82 kB
/* ************************************************************************ 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); } });