UNPKG

shubhadownloader

Version:

There is large amount of information available in market place. The markets are always in sync. In today's world investors find it very difficult to make effective use of information available to them. Shubha Downloader is great tool which resolves this problem and helps investor to increase his productivity and stay focused on decision making. Shubha Downloader enable end user to download market data from available sources and organize it. Shubha Downloader is Open source & FREE utility for end users. Shubha Downloader have main features as follows End of the day market data from web to your favorite charting application . Fundamental market data from web to your favorite charting application. Market reports from web to your favorite charting application.

775 lines (703 loc) 24.2 kB
/** * FiltersFeature is a grid {@link Ext.grid.feature.Feature feature} that allows for a slightly more * robust representation of filtering than what is provided by the default store. * * 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# * * ##Filtering implementations:## * * Default filtering for Strings, Numeric Ranges, Date Ranges, Lists (which can be backed by a * {@link Ext.data.Store}), and Boolean. Additional custom filter types and menus are easily * created by extending {@link Ext.ux.grid.filter.Filter}. * * ##Graphical Indicators:## * * Columns that are filtered have {@link #filterCls a configurable css class} applied to the column headers. * * ##Automatic Reconfiguration:## * * Filters automatically reconfigure when the grid 'reconfigure' event fires. * * ##Stateful:## * * Filter information will be persisted across page loads by specifying a `stateId` * in the Grid configuration. * * The filter collection binds to the {@link Ext.grid.Panel#beforestaterestore beforestaterestore} * and {@link Ext.grid.Panel#beforestatesave beforestatesave} events in order to be stateful. * * ##GridPanel Changes:## * * - A `filters` property is added to the GridPanel using this feature. * - A `filterupdate` event is added to the GridPanel and is fired upon onStateChange completion. * * ##Server side code examples:## * * - [PHP](http://www.vinylfox.com/extjs/grid-filter-php-backend-code.php) - (Thanks VinylFox) * - [Ruby on Rails](http://extjs.com/forum/showthread.php?p=77326#post77326) - (Thanks Zyclops) * - [Ruby on Rails](http://extjs.com/forum/showthread.php?p=176596#post176596) - (Thanks Rotomaul) * * #Example usage:# * * var store = Ext.create('Ext.data.Store', { * pageSize: 15 * ... * }); * * var filtersCfg = { * ftype: 'filters', * 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 headers 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 grid = Ext.create('Ext.grid.Panel', { * store: store, * columns: ..., * features: [filtersCfg], * height: 400, * width: 700, * bbar: Ext.create('Ext.PagingToolbar', { * store: store * }) * }); * * // a filters property is added to the GridPanel * grid.filters */ Ext.define('Ext.ux.grid.FiltersFeature', { extend: 'Ext.grid.feature.Feature', alias: 'feature.filters', uses: [ 'Ext.ux.grid.menu.ListMenu', 'Ext.ux.grid.menu.RangeMenu', 'Ext.ux.grid.filter.BooleanFilter', 'Ext.ux.grid.filter.DateFilter', 'Ext.ux.grid.filter.ListFilter', 'Ext.ux.grid.filter.NumericFilter', 'Ext.ux.grid.filter.StringFilter' ], /** * @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 <code>{@link #updateBuffer}</code>. */ 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 <tt>'ux-filterd-column'</tt>. */ filterCls : 'ux-filtered-column', /** * @cfg {Boolean} local * <tt>true</tt> to use Ext.data.Store filter functions (local filtering) * instead of the default (<tt>false</tt>) server side filtering. */ local : false, /** * @cfg {String} menuFilterText * defaults to <tt>'Filters'</tt>. */ menuFilterText : 'Filters', /** * @cfg {String} paramPrefix * The url parameter prefix for the filters. * Defaults to <tt>'filter'</tt>. */ 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 {Number} updateBuffer * Number of milliseconds to defer store updates since the last filter change. */ updateBuffer : 500, // doesn't handle grid body events hasFeatureEvent: false, /** @private */ constructor : function (config) { var me = this; config = config || {}; Ext.apply(me, config); me.deferredUpdate = Ext.create('Ext.util.DelayedTask', me.reload, me); // Init filters me.filters = me.createFiltersCollection(); me.filterConfigs = config.filters; }, attachEvents: function() { var me = this, view = me.view, headerCt = view.headerCt, grid = me.getGridPanel(); me.bindStore(view.getStore(), true); // Listen for header menu being created headerCt.on('menucreate', me.onMenuCreate, me); view.on('refresh', me.onRefresh, me); grid.on({ scope: me, beforestaterestore: me.applyState, beforestatesave: me.saveState, beforedestroy: me.destroy }); // Add event and filters shortcut on grid panel grid.filters = me; grid.addEvents('filterupdate'); }, createFiltersCollection: function () { return Ext.create('Ext.util.MixedCollection', false, function (o) { return o ? o.dataIndex : null; }); }, /** * @private Create the Filter objects for the current configuration, destroying any existing ones first. */ createFilters: function() { var me = this, hadFilters = me.filters.getCount(), grid = me.getGridPanel(), filters = me.createFiltersCollection(), model = grid.store.model, fields = model.prototype.fields, field, filter, state; if (hadFilters) { state = {}; me.saveState(null, state); } function add (dataIndex, config, filterable) { if (dataIndex && (filterable || config)) { field = fields.get(dataIndex); filter = { dataIndex: dataIndex, type: (field && field.type && field.type.type) || 'auto' }; if (Ext.isObject(config)) { Ext.apply(filter, config); } filters.replace(filter); } } // We start with filters from our config Ext.Array.each(me.filterConfigs, function (filterConfig) { add(filterConfig.dataIndex, filterConfig); }); // Then we merge on filters from the columns in the grid. The columns' filters take precedence. Ext.Array.each(grid.columns, function (column) { if (column.filterable === false) { filters.removeAtKey(column.dataIndex); } else { add(column.dataIndex, column.filter, column.filterable); } }); me.removeAll(); if (filters.items) { me.initializeFilters(filters.items); } if (hadFilters) { me.applyState(null, state); } }, /** * @private */ initializeFilters: function(filters) { var me = this, filtersLength = filters.length, i, filter, FilterClass; for (i = 0; i < filtersLength; i++) { filter = filters[i]; if (filter) { FilterClass = me.getFilterClass(filter.type); filter = filter.menu ? filter : new FilterClass(filter); me.filters.add(filter); Ext.util.Observable.capture(filter, this.onStateChange, this); } } }, /** * @private Handle creation of the grid's header menu. Initializes the filters and listens * for the menu being shown. */ onMenuCreate: function(headerCt, menu) { var me = this; me.createFilters(); menu.on('beforeshow', me.onMenuBeforeShow, me); }, /** * @private Handle showing of the grid's header menu. Sets up the filter item and menu * appropriate for the target column. */ onMenuBeforeShow: function(menu) { var me = this, menuItem, filter; if (me.showMenu) { menuItem = me.menuItem; if (!menuItem || menuItem.isDestroyed) { me.createMenuItem(menu); menuItem = me.menuItem; } filter = me.getMenuFilter(); if (filter) { menuItem.setMenu(filter.menu, false); menuItem.setChecked(filter.active); // disable the menu if filter.disabled explicitly set to true menuItem.setDisabled(filter.disabled === true); } menuItem.setVisible(!!filter); this.sep.setVisible(!!filter); } }, createMenuItem: function(menu) { var me = this; me.sep = menu.add('-'); me.menuItem = menu.add({ checked: false, itemId: 'filters', text: me.menuFilterText, listeners: { scope: me, checkchange: me.onCheckChange, beforecheckchange: me.onBeforeCheck } }); }, getGridPanel: function() { return this.view.up('gridpanel'); }, /** * @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 me = this, key, filter; me.applyingState = true; me.clearFilters(); if (state.filters) { for (key in state.filters) { if (state.filters.hasOwnProperty(key)) { filter = me.filters.get(key); if (filter) { filter.setValue(state.filters[key]); filter.setActive(true); } } } } me.deferredUpdate.cancel(); if (me.local) { me.reload(); } delete me.applyingState; delete state.filters; }, /** * 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); }, /** * @private * Handler called by the grid 'beforedestroy' event */ destroy : function () { var me = this; Ext.destroyMembers(me, 'menuItem', 'sep'); me.removeAll(); me.clearListeners(); }, /** * 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(); } }, /** * Changes the data store bound to this view and refreshes it. * @param {Ext.data.Store} store The store to bind to this view */ bindStore : function(store) { var me = this; // Unbind from the old Store if (me.store && me.storeListeners) { me.store.un(me.storeListeners); } // Set up correct listeners if (store) { me.storeListeners = { scope: me }; if (me.local) { me.storeListeners.load = me.onLoad; } else { me.storeListeners['before' + (store.buffered ? 'prefetch' : 'load')] = me.onBeforeLoad; } store.on(me.storeListeners); } else { delete me.storeListeners; } me.store = store; }, /** * @private * Get the filter menu from the filters MixedCollection based on the clicked header */ getMenuFilter : function () { var header = this.view.headerCt.getMenu().activeHeader; return header ? this.filters.get(header.dataIndex) : null; }, /** @private */ onCheckChange : function (item, value) { this.getMenuFilter().setActive(value); }, /** @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') { var me = this, grid = me.getGridPanel(); if (filter == me.getMenuFilter()) { me.menuItem.setChecked(filter.active, false); } if ((me.autoReload || me.local) && !me.applyingState) { me.deferredUpdate.delay(me.updateBuffer); } me.updateColumnHeadings(); if (!me.applyingState) { grid.saveState(); } grid.fireEvent('filterupdate', me, filter); } }, /** * @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); }, /** * @private * Handler for store's load event when configured for local filtering * @param {Object} store */ onLoad : function (store) { store.filterBy(this.getRecordFilter()); }, /** * @private * Handler called when the grid's view is refreshed */ onRefresh : function () { this.updateColumnHeadings(); }, /** * Update the styles for the header row based on the active filters */ updateColumnHeadings : function () { var me = this, headerCt = me.view.headerCt; if (headerCt) { headerCt.items.each(function(header) { var filter = me.getFilter(header.dataIndex); header[filter && filter.active ? 'addCls' : 'removeCls'](me.filterCls); }); } }, /** @private */ reload : function () { var me = this, store = me.view.getStore(); if (me.local) { store.clearFilter(true); store.filterBy(me.getRecordFilter()); store.sort(); } else { me.deferredUpdate.cancel(); if (store.buffered) { store.pageMap.clear(); } store.loadPage(1); } }, /** * 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; }; }, /** * 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 me = this, columns = me.getGridPanel().columns, i, columnsLength, column, filtersLength, filter; for (i = 0, columnsLength = columns.length; i < columnsLength; i++) { column = columns[i]; if (column.dataIndex === config.dataIndex) { column.filter = config; } } if (me.view.headerCt.menu) { me.createFilters(); } else { // Call getMenu() to ensure the menu is created, and so, also are the filters. We cannot call // createFilters() withouth having a menu because it will cause in a recursion to applyState() // that ends up to clear all the filter values. This is likely to happen when we reorder a column // and then add a new filter before the menu is recreated. me.view.headerCt.getMenu(); } for (i = 0, filtersLength = me.filters.items.length; i < filtersLength; i++) { filter = me.filters.items[i]; if (filter.dataIndex === config.dataIndex) { return filter; } } }, /** * Adds filters to the collection. * @param {Array} filters An Array of filter configuration objects. */ addFilters : function (filters) { if (filters) { var me = this, i, filtersLength; for (i = 0, filtersLength = filters.length; i < filtersLength; i++) { me.addFilter(filters[i]); } } }, /** * 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); }, /** * 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: * * - `false` (Default) : * Flatten into query string of the form (assuming <code>{@link #paramPrefix}='filters'</code>: * * filters[0][field]="someDataIndex"& * filters[0][data][comparison]="someValue1"& * filters[0][data][type]="someValue2"& * filters[0][data][value]="someValue3"& * * * - `true` : * JSON encode the filter data * * {filters:[{"field":"someDataIndex","comparison":"someValue1","type":"someValue2","value":"someValue3"}]} * * Override this method to customize the format of the filter query for remote requests. * * @param {Array} filters A collection of objects representing active filters and their configuration. * Each element will take the form of {field: dataIndex, data: filterConf}. dataIndex is not assured * to be unique as any one filter may be a composite of more basic filters for the same dataIndex. * * @return {Object} Query keys and values */ buildQuery : function (filters) { var p = {}, i, f, root, dataPrefix, key, tmp, len = filters.length; if (!this.encode){ for (i = 0; i < len; i++) { f = filters[i]; root = [this.paramPrefix, '[', i, ']'].join(''); p[root + '[field]'] = f.field; dataPrefix = root + '[data]'; for (key in f.data) { p[[dataPrefix, '[', key, ']'].join('')] = f.data[key]; } } } else { tmp = []; for (i = 0; i < len; i++) { f = filters[i]; tmp.push(Ext.apply( {}, {field: f.field}, f.data )); } // only build if there is active filter if (tmp.length > 0){ p[this.paramPrefix] = Ext.JSON.encode(tmp); } } return p; }, /** * Removes filter related query parameters from the provided object. * @param {Object} p Query parameters that may contain filter related fields. */ cleanParams : function (p) { // if encoding just delete the property if (this.encode) { delete p[this.paramPrefix]; // otherwise scrub the object of filter data } else { var regex, key; regex = new RegExp('^' + this.paramPrefix + '\[[0-9]+\]'); for (key in p) { if (regex.test(key)) { delete p[key]; } } } }, /** * Function for locating filter classes, overwrite this with your favorite * loader to provide dynamic filter loading. * @param {String} type The type of filter to load ('Filter' is automatically * appended to the passed type; eg, 'string' becomes 'StringFilter'). * @return {Function} The Ext.ux.grid.filter.Class */ getFilterClass : function (type) { // map the supported Ext.data.Field type values into a supported filter switch(type) { case 'auto': type = 'string'; break; case 'int': case 'float': type = 'numeric'; break; case 'bool': type = 'boolean'; break; } return Ext.ClassManager.getByAlias('gridfilter.' + type); } });