<!DOCTYPE html>
|
<html>
|
<head>
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<title>The source code</title>
|
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
|
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
|
<style type="text/css">
|
.highlight { display: block; background-color: #ddd; }
|
</style>
|
<script type="text/javascript">
|
function highlight() {
|
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
|
}
|
</script>
|
</head>
|
<body onload="prettyPrint(); highlight();">
|
<pre class="prettyprint lang-js"><span id='Ext-ux-grid-filter-DateTimeFilter'>/**
|
</span> * Filter by a configurable Ext.picker.DatePicker menu
|
*
|
* This filter allows for the following configurations:
|
*
|
* - Any of the normal configs will be passed through to either component.
|
* - There can be a docked config.
|
* - The timepicker can be on the right or left (datepicker, too, of course).
|
* - Choose which component will initiate the filtering, i.e., the event can be
|
* configured to be bound to either the datepicker or the timepicker, or if
|
* there is a docked config it be automatically have the handler bound to it.
|
*
|
* Although not shown here, this class accepts all configuration options
|
* for {@link Ext.picker.Date} and {@link Ext.picker.Time}.
|
*
|
* In the case that a custom dockedItems config is passed in, the
|
* class will handle binding the default listener to it so the
|
* developer need not worry about having to do it.
|
*
|
* The default dockedItems position and the toolbar's
|
* button text can be passed a config for convenience, i.e.,:
|
*
|
* dock: {
|
* buttonText: 'Click to Filter',
|
* dock: 'left'
|
* }
|
*
|
* Or, pass in a full dockedItems config:
|
*
|
* dock: {
|
* dockedItems: {
|
* xtype: 'toolbar',
|
* dock: 'bottom',
|
* ...
|
* }
|
* }
|
*
|
* Or, give a value of `true` to accept dock defaults:
|
*
|
* dock: true
|
*
|
* But, it must be one or the other.
|
*
|
* Example Usage:
|
*
|
* var filters = Ext.create('Ext.ux.grid.GridFilters', {
|
* ...
|
* filters: [{
|
* // required configs
|
* type: 'datetime',
|
* dataIndex: 'date',
|
*
|
* // optional configs
|
* positionDatepickerFirst: false,
|
* //selectDateToFilter: false, // this is overridden b/c of the presence of the dock cfg object
|
*
|
* date: {
|
* format: 'm/d/Y',
|
* },
|
*
|
* time: {
|
* format: 'H:i:s A',
|
* increment: 1
|
* },
|
*
|
* dock: {
|
* buttonText: 'Click to Filter',
|
* dock: 'left'
|
*
|
* // allows for custom dockedItems cfg
|
* //dockedItems: {}
|
* }
|
* }]
|
* });
|
*
|
* In the above example, note that the filter is being passed a {@link #date} config object,
|
* a {@link #time} config object and a {@link #dock} config. These are all optional.
|
*
|
* As for positioning, the datepicker will be on the right, the timepicker on the left
|
* and the docked items will be docked on the left. In addition, since there's a {@link #dock}
|
* config, clicking the button in the dock will trigger the filtering.
|
*/
|
Ext.define('Ext.ux.grid.filter.DateTimeFilter', {
|
extend: 'Ext.ux.grid.filter.DateFilter',
|
alias: 'gridfilter.datetime',
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-property-dateDefaults'> /**
|
</span> * @private
|
*/
|
dateDefaults: {
|
xtype: 'datepicker',
|
format: 'm/d/Y'
|
},
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-property-timeDefaults'> /**
|
</span> * @private
|
*/
|
timeDefaults: {
|
xtype: 'timepicker',
|
width: 100,
|
height: 200,
|
format: 'g:i A'
|
},
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-property-dockDefaults'> /**
|
</span> * @private
|
*/
|
dockDefaults: {
|
dock: 'top',
|
buttonText: 'Filter'
|
},
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-cfg-date'> /**
|
</span> * @cfg {Object} date
|
* A {@link Ext.picker.Date} can be configured here.
|
* Uses {@link #dateDefaults} by default.
|
*/
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-cfg-time'> /**
|
</span> * @cfg {Object} time
|
* A {@link Ext.picker.Time} can be configured here.
|
* Uses {@link #timeDefaults} by default.
|
*/
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-cfg-dock'> /**
|
</span> * @cfg {Boolean/Object} dock
|
* A {@link Ext.panel.AbstractPanel#cfg-dockedItems} can be configured here.
|
* A `true` value will use the {@link #dockDefaults} default configuration.
|
* If present, the button in the docked items will initiate the filtering.
|
*/
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-cfg-selectDateToFilter'> /**
|
</span> * @cfg {Boolean} [selectDateToFilter=true]
|
* By default, the datepicker has the default event listener bound to it.
|
* Setting to `false` will bind it to the timepicker.
|
*
|
* The config will be ignored if there is a `dock` config.
|
*/
|
selectDateToFilter: true,
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-cfg-positionDatepickerFirst'> /**
|
</span> * @cfg {Boolean} [positionDatepickerFirst=true]
|
* Positions the datepicker within its container.
|
* A `true` value will place it on the left in the container.
|
* Set to `false` if the timepicker should be placed on the left.
|
* Defaults to `true`.
|
*/
|
positionDatepickerFirst: true,
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-property-reTime'> reTime: /\s(am|pm)/i,
|
</span><span id='Ext-ux-grid-filter-DateTimeFilter-property-reItemId'> reItemId: /\w*-(\w*)$/,
|
</span>
|
<span id='Ext-ux-grid-filter-DateTimeFilter-method-addTimeSelection'> /**
|
</span> * Replaces the selected value of the timepicker with the default 00:00:00.
|
* @private
|
* @param {Object} date
|
* @param {Ext.picker.Time} timepicker
|
* @return Date object
|
*/
|
addTimeSelection: function (date, timepicker) {
|
var me = this,
|
selection = timepicker.getSelectionModel().getSelection(),
|
time, len, fn, val,
|
i = 0,
|
arr = [],
|
timeFns = ['setHours', 'setMinutes', 'setSeconds', 'setMilliseconds'];
|
|
|
if (selection.length) {
|
time = selection[0].get('disp');
|
|
// Loop through all of the splits and add the time values.
|
arr = time.replace(me.reTime, '').split(':');
|
|
for (len = arr.length; i < len; i++) {
|
fn = timeFns[i];
|
val = arr[i];
|
|
if (val) {
|
date[fn](parseInt(val, 10));
|
}
|
}
|
}
|
|
return date;
|
},
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-method-init'> /**
|
</span> * @private
|
* Template method that is to initialize the filter and install required menu items.
|
*/
|
init: function (config) {
|
var me = this,
|
dateCfg = Ext.applyIf(me.date || {}, me.dateDefaults),
|
timeCfg = Ext.applyIf(me.time || {}, me.timeDefaults),
|
dockCfg = me.dock, // should not default to empty object
|
defaultListeners = {
|
click: {
|
scope: me,
|
click: me.onMenuSelect
|
},
|
select: {
|
scope: me,
|
select: me.onMenuSelect
|
}
|
},
|
pickerCtnCfg, i, len, item, cfg,
|
items = [dateCfg, timeCfg],
|
|
// we need to know the datepicker's position in the items array
|
// for when the itemId name is bound to it before adding to the menu
|
datepickerPosition = 0;
|
|
if (!me.positionDatepickerFirst) {
|
items = items.reverse();
|
datepickerPosition = 1;
|
}
|
|
pickerCtnCfg = Ext.apply(me.pickerOpts, {
|
xtype: !dockCfg ? 'container' : 'panel',
|
layout: 'hbox',
|
items: items
|
});
|
|
// If there's no dock config then bind the default listener to the desired picker.
|
if (!dockCfg) {
|
if (me.selectDateToFilter) {
|
dateCfg.listeners = defaultListeners.select;
|
} else {
|
timeCfg.listeners = defaultListeners.select;
|
}
|
} else if (dockCfg) {
|
me.selectDateToFilter = null;
|
|
if (dockCfg.dockedItems) {
|
pickerCtnCfg.dockedItems = dockCfg.dockedItems;
|
// TODO: allow config that will tell which item to bind the listener to
|
// right now, it's using the first item
|
pickerCtnCfg.dockedItems.items[dockCfg.bindToItem || 0].listeners = defaultListeners.click;
|
} else {
|
// dockCfg can be `true` if button text and dock position defaults are wanted
|
if (Ext.isBoolean(dockCfg)) {
|
dockCfg = {};
|
}
|
dockCfg = Ext.applyIf(dockCfg, me.dockDefaults);
|
pickerCtnCfg.dockedItems = {
|
xtype: 'toolbar',
|
dock: dockCfg.dock,
|
items: [
|
{
|
xtype: 'button',
|
text: dockCfg.buttonText,
|
flex: 1,
|
listeners: defaultListeners.click
|
}
|
]
|
};
|
}
|
}
|
|
me.fields = {};
|
for (i = 0, len = me.menuItems.length; i < len; i++) {
|
item = me.menuItems[i];
|
if (item !== '-') {
|
pickerCtnCfg.items[datepickerPosition].itemId = item;
|
|
cfg = {
|
itemId: 'range-' + item,
|
text: me[item + 'Text'],
|
menu: Ext.create('Ext.menu.Menu', {
|
items: pickerCtnCfg
|
}),
|
listeners: {
|
scope: me,
|
checkchange: me.onCheckChange
|
}
|
};
|
item = me.fields[item] = Ext.create('Ext.menu.CheckItem', cfg);
|
}
|
me.menu.add(item);
|
}
|
me.values = {};
|
},
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-method-onCheckChange'> /**
|
</span> * @private
|
*/
|
onCheckChange: function (item, checked) {
|
var me = this,
|
menu = item.menu,
|
timepicker = menu.down('timepicker'),
|
datepicker = menu.down('datepicker'),
|
itemId = datepicker.itemId,
|
values = me.values;
|
|
if (checked) {
|
values[itemId] = me.addTimeSelection(datepicker.value, timepicker);
|
} else {
|
delete values[itemId];
|
}
|
me.setActive(me.isActivatable());
|
me.fireEvent('update', me);
|
},
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-method-onMenuSelect'> /**
|
</span> * Handler for when the DatePicker for a field fires the 'select' event
|
* @param {Ext.picker.Date} picker
|
* @param {Object} date
|
*/
|
onMenuSelect: function (picker, date) {
|
// NOTE: we need to redefine the picker.
|
var me = this,
|
menu = me.menu,
|
checkItemId = menu.getFocusEl().itemId.replace(me.reItemId, '$1'),
|
fields = me.fields,
|
field;
|
|
picker = menu.queryById(checkItemId);
|
field = me.fields[picker.itemId];
|
field.setChecked(true);
|
|
if (field == fields.on) {
|
fields.before.setChecked(false, true);
|
fields.after.setChecked(false, true);
|
} else {
|
fields.on.setChecked(false, true);
|
if (field == fields.after && me.getFieldValue('before') < date) {
|
fields.before.setChecked(false, true);
|
} else if (field == fields.before && me.getFieldValue('after') > date) {
|
fields.after.setChecked(false, true);
|
}
|
}
|
me.fireEvent('update', me);
|
|
// The timepicker's getBubbleTarget() returns the boundlist's implementation,
|
// so it doesn't look up ownerCt chain (it looks up this.pickerField).
|
// This is a problem :)
|
// This can be fixed by just walking up the ownerCt chain
|
// (same thing, but confusing without comment).
|
picker.ownerCt.ownerCt.hide();
|
},
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-method-getSerialArgs'> /**
|
</span> * @private
|
* Template method that is to get and return serialized filter data for
|
* transmission to the server.
|
* @return {Object/Array} An object or collection of objects containing
|
* key value pairs representing the current configuration of the filter.
|
*/
|
getSerialArgs: function () {
|
var me = this,
|
key,
|
fields = me.fields,
|
args = [];
|
|
for (key in fields) {
|
if (fields[key].checked) {
|
args.push({
|
type: 'datetime',
|
comparison: me.compareMap[key],
|
value: Ext.Date.format(me.getFieldValue(key), (me.date.format || me.dateDefaults.format) + ' ' + (me.time.format || me.timeDefaults.format))
|
});
|
}
|
}
|
return args;
|
},
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-method-setValue'> /**
|
</span> * @private
|
* Template method that is to set the value of the filter.
|
* @param {Object} value The value to set the filter
|
* @param {Boolean} preserve true to preserve the checked status
|
* of the other fields. Defaults to false, unchecking the
|
* other fields
|
*/
|
setValue: function (value, preserve) {
|
var me = this,
|
fields = me.fields,
|
key,
|
val,
|
datepicker;
|
|
for (key in fields) {
|
val = value[key];
|
if (val) {
|
datepicker = me.menu.down('datepicker[itemId="' + key + '"]');
|
// Note that calling the Ext.picker.Date:setValue() calls Ext.Date.clearTime(),
|
// which we don't want, so just call update() instead and set the value on the component.
|
datepicker.update(val);
|
datepicker.value = val;
|
|
fields[key].setChecked(true);
|
} else if (!preserve) {
|
fields[key].setChecked(false);
|
}
|
}
|
me.fireEvent('update', me);
|
},
|
|
<span id='Ext-ux-grid-filter-DateTimeFilter-method-validateRecord'> /**
|
</span> * Template method that is to validate the provided Ext.data.Record
|
* against the filters configuration.
|
* @param {Ext.data.Record} record The record to validate
|
* @return {Boolean} true if the record is valid within the bounds
|
* of the filter, false otherwise.
|
*/
|
validateRecord: function (record) {
|
// remove calls to Ext.Date.clearTime
|
var me = this,
|
key,
|
pickerValue,
|
val = record.get(me.dataIndex);
|
|
if(!Ext.isDate(val)){
|
return false;
|
}
|
|
val = val.getTime();
|
|
for (key in me.fields) {
|
if (me.fields[key].checked) {
|
pickerValue = me.getFieldValue(key).getTime();
|
if (key == 'before' && pickerValue <= val) {
|
return false;
|
}
|
if (key == 'after' && pickerValue >= val) {
|
return false;
|
}
|
if (key == 'on' && pickerValue != val) {
|
return false;
|
}
|
}
|
}
|
return true;
|
}
|
});
|
</pre>
|
</body>
|
</html>
|