/**
* @module uifactory/select
* @author Flavio De Stefano <flavio.destefano@caffeinalab.com>
*/
var Moment = require('alloy/moment');
var Util = require('T/util');
var Dialog = require('T/dialog');
var Data = {};
var PICKER_WIDTH_IPHONE = Alloy.Globals.SCREEN_WIDTH;
var PICKER_HEIGHT_IPHONE = 216;
var PICKER_WIDTH_IPAD = 320;
var PICKER_HEIGHT_IPAD = 216;
function getPickerColumn(rows) {
var $col = Ti.UI.createPickerColumn();
rows.forEach(function(value) {
$col.addRow( Ti.UI.createPickerRow(value) );
});
return $col;
}
function fillPickerData($this, $picker) {
if ($this != null) {
var pickerColumns = Data[ $this._uid ].values.map(getPickerColumn);
if (pickerColumns.length > 0) $picker.columns = pickerColumns;
// Wait for visible custom event, 'cause "On iOS, this method must be called after the picker is rendered."
$picker.addEventListener('visible', function(e) {
Data[ $this._uid ].values.forEach(function(rows, columnIndex) {
$picker.setSelectedRow(columnIndex, Data[ $this._uid ].indexes[columnIndex], false);
});
});
}
Data[ $this._uid ].eventsIndexes = [];
}
function createTiUIPicker($this, opt) {
var $picker = null;
if ($this.typeString === 'plain') {
$picker = Ti.UI.createPicker(opt || {});
fillPickerData($this, $picker);
$picker.addEventListener('change', function(e) {
Data[ $this._uid ].eventsIndexes[e.columnIndex] = e.rowIndex;
});
} else if ($this.typeString === 'date') {
$picker = Ti.UI.createPicker(_.extend({}, opt, {
value: $this.getValue(),
minDate: $this.minDate,
maxDate: $this.maxDate,
type: Ti.UI.PICKER_TYPE_DATE,
}));
}
return $picker;
}
// Get the two buttons in the toolbar
function UIPickerButtons($this, $picker, callbacks) {
var $doneBtn = Ti.UI.createButton({ title: L('done', 'Done') });
$doneBtn.addEventListener('click', function() {
if ($this.typeString === 'plain') {
Data[ $this._uid ].eventsIndexes.forEach(function(rowIndex, columnIndex) {
if (rowIndex != null && rowIndex > -1) {
Data[ $this._uid ].indexes[columnIndex] = rowIndex;
var row = Data[ $this._uid ].values[columnIndex][rowIndex];
if (row != null) {
Data[ $this._uid ].value[columnIndex] = row.value;
Data[ $this._uid ].titles[columnIndex] = row.title;
}
}
});
} else if ($this.typeString === 'date') {
Data[ $this._uid ].value = $picker.value;
}
$this.updateUI();
callbacks.done();
});
var $cancelBtn = Ti.UI.createButton({ title: L('cancel', 'Cancel') });
$cancelBtn.addEventListener('click', function() {
callbacks.cancel();
});
return {
done: $doneBtn,
cancel: $cancelBtn
};
}
var UIPickers = {
// Show the picker in a Window that slide in from the bottom
iphone: function($this) {
var $picker = createTiUIPicker($this, {
width: PICKER_WIDTH_IPHONE,
height: PICKER_HEIGHT_IPHONE
});
var buttons = UIPickerButtons($this, $picker, {
cancel: function() {
$this.fireEvent('cancel');
$pickerModal.close();
},
done: function() {
$pickerModal.close();
}
});
var $toolbar = Ti.UI.iOS.createToolbar({
items: [
buttons.cancel,
Ti.UI.createButton({ systemButton: Ti.UI.iPhone.SystemButton.FLEXIBLE_SPACE }),
buttons.done
],
borderTop: true,
borderBottom: false
});
var $containerView = Ti.UI.createView({
height: Ti.UI.SIZE,
width: Ti.UI.FILL,
layout: 'vertical',
bottom: 0,
transform: Ti.UI.create2DMatrix().translate(0, 300)
});
$containerView.add($toolbar);
$containerView.add($picker);
var $pickerModal = Ti.UI.createWindow({
backgroundColor: '#4000',
});
$pickerModal.add($containerView);
$pickerModal.addEventListener('open', function(e) {
$picker.fireEvent('visible');
});
$pickerModal.open();
$containerView.animate({
transform: Ti.UI.create2DMatrix()
});
},
// Show the picker in a Popover Window attached to the Label
ipad: function($this) {
var $picker = createTiUIPicker($this, {
width: PICKER_WIDTH_IPAD
});
var has_value = false;
var buttons = UIPickerButtons($this, $picker, {
cancel: function() {
has_value = false;
$popover.hide();
},
done: function() {
has_value = true;
$popover.hide();
}
});
var $containerWindow = Ti.UI.createWindow({
leftNavButton: buttons.cancel,
rightNavButton: buttons.done,
title: $this.hintText,
navTintColor: $this.tintColor
});
$containerWindow.add($picker);
$containerWindow.addEventListener('open', function(e) {
$picker.fireEvent('visible');
});
$containerWindow.addEventListener('close', function(e) {
if (!has_value) {
$this.fireEvent('cancel');
}
});
var $navigator = Ti.UI.iOS.createNavigationWindow({
window: $containerWindow,
width: PICKER_WIDTH_IPAD,
height: PICKER_HEIGHT_IPAD + 40, // 40 is the toolbar height
});
var $popover = Ti.UI.iPad.createPopover({
contentView: $navigator
});
$popover.show({
view: $this
});
},
android: function($this) {
if ($this.typeString === 'plain') {
var $dialog = null;
if (Data[ $this._uid ].values.length === 1) {
// Implement an OptionDialog
$dialog = Ti.UI.createOptionDialog({
selectedIndex: Data[ $this._uid ].indexes[0],
buttonNames: [ L('done'), L('cancel') ],
options: Data[ $this._uid ].values[0].map(function(e) {
return String(e.title);
})
});
$dialog.addEventListener('click', function(e) {
if (e.cancel === true || (e.button === true && e.index === 1)) {
$this.fireEvent('cancel');
return;
}
Data[ $this._uid ].indexes[0] = e.source.selectedIndex;
var row = Data[ $this._uid ].values[0][e.source.selectedIndex];
if (row != null) {
Data[ $this._uid ].value[0] = row.value;
Data[ $this._uid ].titles[0] = row.title;
}
$this.updateUI();
});
$dialog.show();
} else {
// AlertDialog with AndroidView with TiUIPicker
var $dialogPickers = [];
$dialog = Ti.UI.createAlertDialog({
buttonNames: [ L('done'), L('cancel') ],
androidView: (function() {
var $a = Ti.UI.createView({
height: Ti.UI.SIZE
});
var len = Data[ $this._uid ].values.length;
var $wrap = Ti.UI.createView({
layout: len <= 3 ? 'horizontal' : 'vertical',
width: len <= 3 ? '100%' : '80%'
});
Data[ $this._uid ].values.forEach(function(column, columnIndex) {
var $picker = Ti.UI.createPicker({
height: 60,
width: len <= 3 ? (Math.floor(100/len)+'%') : '100%',
top: 15,
columns: [ getPickerColumn(column) ]
});
$picker.setSelectedRow(0, Data[ $this._uid].indexes[columnIndex]);
$picker.addEventListener('change', function(e) {
$picker._rowIndex = e.rowIndex;
});
$dialogPickers.push($picker);
$wrap.add($picker);
});
$a.add( $wrap );
return $a;
})()
});
$dialog.addEventListener('click', function(e) {
if (e.cancel || (e.button === true && e.index === 1)) {
$this.fireEvent('cancel');
return;
}
$dialogPickers.forEach(function($p, columnIndex) {
if ($p._rowIndex != null && $p._rowIndex > -1) {
Data[ $this._uid ].indexes[columnIndex] = $p._rowIndex;
var row = Data[ $this._uid ].values[columnIndex][$p._rowIndex];
if (row != null) {
Data[ $this._uid ].value[columnIndex] = row.value;
Data[ $this._uid ].titles[columnIndex] = row.title;
}
}
});
$this.updateUI();
});
}
$dialog.show();
} else if ($this.typeString === 'date') {
Ti.UI.createPicker(
_.extend({}, _.pick($this, 'minDate', 'maxDate'), {
typeString: Ti.UI.PICKER_TYPE_DATE,
})
).showDatePickerDialog({
value: $this.getValue(),
callback: function(e) {
if (e.value == null || e.cancel) return;
Data[ $this._uid ].value = e.value;
$this.updateUI();
}
});
}
}
};
function dataPickerInterface(type, opt) {
var self = {};
if (type === 'plain') {
self.values = opt.columns.map(function(column, columnIndex) {
return column.map(function(row, rowIndex) {
var val = null;
var current = opt.columnsValues != null ? opt.columnsValues[columnIndex] : null;
if (_.isObject(row)) {
val = _.extend({}, row, {
index: rowIndex,
selected: (current != null && _.isEqual(current, row.value))
});
} else {
val = {
title: row.toString(),
value: row,
index: rowIndex,
selected: (current != null && current == row)
};
}
if (_.isEmpty(val.title)) {
val.title = L('no_value');
}
return val;
});
});
self.value = [];
self.indexes = [];
self.titles = [];
_.each(self.values, function(rows, columnIndex) {
var row = _.findWhere(rows, { selected: true });
if (row != null) {
self.value[columnIndex] = row.value;
self.indexes[columnIndex] = row.index;
self.titles[columnIndex] = row.title;
} else {
self.value[columnIndex] = rows[0].value;
self.indexes[columnIndex] = 0;
self.titles[columnIndex] = rows[0].title;
}
});
} else if (type === 'date') {
self.value = opt.value || new Date();
}
return self;
}
module.exports = function(args) {
args = _.defaults(args || {}, {
/**
* @property {String} [dateFormat='D MMMM YYYY']
*/
dateFormat: 'D MMMM YYYY',
/**
* @property {Array} [columns=[]]
* An array containing arrays of values.
* For each entry you can specify an entry like `{ value: '1', title: 'One' }` to define different title/values.
* Alternatively, just declare an entry with a primitive value.
*/
columns: [],
/**
* @property {Object} [columnsValues=null]
* Values of the columns
*/
columnsValues: null,
/**
* @property {Array} [values=null]
* @deprecated Use columns instead
* Shorthand for a single-columns values
*/
values: null,
/**
* @property {Object} [value=null]
* @deprecated Use columnsValues instead
* Shorthand for a single-columns columnsValues
*/
value: null,
/**
* @property {String} [type="plain"]
* Type of the picker. Could be `plain`, `date`.
*/
type: 'plain'
});
if (args.values != null) {
args.columns = [ args.values ];
args.columnsValues = [ args.value ];
}
args._uid = _.uniqueId();
// Create a unique interface
Data[ args._uid ] = dataPickerInterface(args.type, {
// For plain
columnsValues: args.columnsValues,
columns: args.columns,
// For date
value: args.value
});
delete args.columns;
delete args.columnsValues;
delete args.value;
delete args.values;
args.typeString = args.type;
delete args.type;
// Start UI
var $this = null;
_.defaults(args, {
height: 48,
width: Ti.UI.FILL
});
$this = Ti.UI.createLabel(args);
$this.addEventListener('click', function(){
$this.open();
});
$this.updateUI = function(trigger) {
var val = $this.getValue();
if (trigger !== false) {
$this.fireEvent('change', {
value: val,
source: $this
});
}
if ($this.typeString === 'plain') {
var areNullValues = _.every(Data[ $this._uid ].value, function(e) { return e == null; });
if (areNullValues && $this.hintText != null) {
$this.text = $this.hintText;
} else {
$this.text = Data[ $this._uid ].titles.join(' ');
}
} else if ($this.typeString === 'date') {
$this.text = val ? Moment(val).format($this.dateFormat) : ($this.hintText || '');
}
};
/**
* Get the value
* @return {Object}
*/
$this.getValue = function() {
var v = Data[ $this._uid ].value;
if ($this.typeString === 'plain') {
if (v != null && v.length === 1) return v[0];
}
return v;
};
/**
* @param {Object} value
* Set the current value
* Shorthand for setColumnsValues with a single columns picker
*/
$this.setValue = function(value) {
$this.setColumnsValues([ value ]);
};
/**
* @param {Array} values
* Shorthand for setColumns with a single columns picker
*/
$this.setValues = function(values) {
$this.setColumns([ values ]);
};
/**
* Get the internal data interface
*/
$this.getDataInterface = function() {
return Data[ $this._uid ];
};
/**
* @param {Array} columns The columns
* Set the columns for the picker
*/
$this.setColumns = function(columns) {
_.extend(Data[ $this._uid ], dataPickerInterface($this.typeString, {
columnsValues: $this.columnsValues,
columns: columns
}));
$this.updateUI();
};
/**
* @param {Array} columnsValues
*/
$this.setColumnsValues = function(columnsValues) {
if ($this.typeString === 'plain') {
Data[ $this._uid ].value[0] = columnsValues[0];
Data[ $this._uid ].values.forEach(function(rows, columnIndex) {
var row = _.find(rows, function(row) {
return _.isEqual(row.value, columnsValues[columnIndex]);
});
if (row != null) {
Data[ $this._uid ].value[columnIndex] = row.value;
Data[ $this._uid ].indexes[columnIndex] = row.index;
Data[ $this._uid ].titles[columnIndex] = row.title;
} else {
Ti.API.warn('UIFactory.Select: can\'t find this value in the list');
Data[ $this._uid ].value[columnIndex] = null;
Data[ $this._uid ].indexes[columnIndex] = -1;
Data[ $this._uid ].titles[columnIndex] = '';
}
});
} else {
Data[ $this._uid ].value = columnsValues[0];
}
$this.updateUI();
};
/**
* Open the picker
*/
$this.open = function() {
UIPickers[ Ti.Platform.osname ]($this);
};
// Update the UI
$this.updateUI(false);
return $this;
};