X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/c930e9176a5a85509c5b0230e2bff5c22a591432..refs/tags/3.0.3:/examples/ux/ux-all-debug.js
diff --git a/examples/ux/ux-all-debug.js b/examples/ux/ux-all-debug.js
index 6ef28d4d..695e1cec 100644
--- a/examples/ux/ux-all-debug.js
+++ b/examples/ux/ux-all-debug.js
@@ -1,5 +1,5 @@
/*!
- * Ext JS Library 3.0.0
+ * Ext JS Library 3.0.3
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
@@ -157,6 +157,13 @@ Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, {
this.doUpdate();
}
},
+
+ onRemove : function(ds, record, index, isUpdate){
+ Ext.ux.grid.BufferView.superclass.onRemove.apply(this, arguments);
+ if(isUpdate !== true){
+ this.update();
+ }
+ },
doUpdate: function(){
if (this.getVisibleRowCount() > 0) {
@@ -539,6 +546,9 @@ Ext.DataView.DragSelector = function(cfg){
if(!proxy){
proxy = view.el.createChild({cls:'x-view-selector'});
}else{
+ if(proxy.dom.parentNode !== view.el.dom){
+ view.el.dom.appendChild(proxy.dom);
+ }
proxy.setDisplayed('block');
}
fillRegions();
@@ -653,15 +663,7 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
this.wrap = this.el.wrap({cls:'x-form-field-wrap x-form-file-wrap'});
this.el.addClass('x-form-file-text');
this.el.dom.removeAttribute('name');
-
- this.fileInput = this.wrap.createChild({
- id: this.getFileInputId(),
- name: this.name||this.getId(),
- cls: 'x-form-file',
- tag: 'input',
- type: 'file',
- size: 1
- });
+ this.createFileInput();
var btnCfg = Ext.applyIf(this.buttonCfg || {}, {
text: this.buttonText
@@ -676,11 +678,49 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
this.wrap.setWidth(this.button.getEl().getWidth());
}
- this.fileInput.on('change', function(){
- var v = this.fileInput.dom.value;
- this.setValue(v);
- this.fireEvent('fileselected', this, v);
- }, this);
+ this.bindListeners();
+ this.resizeEl = this.positionEl = this.wrap;
+ },
+
+ bindListeners: function(){
+ this.fileInput.on({
+ scope: this,
+ mouseenter: function() {
+ this.button.addClass(['x-btn-over','x-btn-focus'])
+ },
+ mouseleave: function(){
+ this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click'])
+ },
+ mousedown: function(){
+ this.button.addClass('x-btn-click')
+ },
+ mouseup: function(){
+ this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click'])
+ },
+ change: function(){
+ var v = this.fileInput.dom.value;
+ this.setValue(v);
+ this.fireEvent('fileselected', this, v);
+ }
+ });
+ },
+
+ createFileInput : function() {
+ this.fileInput = this.wrap.createChild({
+ id: this.getFileInputId(),
+ name: this.name||this.getId(),
+ cls: 'x-form-file',
+ tag: 'input',
+ type: 'file',
+ size: 1
+ });
+ },
+
+ reset : function(){
+ this.fileInput.remove();
+ this.createFileInput();
+ this.bindListeners();
+ Ext.ux.form.FileUploadField.superclass.reset.call(this);
},
// private
@@ -705,20 +745,27 @@ Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, {
Ext.ux.form.FileUploadField.superclass.onDestroy.call(this);
Ext.destroy(this.fileInput, this.button, this.wrap);
},
+
+ onDisable: function(){
+ Ext.ux.form.FileUploadField.superclass.onDisable.call(this);
+ this.doDisable(true);
+ },
+
+ onEnable: function(){
+ Ext.ux.form.FileUploadField.superclass.onEnable.call(this);
+ this.doDisable(false);
-
- // private
- preFocus : Ext.emptyFn,
-
+ },
+
// private
- getResizeEl : function(){
- return this.wrap;
+ doDisable: function(disabled){
+ this.fileInput.dom.disabled = disabled;
+ this.button.setDisabled(disabled);
},
+
// private
- getPositionEl : function(){
- return this.wrap;
- },
+ preFocus : Ext.emptyFn,
// private
alignErrorIcon : function(){
@@ -731,1020 +778,2305 @@ Ext.reg('fileuploadfield', Ext.ux.form.FileUploadField);
// backwards compat
Ext.form.FileUploadField = Ext.ux.form.FileUploadField;
-(function(){
-Ext.ns('Ext.a11y');
+/**
+ * @class Ext.ux.GMapPanel
+ * @extends Ext.Panel
+ * @author Shea Frederick
+ */
+Ext.ux.GMapPanel = Ext.extend(Ext.Panel, {
+ initComponent : function(){
+
+ var defConfig = {
+ plain: true,
+ zoomLevel: 3,
+ yaw: 180,
+ pitch: 0,
+ zoom: 0,
+ gmapType: 'map',
+ border: false
+ };
+
+ Ext.applyIf(this,defConfig);
+
+ Ext.ux.GMapPanel.superclass.initComponent.call(this);
-Ext.a11y.Frame = Ext.extend(Object, {
- initialized: false,
-
- constructor: function(size, color){
- this.setSize(size || 1);
- this.setColor(color || '15428B');
},
-
- init: function(){
- if (!this.initialized) {
- this.sides = [];
-
- var s, i;
-
- this.ct = Ext.DomHelper.append(document.body, {
- cls: 'x-a11y-focusframe'
- }, true);
-
- for (i = 0; i < 4; i++) {
- s = Ext.DomHelper.append(this.ct, {
- cls: 'x-a11y-focusframe-side',
- style: 'background-color: #' + this.color
- }, true);
- s.visibilityMode = Ext.Element.DISPLAY;
- this.sides.push(s);
- }
-
- this.frameTask = new Ext.util.DelayedTask(function(el){
- var newEl = Ext.get(el);
- if (newEl != this.curEl) {
- var w = newEl.getWidth();
- var h = newEl.getHeight();
- this.sides[0].show().setSize(w, this.size).anchorTo(el, 'tl', [0, -1]);
- this.sides[2].show().setSize(w, this.size).anchorTo(el, 'bl', [0, -1]);
- this.sides[1].show().setSize(this.size, h).anchorTo(el, 'tr', [-1, 0]);
- this.sides[3].show().setSize(this.size, h).anchorTo(el, 'tl', [-1, 0]);
- this.curEl = newEl;
+ afterRender : function(){
+
+ var wh = this.ownerCt.getSize();
+ Ext.applyIf(this, wh);
+
+ Ext.ux.GMapPanel.superclass.afterRender.call(this);
+
+ if (this.gmapType === 'map'){
+ this.gmap = new GMap2(this.body.dom);
+ }
+
+ if (this.gmapType === 'panorama'){
+ this.gmap = new GStreetviewPanorama(this.body.dom);
+ }
+
+ if (typeof this.addControl == 'object' && this.gmapType === 'map') {
+ this.gmap.addControl(this.addControl);
+ }
+
+ if (typeof this.setCenter === 'object') {
+ if (typeof this.setCenter.geoCodeAddr === 'string'){
+ this.geoCodeLookup(this.setCenter.geoCodeAddr);
+ }else{
+ if (this.gmapType === 'map'){
+ var point = new GLatLng(this.setCenter.lat,this.setCenter.lng);
+ this.gmap.setCenter(point, this.zoomLevel);
}
- }, this);
-
- this.unframeTask = new Ext.util.DelayedTask(function(){
- if (this.initialized) {
- this.sides[0].hide();
- this.sides[1].hide();
- this.sides[2].hide();
- this.sides[3].hide();
- this.curEl = null;
+ if (typeof this.setCenter.marker === 'object' && typeof point === 'object'){
+ this.addMarker(point,this.setCenter.marker,this.setCenter.marker.clear);
}
- }, this);
- this.initialized = true;
+ }
+ if (this.gmapType === 'panorama'){
+ this.gmap.setLocationAndPOV(new GLatLng(this.setCenter.lat,this.setCenter.lng), {yaw: this.yaw, pitch: this.pitch, zoom: this.zoom});
+ }
}
+
+ GEvent.bind(this.gmap, 'load', this, function(){
+ this.onMapReady();
+ });
+
},
-
- frame: function(el){
- this.init();
- this.unframeTask.cancel();
- this.frameTask.delay(2, false, false, [el]);
- },
-
- unframe: function(){
- this.init();
- this.unframeTask.delay(2);
- },
-
- setSize: function(size){
- this.size = size;
+ onMapReady : function(){
+ this.addMarkers(this.markers);
+ this.addMapControls();
+ this.addOptions();
},
-
- setColor: function(color){
- this.color = color;
- }
-});
-
-Ext.a11y.FocusFrame = new Ext.a11y.Frame(2, '15428B');
-Ext.a11y.RelayFrame = new Ext.a11y.Frame(1, '6B8CBF');
+ onResize : function(w, h){
-Ext.a11y.Focusable = Ext.extend(Ext.util.Observable, {
- constructor: function(el, relayTo, noFrame, frameEl){
- Ext.a11y.Focusable.superclass.constructor.call(this);
+ if (typeof this.getMap() == 'object') {
+ this.gmap.checkResize();
+ }
- this.addEvents('focus', 'blur', 'left', 'right', 'up', 'down', 'esc', 'enter', 'space');
+ Ext.ux.GMapPanel.superclass.onResize.call(this, w, h);
+
+ },
+ setSize : function(width, height, animate){
- if (el instanceof Ext.Component) {
- this.el = el.el;
- this.setComponent(el);
- }
- else {
- this.el = Ext.get(el);
- this.setComponent(null);
+ if (typeof this.getMap() == 'object') {
+ this.gmap.checkResize();
}
- this.setRelayTo(relayTo)
- this.setNoFrame(noFrame);
- this.setFrameEl(frameEl);
-
- this.init();
+ Ext.ux.GMapPanel.superclass.setSize.call(this, width, height, animate);
- Ext.a11y.FocusMgr.register(this);
- },
-
- init: function(){
- this.el.dom.tabIndex = '1';
- this.el.addClass('x-a11y-focusable');
- this.el.on({
- focus: this.onFocus,
- blur: this.onBlur,
- keydown: this.onKeyDown,
- scope: this
- });
- },
-
- setRelayTo: function(relayTo){
- this.relayTo = relayTo ? Ext.a11y.FocusMgr.get(relayTo) : null;
- },
-
- setNoFrame: function(noFrame){
- this.noFrame = (noFrame === true) ? true : false;
- },
-
- setFrameEl: function(frameEl){
- this.frameEl = frameEl && Ext.get(frameEl) || this.el;
- },
-
- setComponent: function(cmp){
- this.component = cmp || null;
},
-
- onKeyDown: function(e, t){
- var k = e.getKey(), SK = Ext.a11y.Focusable.SpecialKeys, ret, tf;
+ getMap : function(){
- tf = (t !== this.el.dom) ? Ext.a11y.FocusMgr.get(t, true) : this;
- if (!tf) {
- // this can happen when you are on a focused item within a panel body
- // that is not a Ext.a11y.Focusable
- tf = Ext.a11y.FocusMgr.get(Ext.fly(t).parent('.x-a11y-focusable'));
- }
+ return this.gmap;
- if (SK[k] !== undefined) {
- ret = this.fireEvent(SK[k], e, t, tf, this);
- }
- if (ret === false || this.fireEvent('keydown', e, t, tf, this) === false) {
- e.stopEvent();
- }
},
-
- focus: function(){
- this.el.dom.focus();
+ getCenter : function(){
+
+ return this.getMap().getCenter();
+
},
-
- blur: function(){
- this.el.dom.blur();
+ getCenterLatLng : function(){
+
+ var ll = this.getCenter();
+ return {lat: ll.lat(), lng: ll.lng()};
+
},
-
- onFocus: function(e, t){
- this.el.addClass('x-a11y-focused');
- if (this.relayTo) {
- this.relayTo.el.addClass('x-a11y-focused-relay');
- if (!this.relayTo.noFrame) {
- Ext.a11y.FocusFrame.frame(this.relayTo.frameEl);
- }
- if (!this.noFrame) {
- Ext.a11y.RelayFrame.frame(this.frameEl);
- }
- }
- else {
- if (!this.noFrame) {
- Ext.a11y.FocusFrame.frame(this.frameEl);
+ addMarkers : function(markers) {
+
+ if (Ext.isArray(markers)){
+ for (var i = 0; i < markers.length; i++) {
+ var mkr_point = new GLatLng(markers[i].lat,markers[i].lng);
+ this.addMarker(mkr_point,markers[i].marker,false,markers[i].setCenter, markers[i].listeners);
}
}
- this.fireEvent('focus', e, t, this);
},
-
- onBlur: function(e, t){
- if (this.relayTo) {
- this.relayTo.el.removeClass('x-a11y-focused-relay');
- Ext.a11y.RelayFrame.unframe();
+ addMarker : function(point, marker, clear, center, listeners){
+
+ Ext.applyIf(marker,G_DEFAULT_ICON);
+
+ if (clear === true){
+ this.getMap().clearOverlays();
}
- this.el.removeClass('x-a11y-focused');
- Ext.a11y.FocusFrame.unframe();
- this.fireEvent('blur', e, t, this);
- },
-
- destroy: function(){
- this.el.un('keydown', this.onKeyDown);
- this.el.un('focus', this.onFocus);
- this.el.un('blur', this.onBlur);
- this.el.removeClass('x-a11y-focusable');
- this.el.removeClass('x-a11y-focused');
- if (this.relayTo) {
- this.relayTo.el.removeClass('x-a11y-focused-relay');
+ if (center === true) {
+ this.getMap().setCenter(point, this.zoomLevel);
}
- }
-});
-Ext.a11y.FocusItem = Ext.extend(Object, {
- constructor: function(el, enableTabbing){
- Ext.a11y.FocusItem.superclass.constructor.call(this);
-
- this.el = Ext.get(el);
- this.fi = new Ext.a11y.Focusable(el);
- this.fi.setComponent(this);
-
- this.fi.on('tab', this.onTab, this);
-
- this.enableTabbing = enableTabbing === true ? true : false;
- },
-
- getEnterItem: function(){
- if (this.enableTabbing) {
- var items = this.getFocusItems();
- if (items && items.length) {
- return items[0];
+ var mark = new GMarker(point,marker);
+ if (typeof listeners === 'object'){
+ for (evt in listeners) {
+ GEvent.bind(mark, evt, this, listeners[evt]);
}
}
+ this.getMap().addOverlay(mark);
+
},
-
- getFocusItems: function(){
- if (this.enableTabbing) {
- return this.el.query('a, button, input, select');
- }
- return null;
- },
-
- onTab: function(e, t){
- var items = this.getFocusItems(), i;
+ addMapControls : function(){
- if (items && items.length && (i = items.indexOf(t)) !== -1) {
- if (e.shiftKey && i > 0) {
- e.stopEvent();
- items[i - 1].focus();
- Ext.a11y.FocusFrame.frame.defer(20, Ext.a11y.FocusFrame, [this.el]);
- return;
- }
- else
- if (!e.shiftKey && i < items.length - 1) {
- e.stopEvent();
- items[i + 1].focus();
- Ext.a11y.FocusFrame.frame.defer(20, Ext.a11y.FocusFrame, [this.el]);
- return;
+ if (this.gmapType === 'map') {
+ if (Ext.isArray(this.mapControls)) {
+ for(i=0;i GridFilter is a plugin ( Filtering is adjusted by the user using the grid's column header menu
+ * (this menu can be disabled through configuration). Through this menu users
+ * can configure, enable, and disable filters for each column. Features: Example usage: Example Usage:
Level '+accuracy+' Accuracy (8 = Exact Match, 1 = Vague Match)');
+ }else{
+ point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
+ if (typeof this.setCenter.marker === 'object' && typeof point === 'object'){
+ this.addMarker(point,this.setCenter.marker,this.setCenter.marker.clear,true, this.setCenter.listeners);
+ }
+ }
+ }
}
- e.stopPropagation();
- },
-
- onEsc: function(e, t){
- e.preventDefault();
- // check to see if esc is pressed while "inside" the panel
- // or while "on" the panel
- if (t === this.el.dom) {
- // "on" the panel, check if this panel has an owner panel and focus that
- // we dont stop the event in this case so that this same check will be
- // done for this ownerCt
- if (this.ownerCt) {
- this.ownerCt.focus();
+ }
+
+});
+
+Ext.reg('gmappanel', Ext.ux.GMapPanel); Ext.namespace('Ext.ux.grid');
+
+/**
+ * @class Ext.ux.grid.GridFilters
+ * @extends Ext.util.Observable
+ * ptype='gridfilters'
) for grids that
+ * allow for a slightly more robust representation of filtering than what is
+ * provided by the default store.
+ *
stateId
in the Grid configuration.
+ * {@link Ext.grid.GridPanel#beforestaterestore beforestaterestore}
+ * and {@link Ext.grid.GridPanel#beforestatesave beforestatesave}
+ * events in order to be stateful.
+ *
+ *
filters
property is added to the grid pointing to
+ * this plugin.filterupdate
event is added to the grid and is
+ * fired upon onStateChange completion.
+ *
+ */
+Ext.ux.grid.GridFilters = Ext.extend(Ext.util.Observable, {
+ /**
+ * @cfg {Boolean} autoReload
+ * Defaults to true, reloading the datasource when a filter change happens.
+ * Set this to false to prevent the datastore from being reloaded if there
+ * are changes to the filters. See
+var store = new Ext.data.GroupingStore({
+ ...
+});
+
+var filters = new Ext.ux.grid.GridFilters({
+ autoReload: false, //don't reload automatically
+ local: true, //only filter locally
+ // filters may be configured through the plugin,
+ // or in the column definition within the column model configuration
+ filters: [{
+ type: 'numeric',
+ dataIndex: 'id'
+ }, {
+ type: 'string',
+ dataIndex: 'name'
+ }, {
+ type: 'numeric',
+ dataIndex: 'price'
+ }, {
+ type: 'date',
+ dataIndex: 'dateAdded'
+ }, {
+ type: 'list',
+ dataIndex: 'size',
+ options: ['extra small', 'small', 'medium', 'large', 'extra large'],
+ phpMode: true
+ }, {
+ type: 'boolean',
+ dataIndex: 'visible'
+ }]
+});
+var cm = new Ext.grid.ColumnModel([{
+ ...
+}]);
+
+var grid = new Ext.grid.GridPanel({
+ ds: store,
+ cm: cm,
+ view: new Ext.grid.GroupingView(),
+ plugins: [filters],
+ height: 400,
+ width: 700,
+ bbar: new Ext.PagingToolbar({
+ store: store,
+ pageSize: 15,
+ plugins: [filters] //reset page to page 1 if filters change
+ })
+ });
+
+store.load({params: {start: 0, limit: 15}});
+
+// a filters property is added to the grid
+grid.filters
+ *
{@link updateBuffer}
.
+ */
+ autoReload : true,
+ /**
+ * @cfg {Boolean} encode
+ * Specify true for {@link #buildQuery} to use Ext.util.JSON.encode to
+ * encode the filter query parameter sent with a remote request.
+ * Defaults to false.
+ */
+ /**
+ * @cfg {Array} filters
+ * An Array of filters config objects. Refer to each filter type class for
+ * configuration details specific to each filter type. Filters for Strings,
+ * Numeric Ranges, Date Ranges, Lists, and Boolean are the standard filters
+ * available.
+ */
+ /**
+ * @cfg {String} filterCls
+ * The css class to be applied to column headers with active filters.
+ * Defaults to 'ux-filterd-column'.
+ */
+ filterCls : 'ux-filtered-column',
+ /**
+ * @cfg {Boolean} local
+ * true to use Ext.data.Store filter functions (local filtering)
+ * instead of the default (false) server side filtering.
+ */
+ local : false,
+ /**
+ * @cfg {String} menuFilterText
+ * defaults to 'Filters'.
+ */
+ menuFilterText : 'Filters',
+ /**
+ * @cfg {String} paramPrefix
+ * The url parameter prefix for the filters.
+ * Defaults to 'filter'.
+ */
+ paramPrefix : 'filter',
+ /**
+ * @cfg {Boolean} showMenu
+ * Defaults to true, including a filter submenu in the default header menu.
+ */
+ showMenu : true,
+ /**
+ * @cfg {String} stateId
+ * Name of the value to be used to store state information.
+ */
+ stateId : undefined,
+ /**
+ * @cfg {Integer} updateBuffer
+ * Number of milliseconds to defer store updates since the last filter change.
+ */
+ updateBuffer : 500,
+
+ /** @private */
+ constructor : function (config) {
+ this.deferredUpdate = new Ext.util.DelayedTask(this.reload, this);
+ this.filters = new Ext.util.MixedCollection();
+ this.filters.getKey = function (o) {
+ return o ? o.dataIndex : null;
+ };
+ this.addFilters(config.filters);
+ delete config.filters;
+ Ext.apply(this, config);
+ },
+
+ /** @private */
+ init : function (grid) {
+ if (grid instanceof Ext.grid.GridPanel) {
+ this.grid = grid;
+
+ this.bindStore(this.grid.getStore(), true);
+
+ this.grid.filters = this;
+
+ this.grid.addEvents({'filterupdate': true});
+
+ grid.on({
+ scope: this,
+ beforestaterestore: this.applyState,
+ beforestatesave: this.saveState,
+ beforedestroy: this.destroy,
+ reconfigure: this.onReconfigure
+ });
+
+ if (grid.rendered){
+ this.onRender();
+ } else {
+ grid.on({
+ scope: this,
+ single: true,
+ render: this.onRender
+ });
}
+
+ } else if (grid instanceof Ext.PagingToolbar) {
+ this.toolbar = grid;
}
- else {
- // we were inside the panel when esc was pressed,
- // so go back "on" the panel
- if (this.ownerCt && this.ownerCt.isFocusable) {
- var si = this.ownerCt.getFocusItems();
-
- if (si && si.getCount() > 1) {
- e.stopEvent();
+ },
+
+ /**
+ * @private
+ * Handler for the grid's beforestaterestore event (fires before the state of the
+ * grid is restored).
+ * @param {Object} grid The grid object
+ * @param {Object} state The hash of state values returned from the StateProvider.
+ */
+ applyState : function (grid, state) {
+ var key, filter;
+ this.applyingState = true;
+ this.clearFilters();
+ if (state.filters) {
+ for (key in state.filters) {
+ filter = this.filters.get(key);
+ if (filter) {
+ filter.setValue(state.filters[key]);
+ filter.setActive(true);
}
}
- this.focus();
}
+ this.deferredUpdate.cancel();
+ if (this.local) {
+ this.reload();
+ }
+ delete this.applyingState;
},
- getFocusItems: function(){
- return this.items &&
- this.items.filterBy(function(o){
- return o.isFocusable;
- }) ||
- null;
- },
-
- getEnterItem: function(){
- var ci = this.getFocusItems(), length = ci ? ci.getCount() : 0;
-
- if (length === 1) {
- return ci.first().getEnterItem && ci.first().getEnterItem() || ci.first();
- }
- else
- if (length > 1) {
- return ci.first();
+ /**
+ * Saves the state of all active filters
+ * @param {Object} grid
+ * @param {Object} state
+ * @return {Boolean}
+ */
+ saveState : function (grid, state) {
+ var filters = {};
+ this.filters.each(function (filter) {
+ if (filter.active) {
+ filters[filter.dataIndex] = filter.getValue();
}
+ });
+ return (state.filters = filters);
},
- getNextFocus: function(current){
- var items = this.getFocusItems(), next = current, i = items.indexOf(current), length = items.getCount();
-
- if (i === length - 1) {
- next = items.first();
+ /**
+ * @private
+ * Handler called when the grid is rendered
+ */
+ onRender : function () {
+ this.grid.getView().on('refresh', this.onRefresh, this);
+ this.createMenu();
+ },
+
+ /**
+ * @private
+ * Handler called by the grid 'beforedestroy' event
+ */
+ destroy : function () {
+ this.removeAll();
+ this.purgeListeners();
+
+ if(this.filterMenu){
+ Ext.menu.MenuMgr.unregister(this.filterMenu);
+ this.filterMenu.destroy();
+ this.filterMenu = this.menu.menu = null;
}
- else {
- next = items.get(i + 1);
+ },
+
+ /**
+ * Remove all filters, permanently destroying them.
+ */
+ removeAll : function () {
+ if(this.filters){
+ Ext.destroy.apply(Ext, this.filters.items);
+ // remove all items from the collection
+ this.filters.clear();
}
- return next;
},
-
- getPreviousFocus: function(current){
- var items = this.getFocusItems(), prev = current, i = items.indexOf(current), length = items.getCount();
-
- if (i === 0) {
- prev = items.last();
+
+
+ /**
+ * Changes the data store bound to this view and refreshes it.
+ * @param {Store} store The store to bind to this view
+ */
+ bindStore : function(store, initial){
+ if(!initial && this.store){
+ if (this.local) {
+ store.un('load', this.onLoad, this);
+ } else {
+ store.un('beforeload', this.onBeforeLoad, this);
+ }
}
- else {
- prev = items.get(i - 1);
+ if(store){
+ if (this.local) {
+ store.on('load', this.onLoad, this);
+ } else {
+ store.on('beforeload', this.onBeforeLoad, this);
+ }
}
- return prev;
+ this.store = store;
},
-
- getFocusable : function() {
- return this.fi;
- }
-});
-Ext.override(Ext.Panel, {
/**
- * @cfg {Boolean} enableTabbing true to enable tabbing. Default is false.
- */
- getFocusItems: function(){
- // items gets all the items inside the body
- var items = Ext.Panel.superclass.getFocusItems.call(this), bodyFocus = null;
-
- if (!items) {
- items = new Ext.util.MixedCollection();
- this.bodyFocus = this.bodyFocus || new Ext.a11y.FocusItem(this.body, this.enableTabbing);
- items.add('body', this.bodyFocus);
- }
- // but panels can also have tbar, bbar, fbar
- if (this.tbar && this.topToolbar) {
- items.insert(0, this.topToolbar);
+ * @private
+ * Handler called when the grid reconfigure event fires
+ */
+ onReconfigure : function () {
+ this.bindStore(this.grid.getStore());
+ this.store.clearFilter();
+ this.removeAll();
+ this.addFilters(this.grid.getColumnModel());
+ this.updateColumnHeadings();
+ },
+
+ createMenu : function () {
+ var view = this.grid.getView(),
+ hmenu = view.hmenu;
+
+ if (this.showMenu && hmenu) {
+
+ this.sep = hmenu.addSeparator();
+ this.filterMenu = new Ext.menu.Menu({
+ id: this.grid.id + '-filters-menu'
+ });
+ this.menu = hmenu.add({
+ checked: false,
+ itemId: 'filters',
+ text: this.menuFilterText,
+ menu: this.filterMenu
+ });
+
+ this.menu.on({
+ scope: this,
+ checkchange: this.onCheckChange,
+ beforecheckchange: this.onBeforeCheck
+ });
+ hmenu.on('beforeshow', this.onMenu, this);
}
- if (this.bbar && this.bottomToolbar) {
- items.add(this.bottomToolbar);
+ this.updateColumnHeadings();
+ },
+
+ /**
+ * @private
+ * Get the filter menu from the filters MixedCollection based on the clicked header
+ */
+ getMenuFilter : function () {
+ var view = this.grid.getView();
+ if (!view || view.hdCtxIndex === undefined) {
+ return null;
}
- if (this.fbar) {
- items.add(this.fbar);
+ return this.filters.get(
+ view.cm.config[view.hdCtxIndex].dataIndex
+ );
+ },
+
+ /**
+ * @private
+ * Handler called by the grid's hmenu beforeshow event
+ */
+ onMenu : function (filterMenu) {
+ var filter = this.getMenuFilter();
+
+ if (filter) {
+/*
+TODO: lazy rendering
+ if (!filter.menu) {
+ filter.menu = filter.createMenu();
+ }
+*/
+ this.menu.menu = filter.menu;
+ this.menu.setChecked(filter.active, false);
+ // disable the menu if filter.disabled explicitly set to true
+ this.menu.setDisabled(filter.disabled === true);
}
- return items;
- }
-});
-
-Ext.override(Ext.TabPanel, {
- // private
- initFocus: function(){
- Ext.TabPanel.superclass.initFocus.call(this);
- this.mon(this.fi, {
- left: this.onLeft,
- right: this.onRight,
- scope: this
- });
+ this.menu.setVisible(filter !== undefined);
+ this.sep.setVisible(filter !== undefined);
},
- onLeft: function(e){
- if (!this.activeTab) {
- return;
- }
- e.stopEvent();
- var prev = this.items.itemAt(this.items.indexOf(this.activeTab) - 1);
- if (prev) {
- this.setActiveTab(prev);
- }
- return false;
+ /** @private */
+ onCheckChange : function (item, value) {
+ this.getMenuFilter().setActive(value);
},
- onRight: function(e){
- if (!this.activeTab) {
+ /** @private */
+ onBeforeCheck : function (check, value) {
+ return !value || this.getMenuFilter().isActivatable();
+ },
+
+ /**
+ * @private
+ * Handler for all events on filters.
+ * @param {String} event Event name
+ * @param {Object} filter Standard signature of the event before the event is fired
+ */
+ onStateChange : function (event, filter) {
+ if (event === 'serialize') {
return;
}
- e.stopEvent();
- var next = this.items.itemAt(this.items.indexOf(this.activeTab) + 1);
- if (next) {
- this.setActiveTab(next);
- }
- return false;
- }
-});
-
-Ext.override(Ext.tree.TreeNodeUI, {
- // private
- focus: function(){
- this.node.getOwnerTree().bodyFocus.focus();
- }
-});
-
-Ext.override(Ext.tree.TreePanel, {
- // private
- afterRender : function(){
- Ext.tree.TreePanel.superclass.afterRender.call(this);
- this.root.render();
- if(!this.rootVisible){
- this.root.renderChildren();
- }
- this.bodyFocus = new Ext.a11y.FocusItem(this.body.down('.x-tree-root-ct'));
- this.bodyFocus.fi.setFrameEl(this.body);
- }
-});
-Ext.override(Ext.grid.GridPanel, {
- initFocus: function(){
- Ext.grid.GridPanel.superclass.initFocus.call(this);
- this.bodyFocus = new Ext.a11y.FocusItem(this.view.focusEl);
- this.bodyFocus.fi.setFrameEl(this.body);
- }
-});
-
-Ext.override(Ext.Button, {
- isFocusable: true,
- noFocus: false,
-
- initFocus: function(){
- Ext.Button.superclass.initFocus.call(this);
- this.fi = this.fi || new Ext.a11y.Focusable(this.btnEl, null, null, this.el);
- this.fi.setComponent(this);
-
- this.mon(this.fi, {
- focus: this.onFocus,
- blur: this.onBlur,
- scope: this
- });
-
- if (this.menu) {
- this.mon(this.fi, 'down', this.showMenu, this);
- this.on('menuhide', this.focus, this);
+ if (filter == this.getMenuFilter()) {
+ this.menu.setChecked(filter.active, false);
}
-
- if (this.hidden) {
- this.isFocusable = false;
+
+ if ((this.autoReload || this.local) && !this.applyingState) {
+ this.deferredUpdate.delay(this.updateBuffer);
}
-
- this.on('show', function(){
- this.isFocusable = true;
- }, this);
- this.on('hide', function(){
- this.isFocusable = false;
- }, this);
- },
-
- focus: function(){
- this.fi.focus();
+ this.updateColumnHeadings();
+
+ if (!this.applyingState) {
+ this.grid.saveState();
+ }
+ this.grid.fireEvent('filterupdate', this, filter);
},
- blur: function(){
- this.fi.blur();
+ /**
+ * @private
+ * Handler for store's beforeload event when configured for remote filtering
+ * @param {Object} store
+ * @param {Object} options
+ */
+ onBeforeLoad : function (store, options) {
+ options.params = options.params || {};
+ this.cleanParams(options.params);
+ var params = this.buildQuery(this.getFilterData());
+ Ext.apply(options.params, params);
},
- onFocus: function(){
- if (!this.disabled) {
- this.el.addClass("x-btn-focus");
- }
+ /**
+ * @private
+ * Handler for store's load event when configured for local filtering
+ * @param {Object} store
+ * @param {Object} options
+ */
+ onLoad : function (store, options) {
+ store.filterBy(this.getRecordFilter());
},
-
- onBlur: function(){
- this.el.removeClass("x-btn-focus");
- }
-});
-Ext.override(Ext.Toolbar, {
- initFocus: function(){
- Ext.Toolbar.superclass.initFocus.call(this);
- this.mon(this.fi, {
- left: this.onLeft,
- right: this.onRight,
- scope: this
- });
-
- this.on('focus', this.onButtonFocus, this, {
- stopEvent: true
- });
+ /**
+ * @private
+ * Handler called when the grid's view is refreshed
+ */
+ onRefresh : function () {
+ this.updateColumnHeadings();
},
-
- addItem: function(item){
- Ext.Toolbar.superclass.add.apply(this, arguments);
- if (item.rendered && item.fi !== undefined) {
- item.fi.setRelayTo(this.el);
- this.relayEvents(item.fi, ['focus']);
- }
- else {
- item.on('render', function(){
- if (item.fi !== undefined) {
- item.fi.setRelayTo(this.el);
- this.relayEvents(item.fi, ['focus']);
+
+ /**
+ * Update the styles for the header row based on the active filters
+ */
+ updateColumnHeadings : function () {
+ var view = this.grid.getView(),
+ hds, i, len, filter;
+ if (view.mainHd) {
+ hds = view.mainHd.select('td').removeClass(this.filterCls);
+ for (i = 0, len = view.cm.config.length; i < len; i++) {
+ filter = this.getFilter(view.cm.config[i].dataIndex);
+ if (filter && filter.active) {
+ hds.item(i).addClass(this.filterCls);
}
- }, this, {
- single: true
- });
+ }
}
- return item;
},
- onFocus: function(){
- var items = this.getFocusItems();
- if (items && items.getCount() > 0) {
- if (this.lastFocus && items.indexOf(this.lastFocus) !== -1) {
- this.lastFocus.focus();
- }
- else {
- items.first().focus();
+ /** @private */
+ reload : function () {
+ if (this.local) {
+ this.grid.store.clearFilter(true);
+ this.grid.store.filterBy(this.getRecordFilter());
+ } else {
+ var start,
+ store = this.grid.store;
+ this.deferredUpdate.cancel();
+ if (this.toolbar) {
+ start = store.paramNames.start;
+ if (store.lastOptions && store.lastOptions.params && store.lastOptions.params[start]) {
+ store.lastOptions.params[start] = 0;
+ }
}
+ store.reload();
}
},
- onButtonFocus: function(e, t, tf){
- this.lastFocus = tf.component || null;
- },
-
- onLeft: function(e, t, tf){
- e.stopEvent();
- this.getPreviousFocus(tf.component).focus();
+ /**
+ * Method factory that generates a record validator for the filters active at the time
+ * of invokation.
+ * @private
+ */
+ getRecordFilter : function () {
+ var f = [], len, i;
+ this.filters.each(function (filter) {
+ if (filter.active) {
+ f.push(filter);
+ }
+ });
+
+ len = f.length;
+ return function (record) {
+ for (i = 0; i < len; i++) {
+ if (!f[i].validateRecord(record)) {
+ return false;
+ }
+ }
+ return true;
+ };
},
- onRight: function(e, t, tf){
- e.stopEvent();
- this.getNextFocus(tf.component).focus();
+ /**
+ * Adds a filter to the collection and observes it for state change.
+ * @param {Object/Ext.ux.grid.filter.Filter} config A filter configuration or a filter object.
+ * @return {Ext.ux.grid.filter.Filter} The existing or newly created filter object.
+ */
+ addFilter : function (config) {
+ var Cls = this.getFilterClass(config.type),
+ filter = config.menu ? config : (new Cls(config));
+ this.filters.add(filter);
+
+ Ext.util.Observable.capture(filter, this.onStateChange, this);
+ return filter;
},
-
- getEnterItem: Ext.emptyFn,
- onTab: Ext.emptyFn,
- onEsc: Ext.emptyFn
-});
-Ext.override(Ext.menu.BaseItem, {
- initFocus: function(){
- this.fi = new Ext.a11y.Focusable(this, this.parentMenu && this.parentMenu.el || null, true);
- }
-});
+ /**
+ * Adds filters to the collection.
+ * @param {Array/Ext.grid.ColumnModel} filters Either an Array of
+ * filter configuration objects or an Ext.grid.ColumnModel. The columns
+ * of a passed Ext.grid.ColumnModel will be examined for a filter
+ * property and, if present, will be used as the filter configuration object.
+ */
+ addFilters : function (filters) {
+ if (filters) {
+ var i, len, filter, cm = false, dI;
+ if (filters instanceof Ext.grid.ColumnModel) {
+ filters = filters.config;
+ cm = true;
+ }
+ for (i = 0, len = filters.length; i < len; i++) {
+ filter = false;
+ if (cm) {
+ dI = filters[i].dataIndex;
+ filter = filters[i].filter || filters[i].filterable;
+ if (filter){
+ filter = (filter === true) ? {} : filter;
+ Ext.apply(filter, {dataIndex:dI});
+ // filter type is specified in order of preference:
+ // filter type specified in config
+ // type specified in store's field's type config
+ filter.type = filter.type || this.store.fields.get(dI).type;
+ }
+ } else {
+ filter = filters[i];
+ }
+ // if filter config found add filter for the column
+ if (filter) {
+ this.addFilter(filter);
+ }
+ }
+ }
+ },
+
+ /**
+ * Returns a filter for the given dataIndex, if one exists.
+ * @param {String} dataIndex The dataIndex of the desired filter object.
+ * @return {Ext.ux.grid.filter.Filter}
+ */
+ getFilter : function (dataIndex) {
+ return this.filters.get(dataIndex);
+ },
-Ext.override(Ext.menu.Menu, {
- initFocus: function(){
- this.fi = new Ext.a11y.Focusable(this);
- this.focusEl = this.fi;
+ /**
+ * Turns all filters off. This does not clear the configuration information
+ * (see {@link #removeAll}).
+ */
+ clearFilters : function () {
+ this.filters.each(function (filter) {
+ filter.setActive(false);
+ });
+ },
+
+ /**
+ * Returns an Array of the currently active filters.
+ * @return {Array} filters Array of the currently active filters.
+ */
+ getFilterData : function () {
+ var filters = [], i, len;
+
+ this.filters.each(function (f) {
+ if (f.active) {
+ var d = [].concat(f.serialize());
+ for (i = 0, len = d.length; i < len; i++) {
+ filters.push({
+ field: f.dataIndex,
+ data: d[i]
+ });
+ }
+ }
+ });
+ return filters;
+ },
+
+ /**
+ * Function to take the active filters data and build it into a query.
+ * The format of the query depends on the {@link #encode}
+ * configuration:
+ *
+ *
+ *
{@link #paramPrefix}='filters'
:
+ *
+ *
+filters[0][field]="someDataIndex"&
+filters[0][data][comparison]="someValue1"&
+filters[0][data][type]="someValue2"&
+filters[0][data][value]="someValue3"&
+ *
+ *
+filters[0][field]="someDataIndex"&
+filters[0][data][comparison]="someValue1"&
+filters[0][data][type]="someValue2"&
+filters[0][data][value]="someValue3"&
+ *
+ */
+Ext.ux.grid.filter.BooleanFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
+ /**
+ * @cfg {Boolean} defaultValue
+ * Set this to null if you do not want either option to be checked by default. Defaults to false.
+ */
+ defaultValue : false,
+ /**
+ * @cfg {String} yesText
+ * Defaults to 'Yes'.
+ */
+ yesText : 'Yes',
+ /**
+ * @cfg {String} noText
+ * Defaults to 'No'.
+ */
+ noText : 'No',
-Ext.override(Ext.FormPanel, {
- initFocus: function(){
- Ext.FormPanel.superclass.initFocus.call(this);
- this.on('focus', this.onFieldFocus, this, {
- stopEvent: true
- });
+ /**
+ * @private
+ * Template method that is to initialize the filter and install required menu items.
+ */
+ init : function (config) {
+ var gId = Ext.id();
+ this.options = [
+ new Ext.menu.CheckItem({text: this.yesText, group: gId, checked: this.defaultValue === true}),
+ new Ext.menu.CheckItem({text: this.noText, group: gId, checked: this.defaultValue === false})];
+
+ this.menu.add(this.options[0], this.options[1]);
+
+ for(var i=0; i
+var filters = new Ext.ux.grid.GridFilters({
+ ...
+ filters: [{
+ // required configs
+ type: 'boolean',
+ dataIndex: 'visible'
+
+ // optional configs
+ defaultValue: null, // leave unselected (false selected by default)
+ yesText: 'Yes', // default
+ noText: 'No' // default
+ }]
});
+ *
+var filters = new Ext.ux.grid.GridFilters({
+ ...
+ filters: [{
+ // required configs
+ type: 'date',
+ dataIndex: 'dateAdded',
+
+ // optional configs
+ dateFormat: 'm/d/Y', // default
+ beforeText: 'Before', // default
+ afterText: 'After', // default
+ onText: 'On', // default
+ pickerOpts: {
+ // any DateMenu configs
+ },
+
+ active: true // default is false
+ }]
+});
+ *
+ */
+Ext.ux.grid.filter.DateFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
+ /**
+ * @cfg {String} afterText
+ * Defaults to 'After'.
+ */
+ afterText : 'After',
+ /**
+ * @cfg {String} beforeText
+ * Defaults to 'Before'.
+ */
+ beforeText : 'Before',
+ /**
+ * @cfg {Object} compareMap
+ * Map for assigning the comparison values used in serialization.
+ */
+ compareMap : {
+ before: 'lt',
+ after: 'gt',
+ on: 'eq'
},
-
- // private
- createForm: function(){
- delete this.initialConfig.listeners;
- var form = new Ext.form.BasicForm(null, this.initialConfig);
- form.afterMethod('add', this.formItemAdd, this);
- return form;
+ /**
+ * @cfg {String} dateFormat
+ * The date format to return when using getValue.
+ * Defaults to 'm/d/Y'.
+ */
+ dateFormat : 'm/d/Y',
+
+ /**
+ * @cfg {Date} maxDate
+ * Allowable date as passed to the Ext.DatePicker
+ * Defaults to undefined.
+ */
+ /**
+ * @cfg {Date} minDate
+ * Allowable date as passed to the Ext.DatePicker
+ * Defaults to undefined.
+ */
+ /**
+ * @cfg {Array} menuItems
+ * The items to be shown in this menu
+ * Defaults to:+ * menuItems : ['before', 'after', '-', 'on'], + *+ */ + menuItems : ['before', 'after', '-', 'on'], + + /** + * @cfg {Object} menuItemCfgs + * Default configuration options for each menu item + */ + menuItemCfgs : { + selectOnFocus: true, + width: 125 }, + + /** + * @cfg {String} onText + * Defaults to 'On'. + */ + onText : 'On', - formItemAdd: function(item){ - item.on('render', function(field){ - field.fi.setRelayTo(this.el); - this.relayEvents(field.fi, ['focus']); - }, this, { - single: true + /** + * @cfg {Object} pickerOpts + * Configuration options for the date picker associated with each field. + */ + pickerOpts : {}, + + /** + * @private + * Template method that is to initialize the filter and install required menu items. + */ + init : function (config) { + var menuCfg, i, len, item, cfg, Cls; + + menuCfg = Ext.apply(this.pickerOpts, { + minDate: this.minDate, + maxDate: this.maxDate, + format: this.dateFormat, + listeners: { + scope: this, + select: this.onMenuSelect + } }); + + this.fields = {}; + for (i = 0, len = this.menuItems.length; i < len; i++) { + item = this.menuItems[i]; + if (item !== '-') { + cfg = { + itemId: 'range-' + item, + text: this[item + 'Text'], + menu: new Ext.menu.DateMenu( + Ext.apply(menuCfg, { + itemId: item + }) + ), + listeners: { + scope: this, + checkchange: this.onCheckChange + } + }; + Cls = Ext.menu.CheckItem; + item = this.fields[item] = new Cls(cfg); + } + //this.add(item); + this.menu.add(item); + } }, - - onFocus: function(){ - var items = this.getFocusItems(); - if (items && items.getCount() > 0) { - if (this.lastFocus && items.indexOf(this.lastFocus) !== -1) { - this.lastFocus.focus(); + + onCheckChange : function () { + this.setActive(this.isActivatable()); + this.fireEvent('update', this); + }, + + /** + * @private + * Handler method called when there is a keyup event on an input + * item of this menu. + */ + onInputKeyUp : function (field, e) { + var k = e.getKey(); + if (k == e.RETURN && field.isValid()) { + e.stopEvent(); + this.menu.hide(true); + return; + } + }, + + /** + * Handler for when the menu for a field fires the 'select' event + * @param {Object} date + * @param {Object} menuItem + * @param {Object} value + * @param {Object} picker + */ + onMenuSelect : function (menuItem, value, picker) { + var fields = this.fields, + field = this.fields[menuItem.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 && fields.before.menu.picker.value < value) { + fields.before.setChecked(false, true); + } else if (field == fields.before && fields.after.menu.picker.value > value) { + fields.after.setChecked(false, true); } - else { - items.first().focus(); + } + this.fireEvent('update', this); + }, + + /** + * @private + * Template method that is to get and return the value of the filter. + * @return {String} The value of this filter + */ + getValue : function () { + var key, result = {}; + for (key in this.fields) { + if (this.fields[key].checked) { + result[key] = this.fields[key].menu.picker.getValue(); } } + return result; }, - - onFieldFocus: function(e, t, tf){ - this.lastFocus = tf.component || null; + + /** + * @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 key; + for (key in this.fields) { + if(value[key]){ + this.fields[key].menu.picker.setValue(value[key]); + this.fields[key].setChecked(true); + } else if (!preserve) { + this.fields[key].setChecked(false); + } + } + this.fireEvent('update', this); + }, + + /** + * @private + * Template method that is to return true if the filter + * has enough configuration information to be activated. + * @return {Boolean} + */ + isActivatable : function () { + var key; + for (key in this.fields) { + if (this.fields[key].checked) { + return true; + } + } + return false; + }, + + /** + * @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 args = []; + for (var key in this.fields) { + if(this.fields[key].checked){ + args.push({ + type: 'date', + comparison: this.compareMap[key], + value: this.getFieldValue(key).format(this.dateFormat) + }); + } + } + return args; + }, + + /** + * Get and return the date menu picker value + * @param {String} item The field identifier ('before', 'after', 'on') + * @return {Date} Gets the current selected value of the date field + */ + getFieldValue : function(item){ + return this.fields[item].menu.picker.getValue(); }, - onTab: function(e, t, tf){ - if (tf.relayTo.component === this) { - var item = e.shiftKey ? this.getPreviousFocus(tf.component) : this.getNextFocus(tf.component); + /** + * Gets the menu picker associated with the passed field + * @param {String} item The field identifier ('before', 'after', 'on') + * @return {Object} The menu picker + */ + getPicker : function(item){ + return this.fields[item].menu.picker; + }, + + /** + * 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) { + var key, + pickerValue, + val = record.get(this.dataIndex); - if (item) { - ev.stopEvent(); - item.focus(); - return; + if(!Ext.isDate(val)){ + return false; + } + val = val.clearTime(true).getTime(); + + for (key in this.fields) { + if (this.fields[key].checked) { + pickerValue = this.getFieldValue(key).clearTime(true).getTime(); + if (key == 'before' && pickerValue <= val) { + return false; + } + if (key == 'after' && pickerValue >= val) { + return false; + } + if (key == 'on' && pickerValue != val) { + return false; + } } } - Ext.FormPanel.superclass.onTab.apply(this, arguments); + return true; + } +});/** + * @class Ext.ux.grid.filter.ListFilter + * @extends Ext.ux.grid.filter.Filter + *
List filters are able to be preloaded/backed by an Ext.data.Store to load + * their options the first time they are shown. ListFilter utilizes the + * {@link Ext.ux.menu.ListMenu} component.
+ *Although not shown here, this class accepts all configuration options + * for {@link Ext.ux.menu.ListMenu}.
+ * + *Example Usage:
+ *
+var filters = new Ext.ux.grid.GridFilters({
+ ...
+ filters: [{
+ type: 'list',
+ dataIndex: 'size',
+ phpMode: true,
+ // options will be used as data to implicitly creates an ArrayStore
+ options: ['extra small', 'small', 'medium', 'large', 'extra large']
+ }]
+});
+ *
+ *
+ */
+Ext.ux.grid.filter.ListFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
+
+ /**
+ * @cfg {Array} options
+ * data
to be used to implicitly create a data store
+ * to back this list when the data source is local. If the
+ * data for the list is remote, use the {@link #store}
+ * config instead.
Each item within the provided array may be in one of the + * following formats:
+ *
+options: [
+ [11, 'extra small'],
+ [18, 'small'],
+ [22, 'medium'],
+ [35, 'large'],
+ [44, 'extra large']
+]
+ *
+ *
+labelField: 'name', // override default of 'text'
+options: [
+ {id: 11, name:'extra small'},
+ {id: 18, name:'small'},
+ {id: 22, name:'medium'},
+ {id: 35, name:'large'},
+ {id: 44, name:'extra large'}
+]
+ *
+ *
+ * options: ['extra small', 'small', 'medium', 'large', 'extra large']
+ *
+ * Adjust the format of this filter. Defaults to false.
+ *When GridFilters @cfg encode = false
(default):
+// phpMode == false (default):
+filter[0][data][type] list
+filter[0][data][value] value1
+filter[0][data][value] value2
+filter[0][field] prod
+
+// phpMode == true:
+filter[0][data][type] list
+filter[0][data][value] value1, value2
+filter[0][field] prod
+ *
+ * When GridFilters @cfg encode = true
:
+ *
+// phpMode == false (default):
+filter : [{"type":"list","value":["small","medium"],"field":"size"}]
+
+// phpMode == true:
+filter : [{"type":"list","value":"small,medium","field":"size"}]
+ *
+ */
+ phpMode : false,
+ /**
+ * @cfg {Ext.data.Store} store
+ * The {@link Ext.data.Store} this list should use as its data source
+ * when the data source is remote. If the data for the list
+ * is local, use the {@link #options}
config instead.
+ */
+
+ /**
+ * @private
+ * Template method that is to initialize the filter and install required menu items.
+ * @param {Object} config
+ */
+ init : function (config) {
+ this.dt = new Ext.util.DelayedTask(this.fireUpdate, this);
+
+ // if a menu already existed, do clean up first
+ if (this.menu){
+ this.menu.destroy();
+ }
+ this.menu = new Ext.ux.menu.ListMenu(config);
+ this.menu.on('checkchange', this.onCheckChange, this);
},
- getNextFocus: function(current){
- var items = this.getFocusItems(), i = items.indexOf(current), length = items.getCount();
-
- return (i < length - 1) ? items.get(i + 1) : false;
+ /**
+ * @private
+ * Template method that is to get and return the value of the filter.
+ * @return {String} The value of this filter
+ */
+ getValue : function () {
+ return this.menu.getSelected();
+ },
+ /**
+ * @private
+ * Template method that is to set the value of the filter.
+ * @param {Object} value The value to set the filter
+ */
+ setValue : function (value) {
+ this.menu.setSelected(value);
+ this.fireEvent('update', this);
+ },
+
+ /**
+ * @private
+ * Template method that is to return true if the filter
+ * has enough configuration information to be activated.
+ * @return {Boolean}
+ */
+ isActivatable : function () {
+ return this.getValue().length > 0;
},
- getPreviousFocus: function(current){
- var items = this.getFocusItems(), i = items.indexOf(current), length = items.getCount();
-
- return (i > 0) ? items.get(i - 1) : false;
+ /**
+ * @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 args = {type: 'list', value: this.phpMode ? this.getValue().join(',') : this.getValue()};
+ return args;
+ },
+
+ /** @private */
+ onCheckChange : function(){
+ this.dt.delay(this.updateBuffer);
+ },
+
+
+ /**
+ * 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) {
+ return this.getValue().indexOf(record.get(this.dataIndex)) > -1;
}
+});/**
+ * @class Ext.ux.grid.filter.NumericFilter
+ * @extends Ext.ux.grid.filter.Filter
+ * Filters using an Ext.ux.menu.RangeMenu.
+ * Example Usage:
+ *
+var filters = new Ext.ux.grid.GridFilters({
+ ...
+ filters: [{
+ type: 'numeric',
+ dataIndex: 'price'
+ }]
});
+ *
+ */
+Ext.ux.grid.filter.NumericFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
-Ext.override(Ext.Viewport, {
- initFocus: function(){
- Ext.Viewport.superclass.initFocus.apply(this);
- this.mon(Ext.get(document), 'focus', this.focus, this);
- this.mon(Ext.get(document), 'blur', this.blur, this);
- this.fi.setNoFrame(true);
+ /**
+ * @cfg {Object} fieldCls
+ * The Class to use to construct each field item within this menu
+ * Defaults to:+ * fieldCls : Ext.form.NumberField + *+ */ + fieldCls : Ext.form.NumberField, + /** + * @cfg {Object} fieldCfg + * The default configuration options for any field item unless superseded + * by the
{@link #fields}
configuration.
+ * Defaults to:+ * fieldCfg : {} + *+ * Example usage: + *
+fieldCfg : {
+ width: 150,
+},
+ *
+ */
+ /**
+ * @cfg {Object} fields
+ * The field items may be configured individually
+ * Defaults to undefined.
+ * Example usage:
+ *
+fields : {
+ gt: { // override fieldCfg options
+ width: 200,
+ fieldCls: Ext.ux.form.CustomNumberField // to override default {@link #fieldCls}
+ }
+},
+ *
+ */
+ /**
+ * @cfg {Object} iconCls
+ * The iconCls to be applied to each comparator field item.
+ * Defaults to:+iconCls : { + gt : 'ux-rangemenu-gt', + lt : 'ux-rangemenu-lt', + eq : 'ux-rangemenu-eq' +} + *+ */ + iconCls : { + gt : 'ux-rangemenu-gt', + lt : 'ux-rangemenu-lt', + eq : 'ux-rangemenu-eq' + }, + + /** + * @cfg {Object} menuItemCfgs + * Default configuration options for each menu item + * Defaults to:
+menuItemCfgs : { + emptyText: 'Enter Filter Text...', + selectOnFocus: true, + width: 125 +} + *+ */ + menuItemCfgs : { + emptyText: 'Enter Filter Text...', + selectOnFocus: true, + width: 125 + }, + + /** + * @cfg {Array} menuItems + * The items to be shown in this menu. Items are added to the menu + * according to their position within this array. Defaults to:
+ * menuItems : ['lt','gt','-','eq'] + *+ */ + menuItems : ['lt', 'gt', '-', 'eq'], + + /** + * @private + * Template method that is to initialize the filter and install required menu items. + */ + init : function (config) { + // if a menu already existed, do clean up first + if (this.menu){ + this.menu.destroy(); + } + this.menu = new Ext.ux.menu.RangeMenu(Ext.apply(config, { + // pass along filter configs to the menu + fieldCfg : this.fieldCfg || {}, + fieldCls : this.fieldCls, + fields : this.fields || {}, + iconCls: this.iconCls, + menuItemCfgs: this.menuItemCfgs, + menuItems: this.menuItems, + updateBuffer: this.updateBuffer + })); + // relay the event fired by the menu + this.menu.on('update', this.fireUpdate, this); }, - onTab: function(e, t, tf, f){ - e.stopEvent(); - - if (tf === f) { - items = this.getFocusItems(); - if (items && items.getCount() > 0) { - items.first().focus(); + /** + * @private + * Template method that is to get and return the value of the filter. + * @return {String} The value of this filter + */ + getValue : function () { + return this.menu.getValue(); + }, + + /** + * @private + * Template method that is to set the value of the filter. + * @param {Object} value The value to set the filter + */ + setValue : function (value) { + this.menu.setValue(value); + }, + + /** + * @private + * Template method that is to return true if the filter + * has enough configuration information to be activated. + * @return {Boolean} + */ + isActivatable : function () { + var values = this.getValue(); + for (key in values) { + if (values[key] !== undefined) { + return true; } } - else { - var rf = tf.relayTo || tf; - var item = e.shiftKey ? this.getPreviousFocus(rf.component) : this.getNextFocus(rf.component); - item.focus(); - } - } -}); + return false; + }, -})();/** - * @class Ext.ux.GMapPanel - * @extends Ext.Panel - * @author Shea Frederick - */ -Ext.ux.GMapPanel = Ext.extend(Ext.Panel, { - initComponent : function(){ - - var defConfig = { - plain: true, - zoomLevel: 3, - yaw: 180, - pitch: 0, - zoom: 0, - gmapType: 'map', - border: false - }; - - Ext.applyIf(this,defConfig); - - Ext.ux.GMapPanel.superclass.initComponent.call(this); - + /** + * @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 key, + args = [], + values = this.menu.getValue(); + for (key in values) { + args.push({ + type: 'numeric', + comparison: key, + value: values[key] + }); + } + return args; }, - afterRender : function(){ - - var wh = this.ownerCt.getSize(); - Ext.applyIf(this, wh); - - Ext.ux.GMapPanel.superclass.afterRender.call(this); - - if (this.gmapType === 'map'){ - this.gmap = new GMap2(this.body.dom); + + /** + * 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) { + var val = record.get(this.dataIndex), + values = this.getValue(); + if (values.eq !== undefined && val != values.eq) { + return false; } - - if (this.gmapType === 'panorama'){ - this.gmap = new GStreetviewPanorama(this.body.dom); + if (values.lt !== undefined && val >= values.lt) { + return false; } - - if (typeof this.addControl == 'object' && this.gmapType === 'map') { - this.gmap.addControl(this.addControl); + if (values.gt !== undefined && val <= values.gt) { + return false; } + return true; + } +});/** + * @class Ext.ux.grid.filter.StringFilter + * @extends Ext.ux.grid.filter.Filter + * Filter by a configurable Ext.form.TextField + *
Example Usage:
+ *
+var filters = new Ext.ux.grid.GridFilters({
+ ...
+ filters: [{
+ // required configs
+ type: 'string',
+ dataIndex: 'name',
- if (typeof this.setCenter === 'object') {
- if (typeof this.setCenter.geoCodeAddr === 'string'){
- this.geoCodeLookup(this.setCenter.geoCodeAddr);
- }else{
- if (this.gmapType === 'map'){
- var point = new GLatLng(this.setCenter.lat,this.setCenter.lng);
- this.gmap.setCenter(point, this.zoomLevel);
- }
- if (typeof this.setCenter.marker === 'object' && typeof point === 'object'){
- this.addMarker(point,this.setCenter.marker,this.setCenter.marker.clear);
- }
- }
- if (this.gmapType === 'panorama'){
- this.gmap.setLocationAndPOV(new GLatLng(this.setCenter.lat,this.setCenter.lng), {yaw: this.yaw, pitch: this.pitch, zoom: this.zoom});
- }
- }
+ // optional configs
+ value: 'foo',
+ active: true, // default is false
+ iconCls: 'ux-gridfilter-text-icon' // default
+ // any Ext.form.TextField configs accepted
+ }]
+});
+ *
+ */
+Ext.ux.grid.filter.StringFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
- GEvent.bind(this.gmap, 'load', this, function(){
- this.onMapReady();
+ /**
+ * @cfg {String} iconCls
+ * The iconCls to be applied to the menu item.
+ * Defaults to 'ux-gridfilter-text-icon'.
+ */
+ iconCls : 'ux-gridfilter-text-icon',
+
+ emptyText: 'Enter Filter Text...',
+ selectOnFocus: true,
+ width: 125,
+
+ /**
+ * @private
+ * Template method that is to initialize the filter and install required menu items.
+ */
+ init : function (config) {
+ Ext.applyIf(config, {
+ enableKeyEvents: true,
+ iconCls: this.iconCls,
+ listeners: {
+ scope: this,
+ keyup: this.onInputKeyUp
+ }
});
+ this.inputItem = new Ext.form.TextField(config);
+ this.menu.add(this.inputItem);
+ this.updateTask = new Ext.util.DelayedTask(this.fireUpdate, this);
+ },
+
+ /**
+ * @private
+ * Template method that is to get and return the value of the filter.
+ * @return {String} The value of this filter
+ */
+ getValue : function () {
+ return this.inputItem.getValue();
+ },
+
+ /**
+ * @private
+ * Template method that is to set the value of the filter.
+ * @param {Object} value The value to set the filter
+ */
+ setValue : function (value) {
+ this.inputItem.setValue(value);
+ this.fireEvent('update', this);
+ },
+
+ /**
+ * @private
+ * Template method that is to return true if the filter
+ * has enough configuration information to be activated.
+ * @return {Boolean}
+ */
+ isActivatable : function () {
+ return this.inputItem.getValue().length > 0;
},
- onMapReady : function(){
- this.addMarkers(this.markers);
- this.addMapControls();
- this.addOptions();
+
+ /**
+ * @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 () {
+ return {type: 'string', value: this.getValue()};
},
- onResize : function(w, h){
- if (typeof this.getMap() == 'object') {
- this.gmap.checkResize();
+ /**
+ * 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) {
+ var val = record.get(this.dataIndex);
+
+ if(typeof val != 'string') {
+ return (this.getValue().length === 0);
}
-
- Ext.ux.GMapPanel.superclass.onResize.call(this, w, h);
+ return val.toLowerCase().indexOf(this.getValue().toLowerCase()) > -1;
},
- setSize : function(width, height, animate){
-
- if (typeof this.getMap() == 'object') {
- this.gmap.checkResize();
+
+ /**
+ * @private
+ * Handler method called when there is a keyup event on this.inputItem
+ */
+ onInputKeyUp : function (field, e) {
+ var k = e.getKey();
+ if (k == e.RETURN && field.isValid()) {
+ e.stopEvent();
+ this.menu.hide(true);
+ return;
+ }
+ // restart the timer
+ this.updateTask.delay(this.updateBuffer);
+ }
+});
+Ext.namespace('Ext.ux.menu');
+
+/**
+ * @class Ext.ux.menu.ListMenu
+ * @extends Ext.menu.Menu
+ * This is a supporting class for {@link Ext.ux.grid.filter.ListFilter}.
+ * Although not listed as configuration options for this class, this class
+ * also accepts all configuration options from {@link Ext.ux.grid.filter.ListFilter}.
+ */
+Ext.ux.menu.ListMenu = Ext.extend(Ext.menu.Menu, {
+ /**
+ * @cfg {String} labelField
+ * Defaults to 'text'.
+ */
+ labelField : 'text',
+ /**
+ * @cfg {String} paramPrefix
+ * Defaults to 'Loading...'.
+ */
+ loadingText : 'Loading...',
+ /**
+ * @cfg {Boolean} loadOnShow
+ * Defaults to true.
+ */
+ loadOnShow : true,
+ /**
+ * @cfg {Boolean} single
+ * Specify true to group all items in this list into a single-select
+ * radio button group. Defaults to false.
+ */
+ single : false,
+
+ constructor : function (cfg) {
+ this.selected = [];
+ this.addEvents(
+ /**
+ * @event checkchange
+ * Fires when there is a change in checked items from this list
+ * @param {Object} item Ext.menu.CheckItem
+ * @param {Object} checked The checked value that was set
+ */
+ 'checkchange'
+ );
+
+ Ext.ux.menu.ListMenu.superclass.constructor.call(this, cfg = cfg || {});
+
+ if(!cfg.store && cfg.options){
+ var options = [];
+ for(var i=0, len=cfg.options.length; iExample Usage:
+ *
+
+ *
+ */
+Ext.ux.menu.RangeMenu = Ext.extend(Ext.menu.Menu, {
- if (clear === true){
- this.getMap().clearOverlays();
- }
- if (center === true) {
- this.getMap().setCenter(point, this.zoomLevel);
- }
+ constructor : function (config) {
- var mark = new GMarker(point,marker);
- if (typeof listeners === 'object'){
- for (evt in listeners) {
- GEvent.bind(mark, evt, this, listeners[evt]);
+ Ext.ux.menu.RangeMenu.superclass.constructor.call(this, config);
+
+ this.addEvents(
+ /**
+ * @event update
+ * Fires when a filter configuration has changed
+ * @param {Ext.ux.grid.filter.Filter} this The filter object.
+ */
+ 'update'
+ );
+
+ this.updateTask = new Ext.util.DelayedTask(this.fireUpdate, this);
+
+ var i, len, item, cfg, Cls;
+
+ for (i = 0, len = this.menuItems.length; i < len; i++) {
+ item = this.menuItems[i];
+ if (item !== '-') {
+ // defaults
+ cfg = {
+ itemId: 'range-' + item,
+ enableKeyEvents: true,
+ iconCls: this.iconCls[item] || 'no-icon',
+ listeners: {
+ scope: this,
+ keyup: this.onInputKeyUp
+ }
+ };
+ Ext.apply(
+ cfg,
+ // custom configs
+ Ext.applyIf(this.fields[item] || {}, this.fieldCfg[item]),
+ // configurable defaults
+ this.menuItemCfgs
+ );
+ Cls = cfg.fieldCls || this.fieldCls;
+ item = this.fields[item] = new Cls(cfg);
}
+ this.add(item);
}
- this.getMap().addOverlay(mark);
+ },
+ /**
+ * @private
+ * called by this.updateTask
+ */
+ fireUpdate : function () {
+ this.fireEvent('update', this);
},
- addMapControls : function(){
-
- if (this.gmapType === 'map') {
- if (Ext.isArray(this.mapControls)) {
- for(i=0;iBasic status bar component that can be used as the bottom toolbar of any {@link Ext.Panel}. In addition to + * supporting the standard {@link Ext.Toolbar} interface for adding buttons, menus and other items, the StatusBar + * provides a greedy status element that can be aligned to either side and has convenient methods for setting the + * status text and icon. You can also indicate that something is processing using the {@link #showBusy} method.
+ *
+new Ext.Panel({
+ title: 'StatusBar',
+ // etc.
+ bbar: new Ext.ux.StatusBar({
+ id: 'my-status',
+
+ // defaults to use when the status is cleared:
+ defaultText: 'Default status text',
+ defaultIconCls: 'default-icon',
+
+ // values to set initially:
+ text: 'Ready',
+ iconCls: 'ready-icon',
+
+ // any standard Toolbar items:
+ items: [{
+ text: 'A Button'
+ }, '-', 'Plain Text']
+ })
+});
+
+// Update the status bar later in code:
+var sb = Ext.getCmp('my-status');
+sb.setStatus({
+ text: 'OK',
+ iconCls: 'ok-icon',
+ clear: true // auto-clear after a set interval
+});
+
+// Set the status bar to show that something is processing:
+sb.showBusy();
+
+// processing....
+
+sb.clearStatus(); // once completeed
+
+ * @extends Ext.Toolbar
+ * @constructor
+ * Creates a new StatusBar
+ * @param {Object/Array} config A config object
+ */
+Ext.ux.StatusBar = Ext.extend(Ext.Toolbar, {
+ /**
+ * @cfg {String} statusAlign
+ * The alignment of the status element within the overall StatusBar layout. When the StatusBar is rendered,
+ * it creates an internal div containing the status text and icon. Any additional Toolbar items added in the
+ * StatusBar's {@link #items} config, or added via {@link #add} or any of the supported add* methods, will be
+ * rendered, in added order, to the opposite side. The status element is greedy, so it will automatically
+ * expand to take up all sapce left over by any other items. Example usage:
+ *
+// Create a left-aligned status bar containing a button,
+// separator and text item that will be right-aligned (default):
+new Ext.Panel({
+ title: 'StatusBar',
+ // etc.
+ bbar: new Ext.ux.StatusBar({
+ defaultText: 'Default status text',
+ id: 'status-id',
+ items: [{
+ text: 'A Button'
+ }, '-', 'Plain Text']
+ })
+});
+
+// By adding the statusAlign config, this will create the
+// exact same toolbar, except the status and toolbar item
+// layout will be reversed from the previous example:
+new Ext.Panel({
+ title: 'StatusBar',
+ // etc.
+ bbar: new Ext.ux.StatusBar({
+ defaultText: 'Default status text',
+ id: 'status-id',
+ statusAlign: 'right',
+ items: [{
+ text: 'A Button'
+ }, '-', 'Plain Text']
+ })
+});
+
+ */
+ /**
+ * @cfg {String} defaultText
+ * The default {@link #text} value. This will be used anytime the status bar is cleared with the
+ * useDefaults:true option (defaults to '').
+ */
+ /**
+ * @cfg {String} defaultIconCls
+ * The default {@link #iconCls} value (see the iconCls docs for additional details about customizing the icon).
+ * This will be used anytime the status bar is cleared with the useDefaults:true option (defaults to '').
+ */
+ /**
+ * @cfg {String} text
+ * A string that will be initially set as the status message. This string
+ * will be set as innerHTML (html tags are accepted) for the toolbar item.
+ * If not specified, the value set for {@link #defaultText}
+ * will be used.
+ */
+ /**
+ * @cfg {String} iconCls
+ * A CSS class that will be initially set as the status bar icon and is
+ * expected to provide a background image (defaults to '').
+ * Example usage:
+// Example CSS rule:
+.x-statusbar .x-status-custom {
+ padding-left: 25px;
+ background: transparent url(images/custom-icon.gif) no-repeat 3px 2px;
+}
+
+// Setting a default icon:
+var sb = new Ext.ux.StatusBar({
+ defaultIconCls: 'x-status-custom'
+});
+
+// Changing the icon:
+sb.setStatus({
+ text: 'New status',
+ iconCls: 'x-status-custom'
+});
+
+ */
+
+ /**
+ * @cfg {String} cls
+ * The base class applied to the containing element for this component on render (defaults to 'x-statusbar')
+ */
+ cls : 'x-statusbar',
+ /**
+ * @cfg {String} busyIconCls
+ * The default {@link #iconCls}
applied when calling
+ * {@link #showBusy}
(defaults to 'x-status-busy').
+ * It can be overridden at any time by passing the iconCls
+ * argument into {@link #showBusy}
.
+ */
+ busyIconCls : 'x-status-busy',
+ /**
+ * @cfg {String} busyText
+ * The default {@link #text}
applied when calling
+ * {@link #showBusy}
(defaults to 'Loading...').
+ * It can be overridden at any time by passing the text
+ * argument into {@link #showBusy}
.
+ */
+ busyText : 'Loading...',
+ /**
+ * @cfg {Number} autoClear
+ * The number of milliseconds to wait after setting the status via
+ * {@link #setStatus}
before automatically clearing the status
+ * text and icon (defaults to 5000). Note that this only applies
+ * when passing the clear argument to {@link #setStatus}
+ * since that is the only way to defer clearing the status. This can
+ * be overridden by specifying a different wait value in
+ * {@link #setStatus}
. Calls to {@link #clearStatus}
+ * always clear the status bar immediately and ignore this value.
+ */
+ autoClear : 5000,
+
+ /**
+ * @cfg {String} emptyText
+ * The text string to use if no text has been set. Defaults to
+ * ' '). If there are no other items in the toolbar using
+ * an empty string ('') for this value would end up in the toolbar
+ * height collapsing since the empty string will not maintain the toolbar
+ * height. Use '' if the toolbar should collapse in height
+ * vertically when no text is specified and there are no other items in
+ * the toolbar.
+ */
+ emptyText : ' ',
+
+ // private
+ activeThreadId : 0,
+
+ // private
+ initComponent : function(){
+ if(this.statusAlign=='right'){
+ this.cls += ' x-status-right';
+ }
+ Ext.ux.StatusBar.superclass.initComponent.call(this);
+ },
+
+ // private
+ afterRender : function(){
+ Ext.ux.StatusBar.superclass.afterRender.call(this);
+
+ var right = this.statusAlign == 'right';
+ this.currIconCls = this.iconCls || this.defaultIconCls;
+ this.statusEl = new Ext.Toolbar.TextItem({
+ cls: 'x-status-text ' + (this.currIconCls || ''),
+ text: this.text || this.defaultText || ''
+ });
+
+ if(right){
+ this.add('->');
+ this.add(this.statusEl);
+ }else{
+ this.insert(0, this.statusEl);
+ this.insert(1, '->');
+ }
+
+// this.statusEl = td.createChild({
+// cls: 'x-status-text ' + (this.iconCls || this.defaultIconCls || ''),
+// html: this.text || this.defaultText || ''
+// });
+// this.statusEl.unselectable();
+
+// this.spacerEl = td.insertSibling({
+// tag: 'td',
+// style: 'width:100%',
+// cn: [{cls:'ytb-spacer'}]
+// }, right ? 'before' : 'after');
+ },
+
+ /**
+ * Sets the status {@link #text} and/or {@link #iconCls}. Also supports automatically clearing the
+ * status that was set after a specified interval.
+ * @param {Object/String} config A config object specifying what status to set, or a string assumed
+ * to be the status text (and all other options are defaulted as explained below). A config
+ * object containing any or all of the following properties can be passed:
+// Simple call to update the text
+statusBar.setStatus('New status');
+
+// Set the status and icon, auto-clearing with default options:
+statusBar.setStatus({
+ text: 'New status',
+ iconCls: 'x-status-custom',
+ clear: true
+});
+
+// Auto-clear with custom options:
+statusBar.setStatus({
+ text: 'New status',
+ iconCls: 'x-status-custom',
+ clear: {
+ wait: 8000,
+ anim: false,
+ useDefaults: false
+ }
+});
+
+ * @return {Ext.ux.StatusBar} this
+ */
+ setStatus : function(o){
+ o = o || {};
+
+ if(typeof o == 'string'){
+ o = {text:o};
+ }
+ if(o.text !== undefined){
+ this.setText(o.text);
+ }
+ if(o.iconCls !== undefined){
+ this.setIcon(o.iconCls);
+ }
+
+ if(o.clear){
+ var c = o.clear,
+ wait = this.autoClear,
+ defaults = {useDefaults: true, anim: true};
+
+ if(typeof c == 'object'){
+ c = Ext.applyIf(c, defaults);
+ if(c.wait){
+ wait = c.wait;
+ }
+ }else if(typeof c == 'number'){
+ wait = c;
+ c = defaults;
+ }else if(typeof c == 'boolean'){
+ c = defaults;
+ }
+
+ c.threadId = this.activeThreadId;
+ this.clearStatus.defer(wait, this, [c]);
+ }
+ return this;
+ },
+
+ /**
+ * Clears the status {@link #text} and {@link #iconCls}. Also supports clearing via an optional fade out animation.
+ * @param {Object} config (optional) A config object containing any or all of the following properties. If this
+ * object is not specified the status will be cleared using the defaults below: