/ext-4.0.7/pkgs/classes.js
JavaScript | 14596 lines | 6692 code | 1488 blank | 6416 comment | 1428 complexity | a081e388c7e0f979768b033e444b0e49 MD5 | raw file
- /*
- This file is part of Ext JS 4
- Copyright (c) 2011 Sencha Inc
- Contact: http://www.sencha.com/contact
- GNU General Public License Usage
- This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
- If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
- */
- /**
- * Base class that provides a common interface for publishing events. Subclasses are expected to to have a property
- * "events" with all the events defined, and, optionally, a property "listeners" with configured listeners defined.
- *
- * For example:
- *
- * Ext.define('Employee', {
- * extend: 'Ext.util.Observable',
- * constructor: function(config){
- * this.name = config.name;
- * this.addEvents({
- * "fired" : true,
- * "quit" : true
- * });
- *
- * // Copy configured listeners into *this* object so that the base class's
- * // constructor will add them.
- * this.listeners = config.listeners;
- *
- * // Call our superclass constructor to complete construction process.
- * this.callParent(arguments)
- * }
- * });
- *
- * This could then be used like this:
- *
- * var newEmployee = new Employee({
- * name: employeeName,
- * listeners: {
- * quit: function() {
- * // By default, "this" will be the object that fired the event.
- * alert(this.name + " has quit!");
- * }
- * }
- * });
- */
- Ext.define('Ext.util.Observable', {
- /* Begin Definitions */
- requires: ['Ext.util.Event'],
- statics: {
- /**
- * Removes **all** added captures from the Observable.
- *
- * @param {Ext.util.Observable} o The Observable to release
- * @static
- */
- releaseCapture: function(o) {
- o.fireEvent = this.prototype.fireEvent;
- },
- /**
- * Starts capture on the specified Observable. All events will be passed to the supplied function with the event
- * name + standard signature of the event **before** the event is fired. If the supplied function returns false,
- * the event will not fire.
- *
- * @param {Ext.util.Observable} o The Observable to capture events from.
- * @param {Function} fn The function to call when an event is fired.
- * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed. Defaults to
- * the Observable firing the event.
- * @static
- */
- capture: function(o, fn, scope) {
- o.fireEvent = Ext.Function.createInterceptor(o.fireEvent, fn, scope);
- },
- /**
- * Sets observability on the passed class constructor.
- *
- * This makes any event fired on any instance of the passed class also fire a single event through
- * the **class** allowing for central handling of events on many instances at once.
- *
- * Usage:
- *
- * Ext.util.Observable.observe(Ext.data.Connection);
- * Ext.data.Connection.on('beforerequest', function(con, options) {
- * console.log('Ajax request made to ' + options.url);
- * });
- *
- * @param {Function} c The class constructor to make observable.
- * @param {Object} listeners An object containing a series of listeners to add. See {@link #addListener}.
- * @static
- */
- observe: function(cls, listeners) {
- if (cls) {
- if (!cls.isObservable) {
- Ext.applyIf(cls, new this());
- this.capture(cls.prototype, cls.fireEvent, cls);
- }
- if (Ext.isObject(listeners)) {
- cls.on(listeners);
- }
- return cls;
- }
- }
- },
- /* End Definitions */
- /**
- * @cfg {Object} listeners
- *
- * A config object containing one or more event handlers to be added to this object during initialization. This
- * should be a valid listeners config object as specified in the {@link #addListener} example for attaching multiple
- * handlers at once.
- *
- * **DOM events from Ext JS {@link Ext.Component Components}**
- *
- * While _some_ Ext JS Component classes export selected DOM events (e.g. "click", "mouseover" etc), this is usually
- * only done when extra value can be added. For example the {@link Ext.view.View DataView}'s **`{@link
- * Ext.view.View#itemclick itemclick}`** event passing the node clicked on. To access DOM events directly from a
- * child element of a Component, we need to specify the `element` option to identify the Component property to add a
- * DOM listener to:
- *
- * new Ext.panel.Panel({
- * width: 400,
- * height: 200,
- * dockedItems: [{
- * xtype: 'toolbar'
- * }],
- * listeners: {
- * click: {
- * element: 'el', //bind to the underlying el property on the panel
- * fn: function(){ console.log('click el'); }
- * },
- * dblclick: {
- * element: 'body', //bind to the underlying body property on the panel
- * fn: function(){ console.log('dblclick body'); }
- * }
- * }
- * });
- */
- // @private
- isObservable: true,
- constructor: function(config) {
- var me = this;
- Ext.apply(me, config);
- if (me.listeners) {
- me.on(me.listeners);
- delete me.listeners;
- }
- me.events = me.events || {};
- if (me.bubbleEvents) {
- me.enableBubble(me.bubbleEvents);
- }
- },
- // @private
- eventOptionsRe : /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|element|vertical|horizontal|freezeEvent)$/,
- /**
- * Adds listeners to any Observable object (or Ext.Element) which are automatically removed when this Component is
- * destroyed.
- *
- * @param {Ext.util.Observable/Ext.Element} item The item to which to add a listener/listeners.
- * @param {Object/String} ename The event name, or an object containing event name properties.
- * @param {Function} fn (optional) If the `ename` parameter was an event name, this is the handler function.
- * @param {Object} scope (optional) If the `ename` parameter was an event name, this is the scope (`this` reference)
- * in which the handler function is executed.
- * @param {Object} opt (optional) If the `ename` parameter was an event name, this is the
- * {@link Ext.util.Observable#addListener addListener} options.
- */
- addManagedListener : function(item, ename, fn, scope, options) {
- var me = this,
- managedListeners = me.managedListeners = me.managedListeners || [],
- config;
- if (typeof ename !== 'string') {
- options = ename;
- for (ename in options) {
- if (options.hasOwnProperty(ename)) {
- config = options[ename];
- if (!me.eventOptionsRe.test(ename)) {
- me.addManagedListener(item, ename, config.fn || config, config.scope || options.scope, config.fn ? config : options);
- }
- }
- }
- }
- else {
- managedListeners.push({
- item: item,
- ename: ename,
- fn: fn,
- scope: scope,
- options: options
- });
- item.on(ename, fn, scope, options);
- }
- },
- /**
- * Removes listeners that were added by the {@link #mon} method.
- *
- * @param {Ext.util.Observable/Ext.Element} item The item from which to remove a listener/listeners.
- * @param {Object/String} ename The event name, or an object containing event name properties.
- * @param {Function} fn (optional) If the `ename` parameter was an event name, this is the handler function.
- * @param {Object} scope (optional) If the `ename` parameter was an event name, this is the scope (`this` reference)
- * in which the handler function is executed.
- */
- removeManagedListener : function(item, ename, fn, scope) {
- var me = this,
- options,
- config,
- managedListeners,
- length,
- i;
- if (typeof ename !== 'string') {
- options = ename;
- for (ename in options) {
- if (options.hasOwnProperty(ename)) {
- config = options[ename];
- if (!me.eventOptionsRe.test(ename)) {
- me.removeManagedListener(item, ename, config.fn || config, config.scope || options.scope);
- }
- }
- }
- }
- managedListeners = me.managedListeners ? me.managedListeners.slice() : [];
- for (i = 0, length = managedListeners.length; i < length; i++) {
- me.removeManagedListenerItem(false, managedListeners[i], item, ename, fn, scope);
- }
- },
- /**
- * Fires the specified event with the passed parameters (minus the event name, plus the `options` object passed
- * to {@link #addListener}).
- *
- * An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget}) by
- * calling {@link #enableBubble}.
- *
- * @param {String} eventName The name of the event to fire.
- * @param {Object...} args Variable number of parameters are passed to handlers.
- * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
- */
- fireEvent: function(eventName) {
- var name = eventName.toLowerCase(),
- events = this.events,
- event = events && events[name],
- bubbles = event && event.bubble;
- return this.continueFireEvent(name, Ext.Array.slice(arguments, 1), bubbles);
- },
- /**
- * Continue to fire event.
- * @private
- *
- * @param {String} eventName
- * @param {Array} args
- * @param {Boolean} bubbles
- */
- continueFireEvent: function(eventName, args, bubbles) {
- var target = this,
- queue, event,
- ret = true;
- do {
- if (target.eventsSuspended === true) {
- if ((queue = target.eventQueue)) {
- queue.push([eventName, args, bubbles]);
- }
- return ret;
- } else {
- event = target.events[eventName];
- // Continue bubbling if event exists and it is `true` or the handler didn't returns false and it
- // configure to bubble.
- if (event && event != true) {
- if ((ret = event.fire.apply(event, args)) === false) {
- break;
- }
- }
- }
- } while (bubbles && (target = target.getBubbleParent()));
- return ret;
- },
- /**
- * Gets the bubbling parent for an Observable
- * @private
- * @return {Ext.util.Observable} The bubble parent. null is returned if no bubble target exists
- */
- getBubbleParent: function(){
- var me = this, parent = me.getBubbleTarget && me.getBubbleTarget();
- if (parent && parent.isObservable) {
- return parent;
- }
- return null;
- },
- /**
- * Appends an event handler to this object.
- *
- * @param {String} eventName The name of the event to listen for. May also be an object who's property names are
- * event names.
- * @param {Function} fn The method the event invokes. Will be called with arguments given to
- * {@link #fireEvent} plus the `options` parameter described below.
- * @param {Object} [scope] The scope (`this` reference) in which the handler function is executed. **If
- * omitted, defaults to the object which fired the event.**
- * @param {Object} [options] An object containing handler configuration.
- *
- * **Note:** Unlike in ExtJS 3.x, the options object will also be passed as the last argument to every event handler.
- *
- * This object may contain any of the following properties:
- *
- * - **scope** : Object
- *
- * The scope (`this` reference) in which the handler function is executed. **If omitted, defaults to the object
- * which fired the event.**
- *
- * - **delay** : Number
- *
- * The number of milliseconds to delay the invocation of the handler after the event fires.
- *
- * - **single** : Boolean
- *
- * True to add a handler to handle just the next firing of the event, and then remove itself.
- *
- * - **buffer** : Number
- *
- * Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed by the specified number of
- * milliseconds. If the event fires again within that time, the original handler is _not_ invoked, but the new
- * handler is scheduled in its place.
- *
- * - **target** : Observable
- *
- * Only call the handler if the event was fired on the target Observable, _not_ if the event was bubbled up from a
- * child Observable.
- *
- * - **element** : String
- *
- * **This option is only valid for listeners bound to {@link Ext.Component Components}.** The name of a Component
- * property which references an element to add a listener to.
- *
- * This option is useful during Component construction to add DOM event listeners to elements of
- * {@link Ext.Component Components} which will exist only after the Component is rendered.
- * For example, to add a click listener to a Panel's body:
- *
- * new Ext.panel.Panel({
- * title: 'The title',
- * listeners: {
- * click: this.handlePanelClick,
- * element: 'body'
- * }
- * });
- *
- * **Combining Options**
- *
- * Using the options argument, it is possible to combine different types of listeners:
- *
- * A delayed, one-time listener.
- *
- * myPanel.on('hide', this.handleClick, this, {
- * single: true,
- * delay: 100
- * });
- *
- * **Attaching multiple handlers in 1 call**
- *
- * The method also allows for a single argument to be passed which is a config object containing properties which
- * specify multiple events. For example:
- *
- * myGridPanel.on({
- * cellClick: this.onCellClick,
- * mouseover: this.onMouseOver,
- * mouseout: this.onMouseOut,
- * scope: this // Important. Ensure "this" is correct during handler execution
- * });
- *
- * One can also specify options for each event handler separately:
- *
- * myGridPanel.on({
- * cellClick: {fn: this.onCellClick, scope: this, single: true},
- * mouseover: {fn: panel.onMouseOver, scope: panel}
- * });
- *
- */
- addListener: function(ename, fn, scope, options) {
- var me = this,
- config,
- event;
- if (typeof ename !== 'string') {
- options = ename;
- for (ename in options) {
- if (options.hasOwnProperty(ename)) {
- config = options[ename];
- if (!me.eventOptionsRe.test(ename)) {
- me.addListener(ename, config.fn || config, config.scope || options.scope, config.fn ? config : options);
- }
- }
- }
- }
- else {
- ename = ename.toLowerCase();
- me.events[ename] = me.events[ename] || true;
- event = me.events[ename] || true;
- if (Ext.isBoolean(event)) {
- me.events[ename] = event = new Ext.util.Event(me, ename);
- }
- event.addListener(fn, scope, Ext.isObject(options) ? options : {});
- }
- },
- /**
- * Removes an event handler.
- *
- * @param {String} eventName The type of event the handler was associated with.
- * @param {Function} fn The handler to remove. **This must be a reference to the function passed into the
- * {@link #addListener} call.**
- * @param {Object} scope (optional) The scope originally specified for the handler. It must be the same as the
- * scope argument specified in the original call to {@link #addListener} or the listener will not be removed.
- */
- removeListener: function(ename, fn, scope) {
- var me = this,
- config,
- event,
- options;
- if (typeof ename !== 'string') {
- options = ename;
- for (ename in options) {
- if (options.hasOwnProperty(ename)) {
- config = options[ename];
- if (!me.eventOptionsRe.test(ename)) {
- me.removeListener(ename, config.fn || config, config.scope || options.scope);
- }
- }
- }
- } else {
- ename = ename.toLowerCase();
- event = me.events[ename];
- if (event && event.isEvent) {
- event.removeListener(fn, scope);
- }
- }
- },
- /**
- * Removes all listeners for this object including the managed listeners
- */
- clearListeners: function() {
- var events = this.events,
- event,
- key;
- for (key in events) {
- if (events.hasOwnProperty(key)) {
- event = events[key];
- if (event.isEvent) {
- event.clearListeners();
- }
- }
- }
- this.clearManagedListeners();
- },
- //<debug>
- purgeListeners : function() {
- if (Ext.global.console) {
- Ext.global.console.warn('Observable: purgeListeners has been deprecated. Please use clearListeners.');
- }
- return this.clearListeners.apply(this, arguments);
- },
- //</debug>
- /**
- * Removes all managed listeners for this object.
- */
- clearManagedListeners : function() {
- var managedListeners = this.managedListeners || [],
- i = 0,
- len = managedListeners.length;
- for (; i < len; i++) {
- this.removeManagedListenerItem(true, managedListeners[i]);
- }
- this.managedListeners = [];
- },
- /**
- * Remove a single managed listener item
- * @private
- * @param {Boolean} isClear True if this is being called during a clear
- * @param {Object} managedListener The managed listener item
- * See removeManagedListener for other args
- */
- removeManagedListenerItem: function(isClear, managedListener, item, ename, fn, scope){
- if (isClear || (managedListener.item === item && managedListener.ename === ename && (!fn || managedListener.fn === fn) && (!scope || managedListener.scope === scope))) {
- managedListener.item.un(managedListener.ename, managedListener.fn, managedListener.scope);
- if (!isClear) {
- Ext.Array.remove(this.managedListeners, managedListener);
- }
- }
- },
- //<debug>
- purgeManagedListeners : function() {
- if (Ext.global.console) {
- Ext.global.console.warn('Observable: purgeManagedListeners has been deprecated. Please use clearManagedListeners.');
- }
- return this.clearManagedListeners.apply(this, arguments);
- },
- //</debug>
- /**
- * Adds the specified events to the list of events which this Observable may fire.
- *
- * @param {Object/String} o Either an object with event names as properties with a value of `true` or the first
- * event name string if multiple event names are being passed as separate parameters. Usage:
- *
- * this.addEvents({
- * storeloaded: true,
- * storecleared: true
- * });
- *
- * @param {String...} more (optional) Additional event names if multiple event names are being passed as separate
- * parameters. Usage:
- *
- * this.addEvents('storeloaded', 'storecleared');
- *
- */
- addEvents: function(o) {
- var me = this,
- args,
- len,
- i;
- me.events = me.events || {};
- if (Ext.isString(o)) {
- args = arguments;
- i = args.length;
- while (i--) {
- me.events[args[i]] = me.events[args[i]] || true;
- }
- } else {
- Ext.applyIf(me.events, o);
- }
- },
- /**
- * Checks to see if this object has any listeners for a specified event
- *
- * @param {String} eventName The name of the event to check for
- * @return {Boolean} True if the event is being listened for, else false
- */
- hasListener: function(ename) {
- var event = this.events[ename.toLowerCase()];
- return event && event.isEvent === true && event.listeners.length > 0;
- },
- /**
- * Suspends the firing of all events. (see {@link #resumeEvents})
- *
- * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
- * after the {@link #resumeEvents} call instead of discarding all suspended events.
- */
- suspendEvents: function(queueSuspended) {
- this.eventsSuspended = true;
- if (queueSuspended && !this.eventQueue) {
- this.eventQueue = [];
- }
- },
- /**
- * Resumes firing events (see {@link #suspendEvents}).
- *
- * If events were suspended using the `queueSuspended` parameter, then all events fired
- * during event suspension will be sent to any listeners now.
- */
- resumeEvents: function() {
- var me = this,
- queued = me.eventQueue;
- me.eventsSuspended = false;
- delete me.eventQueue;
- if (queued) {
- Ext.each(queued, function(e) {
- me.continueFireEvent.apply(me, e);
- });
- }
- },
- /**
- * Relays selected events from the specified Observable as if the events were fired by `this`.
- *
- * @param {Object} origin The Observable whose events this object is to relay.
- * @param {String[]} events Array of event names to relay.
- * @param {String} prefix
- */
- relayEvents : function(origin, events, prefix) {
- prefix = prefix || '';
- var me = this,
- len = events.length,
- i = 0,
- oldName,
- newName;
- for (; i < len; i++) {
- oldName = events[i].substr(prefix.length);
- newName = prefix + oldName;
- me.events[newName] = me.events[newName] || true;
- origin.on(oldName, me.createRelayer(newName));
- }
- },
- /**
- * @private
- * Creates an event handling function which refires the event from this object as the passed event name.
- * @param newName
- * @returns {Function}
- */
- createRelayer: function(newName){
- var me = this;
- return function(){
- return me.fireEvent.apply(me, [newName].concat(Array.prototype.slice.call(arguments, 0, -1)));
- };
- },
- /**
- * Enables events fired by this Observable to bubble up an owner hierarchy by calling `this.getBubbleTarget()` if
- * present. There is no implementation in the Observable base class.
- *
- * This is commonly used by Ext.Components to bubble events to owner Containers.
- * See {@link Ext.Component#getBubbleTarget}. The default implementation in Ext.Component returns the
- * Component's immediate owner. But if a known target is required, this can be overridden to access the
- * required target more quickly.
- *
- * Example:
- *
- * Ext.override(Ext.form.field.Base, {
- * // Add functionality to Field's initComponent to enable the change event to bubble
- * initComponent : Ext.Function.createSequence(Ext.form.field.Base.prototype.initComponent, function() {
- * this.enableBubble('change');
- * }),
- *
- * // We know that we want Field's events to bubble directly to the FormPanel.
- * getBubbleTarget : function() {
- * if (!this.formPanel) {
- * this.formPanel = this.findParentByType('form');
- * }
- * return this.formPanel;
- * }
- * });
- *
- * var myForm = new Ext.formPanel({
- * title: 'User Details',
- * items: [{
- * ...
- * }],
- * listeners: {
- * change: function() {
- * // Title goes red if form has been modified.
- * myForm.header.setStyle('color', 'red');
- * }
- * }
- * });
- *
- * @param {String/String[]} events The event name to bubble, or an Array of event names.
- */
- enableBubble: function(events) {
- var me = this;
- if (!Ext.isEmpty(events)) {
- events = Ext.isArray(events) ? events: Ext.Array.toArray(arguments);
- Ext.each(events,
- function(ename) {
- ename = ename.toLowerCase();
- var ce = me.events[ename] || true;
- if (Ext.isBoolean(ce)) {
- ce = new Ext.util.Event(me, ename);
- me.events[ename] = ce;
- }
- ce.bubble = true;
- });
- }
- }
- }, function() {
- this.createAlias({
- /**
- * @method
- * Shorthand for {@link #addListener}.
- * @alias Ext.util.Observable#addListener
- */
- on: 'addListener',
- /**
- * @method
- * Shorthand for {@link #removeListener}.
- * @alias Ext.util.Observable#removeListener
- */
- un: 'removeListener',
- /**
- * @method
- * Shorthand for {@link #addManagedListener}.
- * @alias Ext.util.Observable#addManagedListener
- */
- mon: 'addManagedListener',
- /**
- * @method
- * Shorthand for {@link #removeManagedListener}.
- * @alias Ext.util.Observable#removeManagedListener
- */
- mun: 'removeManagedListener'
- });
- //deprecated, will be removed in 5.0
- this.observeClass = this.observe;
- Ext.apply(Ext.util.Observable.prototype, function(){
- // this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)
- // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
- // private
- function getMethodEvent(method){
- var e = (this.methodEvents = this.methodEvents || {})[method],
- returnValue,
- v,
- cancel,
- obj = this;
- if (!e) {
- this.methodEvents[method] = e = {};
- e.originalFn = this[method];
- e.methodName = method;
- e.before = [];
- e.after = [];
- var makeCall = function(fn, scope, args){
- if((v = fn.apply(scope || obj, args)) !== undefined){
- if (typeof v == 'object') {
- if(v.returnValue !== undefined){
- returnValue = v.returnValue;
- }else{
- returnValue = v;
- }
- cancel = !!v.cancel;
- }
- else
- if (v === false) {
- cancel = true;
- }
- else {
- returnValue = v;
- }
- }
- };
- this[method] = function(){
- var args = Array.prototype.slice.call(arguments, 0),
- b, i, len;
- returnValue = v = undefined;
- cancel = false;
- for(i = 0, len = e.before.length; i < len; i++){
- b = e.before[i];
- makeCall(b.fn, b.scope, args);
- if (cancel) {
- return returnValue;
- }
- }
- if((v = e.originalFn.apply(obj, args)) !== undefined){
- returnValue = v;
- }
- for(i = 0, len = e.after.length; i < len; i++){
- b = e.after[i];
- makeCall(b.fn, b.scope, args);
- if (cancel) {
- return returnValue;
- }
- }
- return returnValue;
- };
- }
- return e;
- }
- return {
- // these are considered experimental
- // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
- // adds an 'interceptor' called before the original method
- beforeMethod : function(method, fn, scope){
- getMethodEvent.call(this, method).before.push({
- fn: fn,
- scope: scope
- });
- },
- // adds a 'sequence' called after the original method
- afterMethod : function(method, fn, scope){
- getMethodEvent.call(this, method).after.push({
- fn: fn,
- scope: scope
- });
- },
- removeMethodListener: function(method, fn, scope){
- var e = this.getMethodEvent(method),
- i, len;
- for(i = 0, len = e.before.length; i < len; i++){
- if(e.before[i].fn == fn && e.before[i].scope == scope){
- Ext.Array.erase(e.before, i, 1);
- return;
- }
- }
- for(i = 0, len = e.after.length; i < len; i++){
- if(e.after[i].fn == fn && e.after[i].scope == scope){
- Ext.Array.erase(e.after, i, 1);
- return;
- }
- }
- },
- toggleEventLogging: function(toggle) {
- Ext.util.Observable[toggle ? 'capture' : 'releaseCapture'](this, function(en) {
- if (Ext.isDefined(Ext.global.console)) {
- Ext.global.console.log(en, arguments);
- }
- });
- }
- };
- }());
- });
- /**
- * @class Ext.util.Animate
- * This animation class is a mixin.
- *
- * Ext.util.Animate provides an API for the creation of animated transitions of properties and styles.
- * This class is used as a mixin and currently applied to {@link Ext.Element}, {@link Ext.CompositeElement},
- * {@link Ext.draw.Sprite}, {@link Ext.draw.CompositeSprite}, and {@link Ext.Component}. Note that Components
- * have a limited subset of what attributes can be animated such as top, left, x, y, height, width, and
- * opacity (color, paddings, and margins can not be animated).
- *
- * ## Animation Basics
- *
- * All animations require three things - `easing`, `duration`, and `to` (the final end value for each property)
- * you wish to animate. Easing and duration are defaulted values specified below.
- * Easing describes how the intermediate values used during a transition will be calculated.
- * {@link Ext.fx.Anim#easing Easing} allows for a transition to change speed over its duration.
- * You may use the defaults for easing and duration, but you must always set a
- * {@link Ext.fx.Anim#to to} property which is the end value for all animations.
- *
- * Popular element 'to' configurations are:
- *
- * - opacity
- * - x
- * - y
- * - color
- * - height
- * - width
- *
- * Popular sprite 'to' configurations are:
- *
- * - translation
- * - path
- * - scale
- * - stroke
- * - rotation
- *
- * The default duration for animations is 250 (which is a 1/4 of a second). Duration is denoted in
- * milliseconds. Therefore 1 second is 1000, 1 minute would be 60000, and so on. The default easing curve
- * used for all animations is 'ease'. Popular easing functions are included and can be found in {@link Ext.fx.Anim#easing Easing}.
- *
- * For example, a simple animation to fade out an element with a default easing and duration:
- *
- * var p1 = Ext.get('myElementId');
- *
- * p1.animate({
- * to: {
- * opacity: 0
- * }
- * });
- *
- * To make this animation fade out in a tenth of a second:
- *
- * var p1 = Ext.get('myElementId');
- *
- * p1.animate({
- * duration: 100,
- * to: {
- * opacity: 0
- * }
- * });
- *
- * ## Animation Queues
- *
- * By default all animations are added to a queue which allows for animation via a chain-style API.
- * For example, the following code will queue 4 animations which occur sequentially (one right after the other):
- *
- * p1.animate({
- * to: {
- * x: 500
- * }
- * }).animate({
- * to: {
- * y: 150
- * }
- * }).animate({
- * to: {
- * backgroundColor: '#f00' //red
- * }
- * }).animate({
- * to: {
- * opacity: 0
- * }
- * });
- *
- * You can change this behavior by calling the {@link Ext.util.Animate#syncFx syncFx} method and all
- * subsequent animations for the specified target will be run concurrently (at the same time).
- *
- * p1.syncFx(); //this will make all animations run at the same time
- *
- * p1.animate({
- * to: {
- * x: 500
- * }
- * }).animate({
- * to: {
- * y: 150
- * }
- * }).animate({
- * to: {
- * backgroundColor: '#f00' //red
- * }
- * }).animate({
- * to: {
- * opacity: 0
- * }
- * });
- *
- * This works the same as:
- *
- * p1.animate({
- * to: {
- * x: 500,
- * y: 150,
- * backgroundColor: '#f00' //red
- * opacity: 0
- * }
- * });
- *
- * The {@link Ext.util.Animate#stopAnimation stopAnimation} method can be used to stop any
- * currently running animations and clear any queued animations.
- *
- * ## Animation Keyframes
- *
- * You can also set up complex animations with {@link Ext.fx.Anim#keyframes keyframes} which follow the
- * CSS3 Animation configuration pattern. Note rotation, translation, and scaling can only be done for sprites.
- * The previous example can be written with the following syntax:
- *
- * p1.animate({
- * duration: 1000, //one second total
- * keyframes: {
- * 25: { //from 0 to 250ms (25%)
- * x: 0
- * },
- * 50: { //from 250ms to 500ms (50%)
- * y: 0
- * },
- * 75: { //from 500ms to 750ms (75%)
- * backgroundColor: '#f00' //red
- * },
- * 100: { //from 750ms to 1sec
- * opacity: 0
- * }
- * }
- * });
- *
- * ## Animation Events
- *
- * Each animation you create has events for {@link Ext.fx.Anim#beforeanimate beforeanimate},
- * {@link Ext.fx.Anim#afteranimate afteranimate}, and {@link Ext.fx.Anim#lastframe lastframe}.
- * Keyframed animations adds an additional {@link Ext.fx.Animator#keyframe keyframe} event which
- * fires for each keyframe in your animation.
- *
- * All animations support the {@link Ext.util.Observable#listeners listeners} configuration to attact functions to these events.
- *
- * startAnimate: function() {
- * var p1 = Ext.get('myElementId');
- * p1.animate({
- * duration: 100,
- * to: {
- * opacity: 0
- * },
- * listeners: {
- * beforeanimate: function() {
- * // Execute my custom method before the animation
- * this.myBeforeAnimateFn();
- * },
- * afteranimate: function() {
- * // Execute my custom method after the animation
- * this.myAfterAnimateFn();
- * },
- * scope: this
- * });
- * },
- * myBeforeAnimateFn: function() {
- * // My custom logic
- * },
- * myAfterAnimateFn: function() {
- * // My custom logic
- * }
- *
- * Due to the fact that animations run asynchronously, you can determine if an animation is currently
- * running on any target by using the {@link Ext.util.Animate#getActiveAnimation getActiveAnimation}
- * method. This method will return false if there are no active animations or return the currently
- * running {@link Ext.fx.Anim} instance.
- *
- * In this example, we're going to wait for the current animation to finish, then stop any other
- * queued animations before we fade our element's opacity to 0:
- *
- * var curAnim = p1.getActiveAnimation();
- * if (curAnim) {
- * curAnim.on('afteranimate', function() {
- * p1.stopAnimation();
- * p1.animate({
- * to: {
- * opacity: 0
- * }
- * });
- * });
- * }
- *
- * @docauthor Jamie Avins <jamie@sencha.com>
- */
- Ext.define('Ext.util.Animate', {
- uses: ['Ext.fx.Manager', 'Ext.fx.Anim'],
- /**
- * <p>Perform custom animation on this object.<p>
- * <p>This method is applicable to both the {@link Ext.Component Component} class and the {@link Ext.Element Element} class.
- * It performs animated transitions of certain properties of this object over a specified timeline.</p>
- * <p>The sole parameter is an object which specifies start property values, end property values, and properties which
- * describe the timeline. Of the properties listed below, only <b><code>to</code></b> is mandatory.</p>
- * <p>Properties include<ul>
- * <li><code>from</code> <div class="sub-desc">An object which specifies start values for the properties being animated.
- * If not supplied, properties are animated from current settings. The actual properties which may be animated depend upon
- * ths object being animated. See the sections below on Element and Component animation.<div></li>
- * <li><code>to</code> <div class="sub-desc">An object which specifies end values for the properties being animated.</div></li>
- * <li><code>duration</code><div class="sub-desc">The duration <b>in milliseconds</b> for which the animation will run.</div></li>
- * <li><code>easing</code> <div class="sub-desc">A string value describing an easing type to modify the rate of change from the default linear to non-linear. Values may be one of:<code><ul>
- * <li>ease</li>
- * <li>easeIn</li>
- * <li>easeOut</li>
- * <li>easeInOut</li>
- * <li>backIn</li>
- * <li>backOut</li>
- * <li>elasticIn</li>
- * <li>elasticOut</li>
- * <li>bounceIn</li>
- * <li>bounceOut</li>
- * </ul></code></div></li>
- * <li><code>keyframes</code> <div class="sub-desc">This is an object which describes the state of animated properties at certain points along the timeline.
- * it is an object containing properties who's names are the percentage along the timeline being described and who's values specify the animation state at that point.</div></li>
- * <li><code>listeners</code> <div class="sub-desc">This is a standard {@link Ext.util.Observable#listeners listeners} configuration object which may be used
- * to inject behaviour at either the <code>beforeanimate</code> event or the <code>afteranimate</code> event.</div></li>
- * </ul></p>
- * <h3>Animating an {@link Ext.Element Element}</h3>
- * When animating an Element, the following properties may be specified in <code>from</code>, <code>to</code>, and <code>keyframe</code> objects:<ul>
- * <li><code>x</code> <div class="sub-desc">The page X position in pixels.</div></li>
- * <li><code>y</code> <div class="sub-desc">The page Y position in pixels</div></li>
- * <li><code>left</code> <div class="sub-desc">The element's CSS <code>left</code> value. Units must be supplied.</div></li>
- * <li><code>top</code> <div class="sub-desc">The element's CSS <code>top</code> value. Units must be supplied.</div></li>
- * <li><code>width</code> <div class="sub-desc">The element's CSS <code>width</code> value. Units must be supplied.</div></li>
- * <li><code>height</code> <div class="sub-desc">The element's CSS <code>height</code> value. Units must be supplied.</div></li>
- * <li><code>scrollLeft</code> <div class="sub-desc">The element's <code>scrollLeft</code> value.</div></li>
- * <li><code>scrollTop</code> <div class="sub-desc">The element's <code>scrollLeft</code> value.</div></li>
- * <li><code>opacity</code> <div class="sub-desc">The element's <code>opacity</code> value. This must be a value between <code>0</code> and <code>1</code>.</div></li>
- * </ul>
- * <p><b>Be aware than animating an Element which is being used by an Ext Component without in some way informing the Component about the changed element state
- * will result in incorrect Component behaviour. This is because the Component will be using the old state of the element. To avoid this problem, it is now possible to
- * directly animate certain properties of Components.</b></p>
- * <h3>Animating a {@link Ext.Component Component}</h3>
- * When animating an Element, the following properties may be specified in <code>from</code>, <code>to</code>, and <code>keyframe</code> objects:<ul>
- * <li><code>x</code> <div class="sub-desc">The Component's page X position in pixels.</div></li>
- * <li><code>y</code> <div class="sub-desc">The Component's page Y position in pixels</div></li>
- * <li><code>left</code> <div class="sub-desc">The Component's <code>left</code> value in pixels.</div></li>
- * <li><code>top</code> <div class="sub-desc">The Component's <code>top</code> value in pixels.</div></li>
- * <li><code>width</code> <div class="sub-desc">The Component's <code>width</code> value in pixels.</div></li>
- * <li><code>width</code> <div class="sub-desc">The Component's <code>width</code> value in pixels.</div></li>
- * <li><code>dynamic</code> <div class="sub-desc">Specify as true to update the Component's layout (if it is a Container) at every frame
- * of the animation. <i>Use sparingly as laying out on every intermediate size change is an expensive operation</i>.</div></li>
- * </ul>
- * <p>For example, to animate a Window to a new size, ensuring that its internal layout, and any shadow is correct:</p>
- * <pre><code>
- myWindow = Ext.create('Ext.window.Window', {
- title: 'Test Component animation',
- width: 500,
- height: 300,
- layout: {
- type: 'hbox',
- align: 'stretch'
- },
- items: [{
- title: 'Left: 33%',
- margins: '5 0 5 5',
- flex: 1
- }, {
- title: 'Left: 66%',
- margins: '5 5 5 5',
- flex: 2
- }]
- });
- myWindow.show();
- myWindow.header.el.on('click', function() {
- myWindow.animate({
- to: {
- width: (myWindow.getWidth() == 500) ? 700 : 500,
- height: (myWindow.getHeight() == 300) ? 400 : 300,
- }
- });
- });
- </code></pre>
- * <p>For performance reasons, by default, the internal layout is only updated when the Window reaches its final <code>"to"</code> size. If dynamic updating of the Window's child
- * Components is required, then configure the animation with <code>dynamic: true</code> and the two child items will maintain their proportions during the animation.</p>
- * @param {Object} config An object containing properties which describe the animation's start and end states, and the timeline of the animation.
- * @return {Object} this
- */
- animate: function(animObj) {
- var me = this;
- if (Ext.fx.Manager.hasFxBlock(me.id)) {
- return me;
- }
- Ext.fx.Manager.queueFx(Ext.create('Ext.fx.Anim', me.anim(animObj)));
- return this;
- },
- // @private - process the passed fx configuration.
- anim: function(config) {
- if (!Ext.isObject(config)) {
- return (config) ? {} : false;
- }
- var me = this;
- if (config.stopAnimation) {
- me.stopAnimation();
- }
- Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id));
- return Ext.apply({
- target: me,
- paused: true
- }, config);
- },
- /**
- * @deprecated 4.0 Replaced by {@link #stopAnimation}
- * Stops any running effects and clears this object's internal effects queue if it contains
- * any additional effects that haven't started yet.
- * @return {Ext.Element} The Element
- * @method
- */
- stopFx: Ext.Function.alias(Ext.util.Animate, 'stopAnimation'),
- /**
- * Stops any running effects and clears this object's internal effects queue if it contains
- * any additional effects that haven't started yet.
- * @return {Ext.Element} The Element
- */
- stopAnimation: function() {
- Ext.fx.Manager.stopAnimation(this.id);
- return this;
- },
- /**
- * Ensures that all effects queued after syncFx is called on this object are
- * run concurrently. This is the opposite of {@link #sequenceFx}.
- * @return {Object} this
- */
- syncFx: function() {
- Ext.fx.Manager.setFxDefaults(this.id, {
- concurrent: true
- });
- return this;
- },
- /**
- * Ensures that all effects queued after sequenceFx is called on this object are
- * run in sequence. This is the opposite of {@link #syncFx}.
- * @return {Object} this
- */
- sequenceFx: function() {
- Ext.fx.Manager.setFxDefaults(this.id, {
- concurrent: false
- });
- return this;
- },
- /**
- * @deprecated 4.0 Replaced by {@link #getActiveAnimation}
- * @alias Ext.util.Animate#getActiveAnimation
- * @method
- */
- hasActiveFx: Ext.Function.alias(Ext.util.Animate, 'getActiveAnimation'),
- /**
- * Returns the current animation if this object has any effects actively running or queued, else returns false.
- * @return {Ext.fx.Anim/Boolean} Anim if element has active effects, else false
- */
- getActiveAnimation: function() {
- return Ext.fx.Manager.getActiveAnimation(this.id);
- }
- }, function(){
- // Apply Animate mixin manually until Element is defined in the proper 4.x way
- Ext.applyIf(Ext.Element.prototype, this.prototype);
- // We need to call this again so the animation methods get copied over to CE
- Ext.CompositeElementLite.importElementMethods();
- });
- /**
- * @class Ext.state.Provider
- * <p>Abstract base class for state provider implementations. The provider is responsible
- * for setting values and extracting values to/from the underlying storage source. The
- * storage source can vary and the details should be implemented in a subclass. For example
- * a provider could use a server side database or the browser localstorage where supported.</p>
- *
- * <p>This class provides methods for encoding and decoding <b>typed</b> variables including
- * dates and defines the Provider interface. By default these methods put the value and the
- * type information into a delimited string that can be stored. These should be overridden in
- * a subclass if you want to change the format of the encoded value and subsequent decoding.</p>
- */
- Ext.define('Ext.state.Provider', {
- mixins: {
- observable: 'Ext.util.Observable'
- },
-
- /**
- * @cfg {String} prefix A string to prefix to items stored in the underlying state store.
- * Defaults to <tt>'ext-'</tt>
- */
- prefix: 'ext-',
-
- constructor : function(config){
- config = config || {};
- var me = this;
- Ext.apply(me, config);
- /**
- * @event statechange
- * Fires when a state change occurs.
- * @param {Ext.state.Provider} this This state provider
- * @param {String} key The state key which was changed
- * @param {String} value The encoded value for the state
- */
- me.addEvents("statechange");
- me.state = {};
- me.mixins.observable.constructor.call(me);
- },
-
- /**
- * Returns the current value for a key
- * @param {String} name The key name
- * @param {Object} defaultValue A default value to return if the key's value is not found
- * @return {Object} The state data
- */
- get : function(name, defaultValue){
- return typeof this.state[name] == "undefined" ?
- defaultValue : this.state[name];
- },
- /**
- * Clears a value from the state
- * @param {String} name The key name
- */
- clear : function(name){
- var me = this;
- delete me.state[name];
- me.fireEvent("statechange", me, name, null);
- },
- /**
- * Sets the value for a key
- * @param {String} name The key name
- * @param {Object} value The value to set
- */
- set : function(name, value){
- var me = this;
- me.state[name] = value;
- me.fireEvent("statechange", me, name, value);
- },
- /**
- * Decodes a string previously encoded with {@link #encodeValue}.
- * @param {String} value The value to decode
- * @return {Object} The decoded value
- */
- decodeValue : function(value){
- // a -> Array
- // n -> Number
- // d -> Date
- // b -> Boolean
- // s -> String
- // o -> Object
- // -> Empty (null)
- var me = this,
- re = /^(a|n|d|b|s|o|e)\:(.*)$/,
- matches = re.exec(unescape(value)),
- all,
- type,
- value,
- keyValue;
-
- if(!matches || !matches[1]){
- return; // non state
- }
-
- type = matches[1];
- value = matches[2];
- switch (type) {
- case 'e':
- return null;
- case 'n':
- return parseFloat(value);
- case 'd':
- return new Date(Date.parse(value));
- case 'b':
- return (value == '1');
- case 'a':
- all = [];
- if(value != ''){
- Ext.each(value.split('^'), function(val){
- all.push(me.decodeValue(val));
- }, me);
- }
- return all;
- case 'o':
- all = {};
- if(value != ''){
- Ext.each(value.split('^'), function(val){
- keyValue = val.split('=');
- all[keyValue[0]] = me.decodeValue(keyValue[1]);
- }, me);
- }
- return all;
- default:
- return value;
- }
- },
- /**
- * Encodes a value including type information. Decode with {@link #decodeValue}.
- * @param {Object} value The value to encode
- * @return {String} The encoded value
- */
- encodeValue : function(value){
- var flat = '',
- i = 0,
- enc,
- len,
- key;
-
- if (value == null) {
- return 'e:1';
- } else if(typeof value == 'number') {
- enc = 'n:' + value;
- } else if(typeof value == 'boolean') {
- enc = 'b:' + (value ? '1' : '0');
- } else if(Ext.isDate(value)) {
- enc = 'd:' + value.toGMTString();
- } else if(Ext.isArray(value)) {
- for (len = value.length; i < len; i++) {
- flat += this.encodeValue(value[i]);
- if (i != len - 1) {
- flat += '^';
- }
- }
- enc = 'a:' + flat;
- } else if (typeof value == 'object') {
- for (key in value) {
- if (typeof value[key] != 'function' && value[key] !== undefined) {
- flat += key + '=' + this.encodeValue(value[key]) + '^';
- }
- }
- enc = 'o:' + flat.substring(0, flat.length-1);
- } else {
- enc = 's:' + value;
- }
- return escape(enc);
- }
- });
- /**
- * Provides searching of Components within Ext.ComponentManager (globally) or a specific
- * Ext.container.Container on the document with a similar syntax to a CSS selector.
- *
- * Components can be retrieved by using their {@link Ext.Component xtype} with an optional . prefix
- *
- * - `component` or `.component`
- * - `gridpanel` or `.gridpanel`
- *
- * An itemId or id must be prefixed with a #
- *
- * - `#myContainer`
- *
- * Attributes must be wrapped in brackets
- *
- * - `component[autoScroll]`
- * - `panel[title="Test"]`
- *
- * Member expressions from candidate Components may be tested. If the expression returns a *truthy* value,
- * the candidate Component will be included in the query:
- *
- * var disabledFields = myFormPanel.query("{isDisabled()}");
- *
- * Pseudo classes may be used to filter results in the same way as in {@link Ext.DomQuery DomQuery}:
- *
- * // Function receives array and returns a filtered array.
- * Ext.ComponentQuery.pseudos.invalid = function(items) {
- * var i = 0, l = items.length, c, result = [];
- * for (; i < l; i++) {
- * if (!(c = items[i]).isValid()) {
- * result.push(c);
- * }
- * }
- * return result;
- * };
- *
- * var invalidFields = myFormPanel.query('field:invalid');
- * if (invalidFields.length) {
- * invalidFields[0].getEl().scrollIntoView(myFormPanel.body);
- * for (var i = 0, l = invalidFields.length; i < l; i++) {
- * invalidFields[i].getEl().frame("red");
- * }
- * }
- *
- * Default pseudos include:
- *
- * - not
- * - last
- *
- * Queries return an array of components.
- * Here are some example queries.
- *
- * // retrieve all Ext.Panels in the document by xtype
- * var panelsArray = Ext.ComponentQuery.query('panel');
- *
- * // retrieve all Ext.Panels within the container with an id myCt
- * var panelsWithinmyCt = Ext.ComponentQuery.query('#myCt panel');
- *
- * // retrieve all direct children which are Ext.Panels within myCt
- * var directChildPanel = Ext.ComponentQuery.query('#myCt > panel');
- *
- * // retrieve all grids and trees
- * var gridsAndTrees = Ext.ComponentQuery.query('gridpanel, treepanel');
- *
- * For easy access to queries based from a particular Container see the {@link Ext.container.Container#query},
- * {@link Ext.container.Container#down} and {@link Ext.container.Container#child} methods. Also see
- * {@link Ext.Component#up}.
- */
- Ext.define('Ext.ComponentQuery', {
- singleton: true,
- uses: ['Ext.ComponentManager']
- }, function() {
- var cq = this,
- // A function source code pattern with a placeholder which accepts an expression which yields a truth value when applied
- // as a member on each item in the passed array.
- filterFnPattern = [
- 'var r = [],',
- 'i = 0,',
- 'it = items,',
- 'l = it.length,',
- 'c;',
- 'for (; i < l; i++) {',
- 'c = it[i];',
- 'if (c.{0}) {',
- 'r.push(c);',
- '}',
- '}',
- 'return r;'
- ].join(''),
- filterItems = function(items, operation) {
- // Argument list for the operation is [ itemsArray, operationArg1, operationArg2...]
- // The operation's method loops over each item in the candidate array and
- // returns an array of items which match its criteria
- return operation.method.apply(this, [ items ].concat(operation.args));
- },
- getItems = function(items, mode) {
- var result = [],
- i = 0,
- length = items.length,
- candidate,
- deep = mode !== '>';
-
- for (; i < length; i++) {
- candidate = items[i];
- if (candidate.getRefItems) {
- result = result.concat(candidate.getRefItems(deep));
- }
- }
- return result;
- },
- getAncestors = function(items) {
- var result = [],
- i = 0,
- length = items.length,
- candidate;
- for (; i < length; i++) {
- candidate = items[i];
- while (!!(candidate = (candidate.ownerCt || candidate.floatParent))) {
- result.push(candidate);
- }
- }
- return result;
- },
- // Filters the passed candidate array and returns only items which match the passed xtype
- filterByXType = function(items, xtype, shallow) {
- if (xtype === '*') {
- return items.slice();
- }
- else {
- var result = [],
- i = 0,
- length = items.length,
- candidate;
- for (; i < length; i++) {
- candidate = items[i];
- if (candidate.isXType(xtype, shallow)) {
- result.push(candidate);
- }
- }
- return result;
- }
- },
- // Filters the passed candidate array and returns only items which have the passed className
- filterByClassName = function(items, className) {
- var EA = Ext.Array,
- result = [],
- i = 0,
- length = items.length,
- candidate;
- for (; i < length; i++) {
- candidate = items[i];
- if (candidate.el ? candidate.el.hasCls(className) : EA.contains(candidate.initCls(), className)) {
- result.push(candidate);
- }
- }
- return result;
- },
- // Filters the passed candidate array and returns only items which have the specified property match
- filterByAttribute = function(items, property, operator, value) {
- var result = [],
- i = 0,
- length = items.length,
- candidate;
- for (; i < length; i++) {
- candidate = items[i];
- if (!value ? !!candidate[property] : (String(candidate[property]) === value)) {
- result.push(candidate);
- }
- }
- return result;
- },
- // Filters the passed candidate array and returns only items which have the specified itemId or id
- filterById = function(items, id) {
- var result = [],
- i = 0,
- length = items.length,
- candidate;
- for (; i < length; i++) {
- candidate = items[i];
- if (candidate.getItemId() === id) {
- result.push(candidate);
- }
- }
- return result;
- },
- // Filters the passed candidate array and returns only items which the named pseudo class matcher filters in
- filterByPseudo = function(items, name, value) {
- return cq.pseudos[name](items, value);
- },
- // Determines leading mode
- // > for direct child, and ^ to switch to ownerCt axis
- modeRe = /^(\s?([>\^])\s?|\s|$)/,
- // Matches a token with possibly (true|false) appended for the "shallow" parameter
- tokenRe = /^(#)?([\w\-]+|\*)(?:\((true|false)\))?/,
- matchers = [{
- // Checks for .xtype with possibly (true|false) appended for the "shallow" parameter
- re: /^\.([\w\-]+)(?:\((true|false)\))?/,
- method: filterByXType
- },{
- // checks for [attribute=value]
- re: /^(?:[\[](?:@)?([\w\-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]])/,
- method: filterByAttribute
- }, {
- // checks for #cmpItemId
- re: /^#([\w\-]+)/,
- method: filterById
- }, {
- // checks for :<pseudo_class>(<selector>)
- re: /^\:([\w\-]+)(?:\(((?:\{[^\}]+\})|(?:(?!\{)[^\s>\/]*?(?!\})))\))?/,
- method: filterByPseudo
- }, {
- // checks for {<member_expression>}
- re: /^(?:\{([^\}]+)\})/,
- method: filterFnPattern
- }];
- // @class Ext.ComponentQuery.Query
- // This internal class is completely hidden in documentation.
- cq.Query = Ext.extend(Object, {
- constructor: function(cfg) {
- cfg = cfg || {};
- Ext.apply(this, cfg);
- },
- // Executes this Query upon the selected root.
- // The root provides the initial source of candidate Component matches which are progressively
- // filtered by iterating through this Query's operations cache.
- // If no root is provided, all registered Components are searched via the ComponentManager.
- // root may be a Container who's descendant Components are filtered
- // root may be a Component with an implementation of getRefItems which provides some nested Components such as the
- // docked items within a Panel.
- // root may be an array of candidate Components to filter using this Query.
- execute : function(root) {
- var operations = this.operations,
- i = 0,
- length = operations.length,
- operation,
- workingItems;
- // no root, use all Components in the document
- if (!root) {
- workingItems = Ext.ComponentManager.all.getArray();
- }
- // Root is a candidate Array
- else if (Ext.isArray(root)) {
- workingItems = root;
- }
- // We are going to loop over our operations and take care of them
- // one by one.
- for (; i < length; i++) {
- operation = operations[i];
- // The mode operation requires some custom handling.
- // All other operations essentially filter down our current
- // working items, while mode replaces our current working
- // items by getting children from each one of our current
- // working items. The type of mode determines the type of
- // children we get. (e.g. > only gets direct children)
- if (operation.mode === '^') {
- workingItems = getAncestors(workingItems || [root]);
- }
- else if (operation.mode) {
- workingItems = getItems(workingItems || [root], operation.mode);
- }
- else {
- workingItems = filterItems(workingItems || getItems([root]), operation);
- }
- // If this is the last operation, it means our current working
- // items are the final matched items. Thus return them!
- if (i === length -1) {
- return workingItems;
- }
- }
- return [];
- },
- is: function(component) {
- var operations = this.operations,
- components = Ext.isArray(component) ? component : [component],
- originalLength = components.length,
- lastOperation = operations[operations.length-1],
- ln, i;
- components = filterItems(components, lastOperation);
- if (components.length === originalLength) {
- if (operations.length > 1) {
- for (i = 0, ln = components.length; i < ln; i++) {
- if (Ext.Array.indexOf(this.execute(), components[i]) === -1) {
- return false;
- }
- }
- }
- return true;
- }
- return false;
- }
- });
- Ext.apply(this, {
- // private cache of selectors and matching ComponentQuery.Query objects
- cache: {},
- // private cache of pseudo class filter functions
- pseudos: {
- not: function(components, selector){
- var CQ = Ext.ComponentQuery,
- i = 0,
- length = components.length,
- results = [],
- index = -1,
- component;
-
- for(; i < length; ++i) {
- component = components[i];
- if (!CQ.is(component, selector)) {
- results[++index] = component;
- }
- }
- return results;
- },
- last: function(components) {
- return components[components.length - 1];
- }
- },
- /**
- * Returns an array of matched Components from within the passed root object.
- *
- * This method filters returned Components in a similar way to how CSS selector based DOM
- * queries work using a textual selector string.
- *
- * See class summary for details.
- *
- * @param {String} selector The selector string to filter returned Components
- * @param {Ext.container.Container} root The Container within which to perform the query.
- * If omitted, all Components within the document are included in the search.
- *
- * This parameter may also be an array of Components to filter according to the selector.</p>
- * @returns {Ext.Component[]} The matched Components.
- *
- * @member Ext.ComponentQuery
- */
- query: function(selector, root) {
- var selectors = selector.split(','),
- length = selectors.length,
- i = 0,
- results = [],
- noDupResults = [],
- dupMatcher = {},
- query, resultsLn, cmp;
- for (; i < length; i++) {
- selector = Ext.String.trim(selectors[i]);
- query = this.cache[selector];
- if (!query) {
- this.cache[selector] = query = this.parse(selector);
- }
- results = results.concat(query.execute(root));
- }
- // multiple selectors, potential to find duplicates
- // lets filter them out.
- if (length > 1) {
- resultsLn = results.length;
- for (i = 0; i < resultsLn; i++) {
- cmp = results[i];
- if (!dupMatcher[cmp.id]) {
- noDupResults.push(cmp);
- dupMatcher[cmp.id] = true;
- }
- }
- results = noDupResults;
- }
- return results;
- },
- /**
- * Tests whether the passed Component matches the selector string.
- * @param {Ext.Component} component The Component to test
- * @param {String} selector The selector string to test against.
- * @return {Boolean} True if the Component matches the selector.
- * @member Ext.ComponentQuery
- */
- is: function(component, selector) {
- if (!selector) {
- return true;
- }
- var query = this.cache[selector];
- if (!query) {
- this.cache[selector] = query = this.parse(selector);
- }
- return query.is(component);
- },
- parse: function(selector) {
- var operations = [],
- length = matchers.length,
- lastSelector,
- tokenMatch,
- matchedChar,
- modeMatch,
- selectorMatch,
- i, matcher, method;
- // We are going to parse the beginning of the selector over and
- // over again, slicing off the selector any portions we converted into an
- // operation, until it is an empty string.
- while (selector && lastSelector !== selector) {
- lastSelector = selector;
- // First we check if we are dealing with a token like #, * or an xtype
- tokenMatch = selector.match(tokenRe);
- if (tokenMatch) {
- matchedChar = tokenMatch[1];
- // If the token is prefixed with a # we push a filterById operation to our stack
- if (matchedChar === '#') {
- operations.push({
- method: filterById,
- args: [Ext.String.trim(tokenMatch[2])]
- });
- }
- // If the token is prefixed with a . we push a filterByClassName operation to our stack
- // FIXME: Not enabled yet. just needs \. adding to the tokenRe prefix
- else if (matchedChar === '.') {
- operations.push({
- method: filterByClassName,
- args: [Ext.String.trim(tokenMatch[2])]
- });
- }
- // If the token is a * or an xtype string, we push a filterByXType
- // operation to the stack.
- else {
- operations.push({
- method: filterByXType,
- args: [Ext.String.trim(tokenMatch[2]), Boolean(tokenMatch[3])]
- });
- }
- // Now we slice of the part we just converted into an operation
- selector = selector.replace(tokenMatch[0], '');
- }
- // If the next part of the query is not a space or > or ^, it means we
- // are going to check for more things that our current selection
- // has to comply to.
- while (!(modeMatch = selector.match(modeRe))) {
- // Lets loop over each type of matcher and execute it
- // on our current selector.
- for (i = 0; selector && i < length; i++) {
- matcher = matchers[i];
- selectorMatch = selector.match(matcher.re);
- method = matcher.method;
- // If we have a match, add an operation with the method
- // associated with this matcher, and pass the regular
- // expression matches are arguments to the operation.
- if (selectorMatch) {
- operations.push({
- method: Ext.isString(matcher.method)
- // Turn a string method into a function by formatting the string with our selector matche expression
- // A new method is created for different match expressions, eg {id=='textfield-1024'}
- // Every expression may be different in different selectors.
- ? Ext.functionFactory('items', Ext.String.format.apply(Ext.String, [method].concat(selectorMatch.slice(1))))
- : matcher.method,
- args: selectorMatch.slice(1)
- });
- selector = selector.replace(selectorMatch[0], '');
- break; // Break on match
- }
- //<debug>
- // Exhausted all matches: It's an error
- if (i === (length - 1)) {
- Ext.Error.raise('Invalid ComponentQuery selector: "' + arguments[0] + '"');
- }
- //</debug>
- }
- }
- // Now we are going to check for a mode change. This means a space
- // or a > to determine if we are going to select all the children
- // of the currently matched items, or a ^ if we are going to use the
- // ownerCt axis as the candidate source.
- if (modeMatch[1]) { // Assignment, and test for truthiness!
- operations.push({
- mode: modeMatch[2]||modeMatch[1]
- });
- selector = selector.replace(modeMatch[0], '');
- }
- }
- // Now that we have all our operations in an array, we are going
- // to create a new Query using these operations.
- return new cq.Query({
- operations: operations
- });
- }
- });
- });
- /**
- * @class Ext.util.HashMap
- * <p>
- * Represents a collection of a set of key and value pairs. Each key in the HashMap
- * must be unique, the same key cannot exist twice. Access to items is provided via
- * the key only. Sample usage:
- * <pre><code>
- var map = new Ext.util.HashMap();
- map.add('key1', 1);
- map.add('key2', 2);
- map.add('key3', 3);
- map.each(function(key, value, length){
- console.log(key, value, length);
- });
- * </code></pre>
- * </p>
- *
- * <p>The HashMap is an unordered class,
- * there is no guarantee when iterating over the items that they will be in any particular
- * order. If this is required, then use a {@link Ext.util.MixedCollection}.
- * </p>
- */
- Ext.define('Ext.util.HashMap', {
- mixins: {
- observable: 'Ext.util.Observable'
- },
- /**
- * @cfg {Function} keyFn A function that is used to retrieve a default key for a passed object.
- * A default is provided that returns the <b>id</b> property on the object. This function is only used
- * if the add method is called with a single argument.
- */
- /**
- * Creates new HashMap.
- * @param {Object} config (optional) Config object.
- */
- constructor: function(config) {
- config = config || {};
-
- var me = this,
- keyFn = config.keyFn;
- me.addEvents(
- /**
- * @event add
- * Fires when a new item is added to the hash
- * @param {Ext.util.HashMap} this.
- * @param {String} key The key of the added item.
- * @param {Object} value The value of the added item.
- */
- 'add',
- /**
- * @event clear
- * Fires when the hash is cleared.
- * @param {Ext.util.HashMap} this.
- */
- 'clear',
- /**
- * @event remove
- * Fires when an item is removed from the hash.
- * @param {Ext.util.HashMap} this.
- * @param {String} key The key of the removed item.
- * @param {Object} value The value of the removed item.
- */
- 'remove',
- /**
- * @event replace
- * Fires when an item is replaced in the hash.
- * @param {Ext.util.HashMap} this.
- * @param {String} key The key of the replaced item.
- * @param {Object} value The new value for the item.
- * @param {Object} old The old value for the item.
- */
- 'replace'
- );
- me.mixins.observable.constructor.call(me, config);
- me.clear(true);
-
- if (keyFn) {
- me.getKey = keyFn;
- }
- },
- /**
- * Gets the number of items in the hash.
- * @return {Number} The number of items in the hash.
- */
- getCount: function() {
- return this.length;
- },
- /**
- * Implementation for being able to extract the key from an object if only
- * a single argument is passed.
- * @private
- * @param {String} key The key
- * @param {Object} value The value
- * @return {Array} [key, value]
- */
- getData: function(key, value) {
- // if we have no value, it means we need to get the key from the object
- if (value === undefined) {
- value = key;
- key = this.getKey(value);
- }
- return [key, value];
- },
- /**
- * Extracts the key from an object. This is a default implementation, it may be overridden
- * @param {Object} o The object to get the key from
- * @return {String} The key to use.
- */
- getKey: function(o) {
- return o.id;
- },
- /**
- * Adds an item to the collection. Fires the {@link #add} event when complete.
- * @param {String} key <p>The key to associate with the item, or the new item.</p>
- * <p>If a {@link #getKey} implementation was specified for this HashMap,
- * or if the key of the stored items is in a property called <tt><b>id</b></tt>,
- * the HashMap will be able to <i>derive</i> the key for the new item.
- * In this case just pass the new item in this parameter.</p>
- * @param {Object} o The item to add.
- * @return {Object} The item added.
- */
- add: function(key, value) {
- var me = this,
- data;
- if (arguments.length === 1) {
- value = key;
- key = me.getKey(value);
- }
- if (me.containsKey(key)) {
- return me.replace(key, value);
- }
- data = me.getData(key, value);
- key = data[0];
- value = data[1];
- me.map[key] = value;
- ++me.length;
- me.fireEvent('add', me, key, value);
- return value;
- },
- /**
- * Replaces an item in the hash. If the key doesn't exist, the
- * {@link #add} method will be used.
- * @param {String} key The key of the item.
- * @param {Object} value The new value for the item.
- * @return {Object} The new value of the item.
- */
- replace: function(key, value) {
- var me = this,
- map = me.map,
- old;
- if (!me.containsKey(key)) {
- me.add(key, value);
- }
- old = map[key];
- map[key] = value;
- me.fireEvent('replace', me, key, value, old);
- return value;
- },
- /**
- * Remove an item from the hash.
- * @param {Object} o The value of the item to remove.
- * @return {Boolean} True if the item was successfully removed.
- */
- remove: function(o) {
- var key = this.findKey(o);
- if (key !== undefined) {
- return this.removeAtKey(key);
- }
- return false;
- },
- /**
- * Remove an item from the hash.
- * @param {String} key The key to remove.
- * @return {Boolean} True if the item was successfully removed.
- */
- removeAtKey: function(key) {
- var me = this,
- value;
- if (me.containsKey(key)) {
- value = me.map[key];
- delete me.map[key];
- --me.length;
- me.fireEvent('remove', me, key, value);
- return true;
- }
- return false;
- },
- /**
- * Retrieves an item with a particular key.
- * @param {String} key The key to lookup.
- * @return {Object} The value at that key. If it doesn't exist, <tt>undefined</tt> is returned.
- */
- get: function(key) {
- return this.map[key];
- },
- /**
- * Removes all items from the hash.
- * @return {Ext.util.HashMap} this
- */
- clear: function(/* private */ initial) {
- var me = this;
- me.map = {};
- me.length = 0;
- if (initial !== true) {
- me.fireEvent('clear', me);
- }
- return me;
- },
- /**
- * Checks whether a key exists in the hash.
- * @param {String} key The key to check for.
- * @return {Boolean} True if they key exists in the hash.
- */
- containsKey: function(key) {
- return this.map[key] !== undefined;
- },
- /**
- * Checks whether a value exists in the hash.
- * @param {Object} value The value to check for.
- * @return {Boolean} True if the value exists in the dictionary.
- */
- contains: function(value) {
- return this.containsKey(this.findKey(value));
- },
- /**
- * Return all of the keys in the hash.
- * @return {Array} An array of keys.
- */
- getKeys: function() {
- return this.getArray(true);
- },
- /**
- * Return all of the values in the hash.
- * @return {Array} An array of values.
- */
- getValues: function() {
- return this.getArray(false);
- },
- /**
- * Gets either the keys/values in an array from the hash.
- * @private
- * @param {Boolean} isKey True to extract the keys, otherwise, the value
- * @return {Array} An array of either keys/values from the hash.
- */
- getArray: function(isKey) {
- var arr = [],
- key,
- map = this.map;
- for (key in map) {
- if (map.hasOwnProperty(key)) {
- arr.push(isKey ? key: map[key]);
- }
- }
- return arr;
- },
- /**
- * Executes the specified function once for each item in the hash.
- * Returning false from the function will cease iteration.
- *
- * The paramaters passed to the function are:
- * <div class="mdetail-params"><ul>
- * <li><b>key</b> : String<p class="sub-desc">The key of the item</p></li>
- * <li><b>value</b> : Number<p class="sub-desc">The value of the item</p></li>
- * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the hash</p></li>
- * </ul></div>
- * @param {Function} fn The function to execute.
- * @param {Object} scope The scope to execute in. Defaults to <tt>this</tt>.
- * @return {Ext.util.HashMap} this
- */
- each: function(fn, scope) {
- // copy items so they may be removed during iteration.
- var items = Ext.apply({}, this.map),
- key,
- length = this.length;
- scope = scope || this;
- for (key in items) {
- if (items.hasOwnProperty(key)) {
- if (fn.call(scope, key, items[key], length) === false) {
- break;
- }
- }
- }
- return this;
- },
- /**
- * Performs a shallow copy on this hash.
- * @return {Ext.util.HashMap} The new hash object.
- */
- clone: function() {
- var hash = new this.self(),
- map = this.map,
- key;
- hash.suspendEvents();
- for (key in map) {
- if (map.hasOwnProperty(key)) {
- hash.add(key, map[key]);
- }
- }
- hash.resumeEvents();
- return hash;
- },
- /**
- * @private
- * Find the key for a value.
- * @param {Object} value The value to find.
- * @return {Object} The value of the item. Returns <tt>undefined</tt> if not found.
- */
- findKey: function(value) {
- var key,
- map = this.map;
- for (key in map) {
- if (map.hasOwnProperty(key) && map[key] === value) {
- return key;
- }
- }
- return undefined;
- }
- });
- /**
- * @class Ext.state.Manager
- * This is the global state manager. By default all components that are "state aware" check this class
- * for state information if you don't pass them a custom state provider. In order for this class
- * to be useful, it must be initialized with a provider when your application initializes. Example usage:
- <pre><code>
- // in your initialization function
- init : function(){
- Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
- var win = new Window(...);
- win.restoreState();
- }
- </code></pre>
- * This class passes on calls from components to the underlying {@link Ext.state.Provider} so that
- * there is a common interface that can be used without needing to refer to a specific provider instance
- * in every component.
- * @singleton
- * @docauthor Evan Trimboli <evan@sencha.com>
- */
- Ext.define('Ext.state.Manager', {
- singleton: true,
- requires: ['Ext.state.Provider'],
- constructor: function() {
- this.provider = Ext.create('Ext.state.Provider');
- },
-
-
- /**
- * Configures the default state provider for your application
- * @param {Ext.state.Provider} stateProvider The state provider to set
- */
- setProvider : function(stateProvider){
- this.provider = stateProvider;
- },
- /**
- * Returns the current value for a key
- * @param {String} name The key name
- * @param {Object} defaultValue The default value to return if the key lookup does not match
- * @return {Object} The state data
- */
- get : function(key, defaultValue){
- return this.provider.get(key, defaultValue);
- },
- /**
- * Sets the value for a key
- * @param {String} name The key name
- * @param {Object} value The state data
- */
- set : function(key, value){
- this.provider.set(key, value);
- },
- /**
- * Clears a value from the state
- * @param {String} name The key name
- */
- clear : function(key){
- this.provider.clear(key);
- },
- /**
- * Gets the currently configured state provider
- * @return {Ext.state.Provider} The state provider
- */
- getProvider : function(){
- return this.provider;
- }
- });
- /**
- * @class Ext.state.Stateful
- * A mixin for being able to save the state of an object to an underlying
- * {@link Ext.state.Provider}.
- */
- Ext.define('Ext.state.Stateful', {
- /* Begin Definitions */
- mixins: {
- observable: 'Ext.util.Observable'
- },
- requires: ['Ext.state.Manager'],
- /* End Definitions */
- /**
- * @cfg {Boolean} stateful
- * <p>A flag which causes the object to attempt to restore the state of
- * internal properties from a saved state on startup. The object must have
- * a <code>{@link #stateId}</code> for state to be managed.
- * Auto-generated ids are not guaranteed to be stable across page loads and
- * cannot be relied upon to save and restore the same state for a object.<p>
- * <p>For state saving to work, the state manager's provider must have been
- * set to an implementation of {@link Ext.state.Provider} which overrides the
- * {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get}
- * methods to save and recall name/value pairs. A built-in implementation,
- * {@link Ext.state.CookieProvider} is available.</p>
- * <p>To set the state provider for the current page:</p>
- * <pre><code>
- Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
- expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now
- }));
- * </code></pre>
- * <p>A stateful object attempts to save state when one of the events
- * listed in the <code>{@link #stateEvents}</code> configuration fires.</p>
- * <p>To save state, a stateful object first serializes its state by
- * calling <b><code>{@link #getState}</code></b>. By default, this function does
- * nothing. The developer must provide an implementation which returns an
- * object hash which represents the restorable state of the object.</p>
- * <p>The value yielded by getState is passed to {@link Ext.state.Manager#set}
- * which uses the configured {@link Ext.state.Provider} to save the object
- * keyed by the <code>{@link #stateId}</code>.</p>
- * <p>During construction, a stateful object attempts to <i>restore</i>
- * its state by calling {@link Ext.state.Manager#get} passing the
- * <code>{@link #stateId}</code></p>
- * <p>The resulting object is passed to <b><code>{@link #applyState}</code></b>.
- * The default implementation of <code>{@link #applyState}</code> simply copies
- * properties into the object, but a developer may override this to support
- * more behaviour.</p>
- * <p>You can perform extra processing on state save and restore by attaching
- * handlers to the {@link #beforestaterestore}, {@link #staterestore},
- * {@link #beforestatesave} and {@link #statesave} events.</p>
- */
- stateful: true,
- /**
- * @cfg {String} stateId
- * The unique id for this object to use for state management purposes.
- * <p>See {@link #stateful} for an explanation of saving and restoring state.</p>
- */
- /**
- * @cfg {String[]} stateEvents
- * <p>An array of events that, when fired, should trigger this object to
- * save its state. Defaults to none. <code>stateEvents</code> may be any type
- * of event supported by this object, including browser or custom events
- * (e.g., <tt>['click', 'customerchange']</tt>).</p>
- * <p>See <code>{@link #stateful}</code> for an explanation of saving and
- * restoring object state.</p>
- */
- /**
- * @cfg {Number} saveDelay
- * A buffer to be applied if many state events are fired within a short period.
- */
- saveDelay: 100,
- autoGenIdRe: /^((\w+-)|(ext-comp-))\d{4,}$/i,
- constructor: function(config) {
- var me = this;
- config = config || {};
- if (Ext.isDefined(config.stateful)) {
- me.stateful = config.stateful;
- }
- if (Ext.isDefined(config.saveDelay)) {
- me.saveDelay = config.saveDelay;
- }
- me.stateId = me.stateId || config.stateId;
- if (!me.stateEvents) {
- me.stateEvents = [];
- }
- if (config.stateEvents) {
- me.stateEvents.concat(config.stateEvents);
- }
- this.addEvents(
- /**
- * @event beforestaterestore
- * Fires before the state of the object is restored. Return false from an event handler to stop the restore.
- * @param {Ext.state.Stateful} this
- * @param {Object} state The hash of state values returned from the StateProvider. If this
- * event is not vetoed, then the state object is passed to <b><tt>applyState</tt></b>. By default,
- * that simply copies property values into this object. The method maybe overriden to
- * provide custom state restoration.
- */
- 'beforestaterestore',
- /**
- * @event staterestore
- * Fires after the state of the object is restored.
- * @param {Ext.state.Stateful} this
- * @param {Object} state The hash of state values returned from the StateProvider. This is passed
- * to <b><tt>applyState</tt></b>. By default, that simply copies property values into this
- * object. The method maybe overriden to provide custom state restoration.
- */
- 'staterestore',
- /**
- * @event beforestatesave
- * Fires before the state of the object is saved to the configured state provider. Return false to stop the save.
- * @param {Ext.state.Stateful} this
- * @param {Object} state The hash of state values. This is determined by calling
- * <b><tt>getState()</tt></b> on the object. This method must be provided by the
- * developer to return whetever representation of state is required, by default, Ext.state.Stateful
- * has a null implementation.
- */
- 'beforestatesave',
- /**
- * @event statesave
- * Fires after the state of the object is saved to the configured state provider.
- * @param {Ext.state.Stateful} this
- * @param {Object} state The hash of state values. This is determined by calling
- * <b><tt>getState()</tt></b> on the object. This method must be provided by the
- * developer to return whetever representation of state is required, by default, Ext.state.Stateful
- * has a null implementation.
- */
- 'statesave'
- );
- me.mixins.observable.constructor.call(me);
- if (me.stateful !== false) {
- me.initStateEvents();
- me.initState();
- }
- },
- /**
- * Initializes any state events for this object.
- * @private
- */
- initStateEvents: function() {
- this.addStateEvents(this.stateEvents);
- },
- /**
- * Add events that will trigger the state to be saved.
- * @param {String/String[]} events The event name or an array of event names.
- */
- addStateEvents: function(events){
- if (!Ext.isArray(events)) {
- events = [events];
- }
- var me = this,
- i = 0,
- len = events.length;
- for (; i < len; ++i) {
- me.on(events[i], me.onStateChange, me);
- }
- },
- /**
- * This method is called when any of the {@link #stateEvents} are fired.
- * @private
- */
- onStateChange: function(){
- var me = this,
- delay = me.saveDelay;
- if (delay > 0) {
- if (!me.stateTask) {
- me.stateTask = Ext.create('Ext.util.DelayedTask', me.saveState, me);
- }
- me.stateTask.delay(me.saveDelay);
- } else {
- me.saveState();
- }
- },
- /**
- * Saves the state of the object to the persistence store.
- * @private
- */
- saveState: function() {
- var me = this,
- id,
- state;
- if (me.stateful !== false) {
- id = me.getStateId();
- if (id) {
- state = me.getState();
- if (me.fireEvent('beforestatesave', me, state) !== false) {
- Ext.state.Manager.set(id, state);
- me.fireEvent('statesave', me, state);
- }
- }
- }
- },
- /**
- * Gets the current state of the object. By default this function returns null,
- * it should be overridden in subclasses to implement methods for getting the state.
- * @return {Object} The current state
- */
- getState: function(){
- return null;
- },
- /**
- * Applies the state to the object. This should be overridden in subclasses to do
- * more complex state operations. By default it applies the state properties onto
- * the current object.
- * @param {Object} state The state
- */
- applyState: function(state) {
- if (state) {
- Ext.apply(this, state);
- }
- },
- /**
- * Gets the state id for this object.
- * @return {String} The state id, null if not found.
- */
- getStateId: function() {
- var me = this,
- id = me.stateId;
- if (!id) {
- id = me.autoGenIdRe.test(String(me.id)) ? null : me.id;
- }
- return id;
- },
- /**
- * Initializes the state of the object upon construction.
- * @private
- */
- initState: function(){
- var me = this,
- id = me.getStateId(),
- state;
- if (me.stateful !== false) {
- if (id) {
- state = Ext.state.Manager.get(id);
- if (state) {
- state = Ext.apply({}, state);
- if (me.fireEvent('beforestaterestore', me, state) !== false) {
- me.applyState(state);
- me.fireEvent('staterestore', me, state);
- }
- }
- }
- }
- },
- /**
- * Conditionally saves a single property from this object to the given state object.
- * The idea is to only save state which has changed from the initial state so that
- * current software settings do not override future software settings. Only those
- * values that are user-changed state should be saved.
- *
- * @param {String} propName The name of the property to save.
- * @param {Object} state The state object in to which to save the property.
- * @param {String} stateName (optional) The name to use for the property in state.
- * @return {Boolean} True if the property was saved, false if not.
- */
- savePropToState: function (propName, state, stateName) {
- var me = this,
- value = me[propName],
- config = me.initialConfig;
- if (me.hasOwnProperty(propName)) {
- if (!config || config[propName] !== value) {
- if (state) {
- state[stateName || propName] = value;
- }
- return true;
- }
- }
- return false;
- },
- savePropsToState: function (propNames, state) {
- var me = this;
- Ext.each(propNames, function (propName) {
- me.savePropToState(propName, state);
- });
- return state;
- },
- /**
- * Destroys this stateful object.
- */
- destroy: function(){
- var task = this.stateTask;
- if (task) {
- task.cancel();
- }
- this.clearListeners();
- }
- });
- /**
- * Base Manager class
- */
- Ext.define('Ext.AbstractManager', {
- /* Begin Definitions */
- requires: ['Ext.util.HashMap'],
- /* End Definitions */
- typeName: 'type',
- constructor: function(config) {
- Ext.apply(this, config || {});
- /**
- * @property {Ext.util.HashMap} all
- * Contains all of the items currently managed
- */
- this.all = Ext.create('Ext.util.HashMap');
- this.types = {};
- },
- /**
- * Returns an item by id.
- * For additional details see {@link Ext.util.HashMap#get}.
- * @param {String} id The id of the item
- * @return {Object} The item, undefined if not found.
- */
- get : function(id) {
- return this.all.get(id);
- },
- /**
- * Registers an item to be managed
- * @param {Object} item The item to register
- */
- register: function(item) {
- //<debug>
- var all = this.all,
- key = all.getKey(item);
-
- if (all.containsKey(key)) {
- Ext.Error.raise('Registering duplicate id "' + key + '" with this manager');
- }
- //</debug>
- this.all.add(item);
- },
- /**
- * Unregisters an item by removing it from this manager
- * @param {Object} item The item to unregister
- */
- unregister: function(item) {
- this.all.remove(item);
- },
- /**
- * Registers a new item constructor, keyed by a type key.
- * @param {String} type The mnemonic string by which the class may be looked up.
- * @param {Function} cls The new instance class.
- */
- registerType : function(type, cls) {
- this.types[type] = cls;
- cls[this.typeName] = type;
- },
- /**
- * Checks if an item type is registered.
- * @param {String} type The mnemonic string by which the class may be looked up
- * @return {Boolean} Whether the type is registered.
- */
- isRegistered : function(type){
- return this.types[type] !== undefined;
- },
- /**
- * Creates and returns an instance of whatever this manager manages, based on the supplied type and
- * config object.
- * @param {Object} config The config object
- * @param {String} defaultType If no type is discovered in the config object, we fall back to this type
- * @return {Object} The instance of whatever this manager is managing
- */
- create: function(config, defaultType) {
- var type = config[this.typeName] || config.type || defaultType,
- Constructor = this.types[type];
- //<debug>
- if (Constructor === undefined) {
- Ext.Error.raise("The '" + type + "' type has not been registered with this manager");
- }
- //</debug>
- return new Constructor(config);
- },
- /**
- * Registers a function that will be called when an item with the specified id is added to the manager.
- * This will happen on instantiation.
- * @param {String} id The item id
- * @param {Function} fn The callback function. Called with a single parameter, the item.
- * @param {Object} scope The scope (this reference) in which the callback is executed.
- * Defaults to the item.
- */
- onAvailable : function(id, fn, scope){
- var all = this.all,
- item;
-
- if (all.containsKey(id)) {
- item = all.get(id);
- fn.call(scope || item, item);
- } else {
- all.on('add', function(map, key, item){
- if (key == id) {
- fn.call(scope || item, item);
- all.un('add', fn, scope);
- }
- });
- }
- },
-
- /**
- * Executes the specified function once for each item in the collection.
- * @param {Function} fn The function to execute.
- * @param {String} fn.key The key of the item
- * @param {Number} fn.value The value of the item
- * @param {Number} fn.length The total number of items in the collection
- * @param {Boolean} fn.return False to cease iteration.
- * @param {Object} scope The scope to execute in. Defaults to `this`.
- */
- each: function(fn, scope){
- this.all.each(fn, scope || this);
- },
-
- /**
- * Gets the number of items in the collection.
- * @return {Number} The number of items in the collection.
- */
- getCount: function(){
- return this.all.getCount();
- }
- });
- /**
- * @class Ext.ComponentManager
- * @extends Ext.AbstractManager
- * <p>Provides a registry of all Components (instances of {@link Ext.Component} or any subclass
- * thereof) on a page so that they can be easily accessed by {@link Ext.Component component}
- * {@link Ext.Component#id id} (see {@link #get}, or the convenience method {@link Ext#getCmp Ext.getCmp}).</p>
- * <p>This object also provides a registry of available Component <i>classes</i>
- * indexed by a mnemonic code known as the Component's {@link Ext.Component#xtype xtype}.
- * The <code>xtype</code> provides a way to avoid instantiating child Components
- * when creating a full, nested config object for a complete Ext page.</p>
- * <p>A child Component may be specified simply as a <i>config object</i>
- * as long as the correct <code>{@link Ext.Component#xtype xtype}</code> is specified so that if and when the Component
- * needs rendering, the correct type can be looked up for lazy instantiation.</p>
- * <p>For a list of all available <code>{@link Ext.Component#xtype xtypes}</code>, see {@link Ext.Component}.</p>
- * @singleton
- */
- Ext.define('Ext.ComponentManager', {
- extend: 'Ext.AbstractManager',
- alternateClassName: 'Ext.ComponentMgr',
-
- singleton: true,
-
- typeName: 'xtype',
-
- /**
- * Creates a new Component from the specified config object using the
- * config object's xtype to determine the class to instantiate.
- * @param {Object} config A configuration object for the Component you wish to create.
- * @param {Function} defaultType (optional) The constructor to provide the default Component type if
- * the config object does not contain a <code>xtype</code>. (Optional if the config contains a <code>xtype</code>).
- * @return {Ext.Component} The newly instantiated Component.
- */
- create: function(component, defaultType){
- if (component instanceof Ext.AbstractComponent) {
- return component;
- }
- else if (Ext.isString(component)) {
- return Ext.createByAlias('widget.' + component);
- }
- else {
- var type = component.xtype || defaultType,
- config = component;
-
- return Ext.createByAlias('widget.' + type, config);
- }
- },
- registerType: function(type, cls) {
- this.types[type] = cls;
- cls[this.typeName] = type;
- cls.prototype[this.typeName] = type;
- }
- });
- /**
- * An abstract base class which provides shared methods for Components across the Sencha product line.
- *
- * Please refer to sub class's documentation
- * @private
- */
- Ext.define('Ext.AbstractComponent', {
- /* Begin Definitions */
- requires: [
- 'Ext.ComponentQuery',
- 'Ext.ComponentManager'
- ],
- mixins: {
- observable: 'Ext.util.Observable',
- animate: 'Ext.util.Animate',
- state: 'Ext.state.Stateful'
- },
- // The "uses" property specifies class which are used in an instantiated AbstractComponent.
- // They do *not* have to be loaded before this class may be defined - that is what "requires" is for.
- uses: [
- 'Ext.PluginManager',
- 'Ext.ComponentManager',
- 'Ext.Element',
- 'Ext.DomHelper',
- 'Ext.XTemplate',
- 'Ext.ComponentQuery',
- 'Ext.ComponentLoader',
- 'Ext.EventManager',
- 'Ext.layout.Layout',
- 'Ext.layout.component.Auto',
- 'Ext.LoadMask',
- 'Ext.ZIndexManager'
- ],
- statics: {
- AUTO_ID: 1000
- },
- /* End Definitions */
- isComponent: true,
- getAutoId: function() {
- return ++Ext.AbstractComponent.AUTO_ID;
- },
- /**
- * @cfg {String} id
- * The **unique id of this component instance.**
- *
- * It should not be necessary to use this configuration except for singleton objects in your application. Components
- * created with an id may be accessed globally using {@link Ext#getCmp Ext.getCmp}.
- *
- * Instead of using assigned ids, use the {@link #itemId} config, and {@link Ext.ComponentQuery ComponentQuery}
- * which provides selector-based searching for Sencha Components analogous to DOM querying. The {@link
- * Ext.container.Container Container} class contains {@link Ext.container.Container#down shortcut methods} to query
- * its descendant Components by selector.
- *
- * Note that this id will also be used as the element id for the containing HTML element that is rendered to the
- * page for this component. This allows you to write id-based CSS rules to style the specific instance of this
- * component uniquely, and also to select sub-elements using this component's id as the parent.
- *
- * **Note**: to avoid complications imposed by a unique id also see `{@link #itemId}`.
- *
- * **Note**: to access the container of a Component see `{@link #ownerCt}`.
- *
- * Defaults to an {@link #getId auto-assigned id}.
- */
- /**
- * @cfg {String} itemId
- * An itemId can be used as an alternative way to get a reference to a component when no object reference is
- * available. Instead of using an `{@link #id}` with {@link Ext}.{@link Ext#getCmp getCmp}, use `itemId` with
- * {@link Ext.container.Container}.{@link Ext.container.Container#getComponent getComponent} which will retrieve
- * `itemId`'s or {@link #id}'s. Since `itemId`'s are an index to the container's internal MixedCollection, the
- * `itemId` is scoped locally to the container -- avoiding potential conflicts with {@link Ext.ComponentManager}
- * which requires a **unique** `{@link #id}`.
- *
- * var c = new Ext.panel.Panel({ //
- * {@link Ext.Component#height height}: 300,
- * {@link #renderTo}: document.body,
- * {@link Ext.container.Container#layout layout}: 'auto',
- * {@link Ext.container.Container#items items}: [
- * {
- * itemId: 'p1',
- * {@link Ext.panel.Panel#title title}: 'Panel 1',
- * {@link Ext.Component#height height}: 150
- * },
- * {
- * itemId: 'p2',
- * {@link Ext.panel.Panel#title title}: 'Panel 2',
- * {@link Ext.Component#height height}: 150
- * }
- * ]
- * })
- * p1 = c.{@link Ext.container.Container#getComponent getComponent}('p1'); // not the same as {@link Ext#getCmp Ext.getCmp()}
- * p2 = p1.{@link #ownerCt}.{@link Ext.container.Container#getComponent getComponent}('p2'); // reference via a sibling
- *
- * Also see {@link #id}, `{@link Ext.container.Container#query}`, `{@link Ext.container.Container#down}` and
- * `{@link Ext.container.Container#child}`.
- *
- * **Note**: to access the container of an item see {@link #ownerCt}.
- */
- /**
- * @property {Ext.Container} ownerCt
- * This Component's owner {@link Ext.container.Container Container} (is set automatically
- * when this Component is added to a Container). Read-only.
- *
- * **Note**: to access items within the Container see {@link #itemId}.
- */
- /**
- * @property {Boolean} layoutManagedWidth
- * @private
- * Flag set by the container layout to which this Component is added.
- * If the layout manages this Component's width, it sets the value to 1.
- * If it does NOT manage the width, it sets it to 2.
- * If the layout MAY affect the width, but only if the owning Container has a fixed width, this is set to 0.
- */
- /**
- * @property {Boolean} layoutManagedHeight
- * @private
- * Flag set by the container layout to which this Component is added.
- * If the layout manages this Component's height, it sets the value to 1.
- * If it does NOT manage the height, it sets it to 2.
- * If the layout MAY affect the height, but only if the owning Container has a fixed height, this is set to 0.
- */
- /**
- * @cfg {String/Object} autoEl
- * A tag name or {@link Ext.DomHelper DomHelper} spec used to create the {@link #getEl Element} which will
- * encapsulate this Component.
- *
- * You do not normally need to specify this. For the base classes {@link Ext.Component} and
- * {@link Ext.container.Container}, this defaults to **'div'**. The more complex Sencha classes use a more
- * complex DOM structure specified by their own {@link #renderTpl}s.
- *
- * This is intended to allow the developer to create application-specific utility Components encapsulated by
- * different DOM elements. Example usage:
- *
- * {
- * xtype: 'component',
- * autoEl: {
- * tag: 'img',
- * src: 'http://www.example.com/example.jpg'
- * }
- * }, {
- * xtype: 'component',
- * autoEl: {
- * tag: 'blockquote',
- * html: 'autoEl is cool!'
- * }
- * }, {
- * xtype: 'container',
- * autoEl: 'ul',
- * cls: 'ux-unordered-list',
- * items: {
- * xtype: 'component',
- * autoEl: 'li',
- * html: 'First list item'
- * }
- * }
- */
- /**
- * @cfg {Ext.XTemplate/String/String[]} renderTpl
- * An {@link Ext.XTemplate XTemplate} used to create the internal structure inside this Component's encapsulating
- * {@link #getEl Element}.
- *
- * You do not normally need to specify this. For the base classes {@link Ext.Component} and
- * {@link Ext.container.Container}, this defaults to **`null`** which means that they will be initially rendered
- * with no internal structure; they render their {@link #getEl Element} empty. The more specialized ExtJS and Touch
- * classes which use a more complex DOM structure, provide their own template definitions.
- *
- * This is intended to allow the developer to create application-specific utility Components with customized
- * internal structure.
- *
- * Upon rendering, any created child elements may be automatically imported into object properties using the
- * {@link #renderSelectors} and {@link #childEls} options.
- */
- renderTpl: null,
- /**
- * @cfg {Object} renderData
- *
- * The data used by {@link #renderTpl} in addition to the following property values of the component:
- *
- * - id
- * - ui
- * - uiCls
- * - baseCls
- * - componentCls
- * - frame
- *
- * See {@link #renderSelectors} and {@link #childEls} for usage examples.
- */
- /**
- * @cfg {Object} renderSelectors
- * An object containing properties specifying {@link Ext.DomQuery DomQuery} selectors which identify child elements
- * created by the render process.
- *
- * After the Component's internal structure is rendered according to the {@link #renderTpl}, this object is iterated through,
- * and the found Elements are added as properties to the Component using the `renderSelector` property name.
- *
- * For example, a Component which renderes a title and description into its element:
- *
- * Ext.create('Ext.Component', {
- * renderTo: Ext.getBody(),
- * renderTpl: [
- * '<h1 class="title">{title}</h1>',
- * '<p>{desc}</p>'
- * ],
- * renderData: {
- * title: "Error",
- * desc: "Something went wrong"
- * },
- * renderSelectors: {
- * titleEl: 'h1.title',
- * descEl: 'p'
- * },
- * listeners: {
- * afterrender: function(cmp){
- * // After rendering the component will have a titleEl and descEl properties
- * cmp.titleEl.setStyle({color: "red"});
- * }
- * }
- * });
- *
- * For a faster, but less flexible, alternative that achieves the same end result (properties for child elements on the
- * Component after render), see {@link #childEls} and {@link #addChildEls}.
- */
- /**
- * @cfg {Object[]} childEls
- * An array describing the child elements of the Component. Each member of the array
- * is an object with these properties:
- *
- * - `name` - The property name on the Component for the child element.
- * - `itemId` - The id to combine with the Component's id that is the id of the child element.
- * - `id` - The id of the child element.
- *
- * If the array member is a string, it is equivalent to `{ name: m, itemId: m }`.
- *
- * For example, a Component which renders a title and body text:
- *
- * Ext.create('Ext.Component', {
- * renderTo: Ext.getBody(),
- * renderTpl: [
- * '<h1 id="{id}-title">{title}</h1>',
- * '<p>{msg}</p>',
- * ],
- * renderData: {
- * title: "Error",
- * msg: "Something went wrong"
- * },
- * childEls: ["title"],
- * listeners: {
- * afterrender: function(cmp){
- * // After rendering the component will have a title property
- * cmp.title.setStyle({color: "red"});
- * }
- * }
- * });
- *
- * A more flexible, but somewhat slower, approach is {@link #renderSelectors}.
- */
- /**
- * @cfg {String/HTMLElement/Ext.Element} renderTo
- * Specify the id of the element, a DOM element or an existing Element that this component will be rendered into.
- *
- * **Notes:**
- *
- * Do *not* use this option if the Component is to be a child item of a {@link Ext.container.Container Container}.
- * It is the responsibility of the {@link Ext.container.Container Container}'s
- * {@link Ext.container.Container#layout layout manager} to render and manage its child items.
- *
- * When using this config, a call to render() is not required.
- *
- * See `{@link #render}` also.
- */
- /**
- * @cfg {Boolean} frame
- * Specify as `true` to have the Component inject framing elements within the Component at render time to provide a
- * graphical rounded frame around the Component content.
- *
- * This is only necessary when running on outdated, or non standard-compliant browsers such as Microsoft's Internet
- * Explorer prior to version 9 which do not support rounded corners natively.
- *
- * The extra space taken up by this framing is available from the read only property {@link #frameSize}.
- */
- /**
- * @property {Object} frameSize
- * Read-only property indicating the width of any framing elements which were added within the encapsulating element
- * to provide graphical, rounded borders. See the {@link #frame} config.
- *
- * This is an object containing the frame width in pixels for all four sides of the Component containing the
- * following properties:
- *
- * @property {Number} frameSize.top The width of the top framing element in pixels.
- * @property {Number} frameSize.right The width of the right framing element in pixels.
- * @property {Number} frameSize.bottom The width of the bottom framing element in pixels.
- * @property {Number} frameSize.left The width of the left framing element in pixels.
- */
- /**
- * @cfg {String/Object} componentLayout
- * The sizing and positioning of a Component's internal Elements is the responsibility of the Component's layout
- * manager which sizes a Component's internal structure in response to the Component being sized.
- *
- * Generally, developers will not use this configuration as all provided Components which need their internal
- * elements sizing (Such as {@link Ext.form.field.Base input fields}) come with their own componentLayout managers.
- *
- * The {@link Ext.layout.container.Auto default layout manager} will be used on instances of the base Ext.Component
- * class which simply sizes the Component's encapsulating element to the height and width specified in the
- * {@link #setSize} method.
- */
- /**
- * @cfg {Ext.XTemplate/Ext.Template/String/String[]} tpl
- * An {@link Ext.Template}, {@link Ext.XTemplate} or an array of strings to form an Ext.XTemplate. Used in
- * conjunction with the `{@link #data}` and `{@link #tplWriteMode}` configurations.
- */
- /**
- * @cfg {Object} data
- * The initial set of data to apply to the `{@link #tpl}` to update the content area of the Component.
- */
- /**
- * @cfg {String} xtype
- * The `xtype` configuration option can be used to optimize Component creation and rendering. It serves as a
- * shortcut to the full componet name. For example, the component `Ext.button.Button` has an xtype of `button`.
- *
- * You can define your own xtype on a custom {@link Ext.Component component} by specifying the
- * {@link Ext.Class#alias alias} config option with a prefix of `widget`. For example:
- *
- * Ext.define('PressMeButton', {
- * extend: 'Ext.button.Button',
- * alias: 'widget.pressmebutton',
- * text: 'Press Me'
- * })
- *
- * Any Component can be created implicitly as an object config with an xtype specified, allowing it to be
- * declared and passed into the rendering pipeline without actually being instantiated as an object. Not only is
- * rendering deferred, but the actual creation of the object itself is also deferred, saving memory and resources
- * until they are actually needed. In complex, nested layouts containing many Components, this can make a
- * noticeable improvement in performance.
- *
- * // Explicit creation of contained Components:
- * var panel = new Ext.Panel({
- * ...
- * items: [
- * Ext.create('Ext.button.Button', {
- * text: 'OK'
- * })
- * ]
- * };
- *
- * // Implicit creation using xtype:
- * var panel = new Ext.Panel({
- * ...
- * items: [{
- * xtype: 'button',
- * text: 'OK'
- * }]
- * };
- *
- * In the first example, the button will always be created immediately during the panel's initialization. With
- * many added Components, this approach could potentially slow the rendering of the page. In the second example,
- * the button will not be created or rendered until the panel is actually displayed in the browser. If the panel
- * is never displayed (for example, if it is a tab that remains hidden) then the button will never be created and
- * will never consume any resources whatsoever.
- */
- /**
- * @cfg {String} tplWriteMode
- * The Ext.(X)Template method to use when updating the content area of the Component.
- * See `{@link Ext.XTemplate#overwrite}` for information on default mode.
- */
- tplWriteMode: 'overwrite',
- /**
- * @cfg {String} [baseCls='x-component']
- * The base CSS class to apply to this components's element. This will also be prepended to elements within this
- * component like Panel's body will get a class x-panel-body. This means that if you create a subclass of Panel, and
- * you want it to get all the Panels styling for the element and the body, you leave the baseCls x-panel and use
- * componentCls to add specific styling for this component.
- */
- baseCls: Ext.baseCSSPrefix + 'component',
- /**
- * @cfg {String} componentCls
- * CSS Class to be added to a components root level element to give distinction to it via styling.
- */
- /**
- * @cfg {String} [cls='']
- * An optional extra CSS class that will be added to this component's Element. This can be useful
- * for adding customized styles to the component or any of its children using standard CSS rules.
- */
- /**
- * @cfg {String} [overCls='']
- * An optional extra CSS class that will be added to this component's Element when the mouse moves over the Element,
- * and removed when the mouse moves out. This can be useful for adding customized 'active' or 'hover' styles to the
- * component or any of its children using standard CSS rules.
- */
- /**
- * @cfg {String} [disabledCls='x-item-disabled']
- * CSS class to add when the Component is disabled. Defaults to 'x-item-disabled'.
- */
- disabledCls: Ext.baseCSSPrefix + 'item-disabled',
- /**
- * @cfg {String/String[]} ui
- * A set style for a component. Can be a string or an Array of multiple strings (UIs)
- */
- ui: 'default',
- /**
- * @cfg {String[]} uiCls
- * An array of of classNames which are currently applied to this component
- * @private
- */
- uiCls: [],
- /**
- * @cfg {String} style
- * A custom style specification to be applied to this component's Element. Should be a valid argument to
- * {@link Ext.Element#applyStyles}.
- *
- * new Ext.panel.Panel({
- * title: 'Some Title',
- * renderTo: Ext.getBody(),
- * width: 400, height: 300,
- * layout: 'form',
- * items: [{
- * xtype: 'textarea',
- * style: {
- * width: '95%',
- * marginBottom: '10px'
- * }
- * },
- * new Ext.button.Button({
- * text: 'Send',
- * minWidth: '100',
- * style: {
- * marginBottom: '10px'
- * }
- * })
- * ]
- * });
- */
- /**
- * @cfg {Number} width
- * The width of this component in pixels.
- */
- /**
- * @cfg {Number} height
- * The height of this component in pixels.
- */
- /**
- * @cfg {Number/String} border
- * Specifies the border for this component. The border can be a single numeric value to apply to all sides or it can
- * be a CSS style specification for each style, for example: '10 5 3 10'.
- */
- /**
- * @cfg {Number/String} padding
- * Specifies the padding for this component. The padding can be a single numeric value to apply to all sides or it
- * can be a CSS style specification for each style, for example: '10 5 3 10'.
- */
- /**
- * @cfg {Number/String} margin
- * Specifies the margin for this component. The margin can be a single numeric value to apply to all sides or it can
- * be a CSS style specification for each style, for example: '10 5 3 10'.
- */
- /**
- * @cfg {Boolean} hidden
- * True to hide the component.
- */
- hidden: false,
- /**
- * @cfg {Boolean} disabled
- * True to disable the component.
- */
- disabled: false,
- /**
- * @cfg {Boolean} [draggable=false]
- * Allows the component to be dragged.
- */
- /**
- * @property {Boolean} draggable
- * Read-only property indicating whether or not the component can be dragged
- */
- draggable: false,
- /**
- * @cfg {Boolean} floating
- * Create the Component as a floating and use absolute positioning.
- *
- * The z-index of floating Components is handled by a ZIndexManager. If you simply render a floating Component into the DOM, it will be managed
- * by the global {@link Ext.WindowManager WindowManager}.
- *
- * If you include a floating Component as a child item of a Container, then upon render, ExtJS will seek an ancestor floating Component to house a new
- * ZIndexManager instance to manage its descendant floaters. If no floating ancestor can be found, the global WindowManager will be used.
- *
- * When a floating Component which has a ZindexManager managing descendant floaters is destroyed, those descendant floaters will also be destroyed.
- */
- floating: false,
- /**
- * @cfg {String} hideMode
- * A String which specifies how this Component's encapsulating DOM element will be hidden. Values may be:
- *
- * - `'display'` : The Component will be hidden using the `display: none` style.
- * - `'visibility'` : The Component will be hidden using the `visibility: hidden` style.
- * - `'offsets'` : The Component will be hidden by absolutely positioning it out of the visible area of the document.
- * This is useful when a hidden Component must maintain measurable dimensions. Hiding using `display` results in a
- * Component having zero dimensions.
- */
- hideMode: 'display',
- /**
- * @cfg {String} contentEl
- * Specify an existing HTML element, or the `id` of an existing HTML element to use as the content for this component.
- *
- * This config option is used to take an existing HTML element and place it in the layout element of a new component
- * (it simply moves the specified DOM element _after the Component is rendered_ to use as the content.
- *
- * **Notes:**
- *
- * The specified HTML element is appended to the layout element of the component _after any configured
- * {@link #html HTML} has been inserted_, and so the document will not contain this element at the time
- * the {@link #render} event is fired.
- *
- * The specified HTML element used will not participate in any **`{@link Ext.container.Container#layout layout}`**
- * scheme that the Component may use. It is just HTML. Layouts operate on child
- * **`{@link Ext.container.Container#items items}`**.
- *
- * Add either the `x-hidden` or the `x-hide-display` CSS class to prevent a brief flicker of the content before it
- * is rendered to the panel.
- */
- /**
- * @cfg {String/Object} [html='']
- * An HTML fragment, or a {@link Ext.DomHelper DomHelper} specification to use as the layout element content.
- * The HTML content is added after the component is rendered, so the document will not contain this HTML at the time
- * the {@link #render} event is fired. This content is inserted into the body _before_ any configured {@link #contentEl}
- * is appended.
- */
- /**
- * @cfg {Boolean} styleHtmlContent
- * True to automatically style the html inside the content target of this component (body for panels).
- */
- styleHtmlContent: false,
- /**
- * @cfg {String} [styleHtmlCls='x-html']
- * The class that is added to the content target when you set styleHtmlContent to true.
- */
- styleHtmlCls: Ext.baseCSSPrefix + 'html',
- /**
- * @cfg {Number} minHeight
- * The minimum value in pixels which this Component will set its height to.
- *
- * **Warning:** This will override any size management applied by layout managers.
- */
- /**
- * @cfg {Number} minWidth
- * The minimum value in pixels which this Component will set its width to.
- *
- * **Warning:** This will override any size management applied by layout managers.
- */
- /**
- * @cfg {Number} maxHeight
- * The maximum value in pixels which this Component will set its height to.
- *
- * **Warning:** This will override any size management applied by layout managers.
- */
- /**
- * @cfg {Number} maxWidth
- * The maximum value in pixels which this Component will set its width to.
- *
- * **Warning:** This will override any size management applied by layout managers.
- */
- /**
- * @cfg {Ext.ComponentLoader/Object} loader
- * A configuration object or an instance of a {@link Ext.ComponentLoader} to load remote content for this Component.
- */
- /**
- * @cfg {Boolean} autoShow
- * True to automatically show the component upon creation. This config option may only be used for
- * {@link #floating} components or components that use {@link #autoRender}. Defaults to false.
- */
- autoShow: false,
- /**
- * @cfg {Boolean/String/HTMLElement/Ext.Element} autoRender
- * This config is intended mainly for non-{@link #floating} Components which may or may not be shown. Instead of using
- * {@link #renderTo} in the configuration, and rendering upon construction, this allows a Component to render itself
- * upon first _{@link #show}_. If {@link #floating} is true, the value of this config is omited as if it is `true`.
- *
- * Specify as `true` to have this Component render to the document body upon first show.
- *
- * Specify as an element, or the ID of an element to have this Component render to a specific element upon first
- * show.
- *
- * **This defaults to `true` for the {@link Ext.window.Window Window} class.**
- */
- autoRender: false,
- needsLayout: false,
- // @private
- allowDomMove: true,
- /**
- * @cfg {Object/Object[]} plugins
- * An object or array of objects that will provide custom functionality for this component. The only requirement for
- * a valid plugin is that it contain an init method that accepts a reference of type Ext.Component. When a component
- * is created, if any plugins are available, the component will call the init method on each plugin, passing a
- * reference to itself. Each plugin can then call methods or respond to events on the component as needed to provide
- * its functionality.
- */
- /**
- * @property {Boolean} rendered
- * Read-only property indicating whether or not the component has been rendered.
- */
- rendered: false,
- /**
- * @property {Number} componentLayoutCounter
- * @private
- * The number of component layout calls made on this object.
- */
- componentLayoutCounter: 0,
- weight: 0,
- trimRe: /^\s+|\s+$/g,
- spacesRe: /\s+/,
- /**
- * @property {Boolean} maskOnDisable
- * This is an internal flag that you use when creating custom components. By default this is set to true which means
- * that every component gets a mask when its disabled. Components like FieldContainer, FieldSet, Field, Button, Tab
- * override this property to false since they want to implement custom disable logic.
- */
- maskOnDisable: true,
- /**
- * Creates new Component.
- * @param {Object} config (optional) Config object.
- */
- constructor : function(config) {
- var me = this,
- i, len;
- config = config || {};
- me.initialConfig = config;
- Ext.apply(me, config);
- me.addEvents(
- /**
- * @event beforeactivate
- * Fires before a Component has been visually activated. Returning false from an event listener can prevent
- * the activate from occurring.
- * @param {Ext.Component} this
- */
- 'beforeactivate',
- /**
- * @event activate
- * Fires after a Component has been visually activated.
- * @param {Ext.Component} this
- */
- 'activate',
- /**
- * @event beforedeactivate
- * Fires before a Component has been visually deactivated. Returning false from an event listener can
- * prevent the deactivate from occurring.
- * @param {Ext.Component} this
- */
- 'beforedeactivate',
- /**
- * @event deactivate
- * Fires after a Component has been visually deactivated.
- * @param {Ext.Component} this
- */
- 'deactivate',
- /**
- * @event added
- * Fires after a Component had been added to a Container.
- * @param {Ext.Component} this
- * @param {Ext.container.Container} container Parent Container
- * @param {Number} pos position of Component
- */
- 'added',
- /**
- * @event disable
- * Fires after the component is disabled.
- * @param {Ext.Component} this
- */
- 'disable',
- /**
- * @event enable
- * Fires after the component is enabled.
- * @param {Ext.Component} this
- */
- 'enable',
- /**
- * @event beforeshow
- * Fires before the component is shown when calling the {@link #show} method. Return false from an event
- * handler to stop the show.
- * @param {Ext.Component} this
- */
- 'beforeshow',
- /**
- * @event show
- * Fires after the component is shown when calling the {@link #show} method.
- * @param {Ext.Component} this
- */
- 'show',
- /**
- * @event beforehide
- * Fires before the component is hidden when calling the {@link #hide} method. Return false from an event
- * handler to stop the hide.
- * @param {Ext.Component} this
- */
- 'beforehide',
- /**
- * @event hide
- * Fires after the component is hidden. Fires after the component is hidden when calling the {@link #hide}
- * method.
- * @param {Ext.Component} this
- */
- 'hide',
- /**
- * @event removed
- * Fires when a component is removed from an Ext.container.Container
- * @param {Ext.Component} this
- * @param {Ext.container.Container} ownerCt Container which holds the component
- */
- 'removed',
- /**
- * @event beforerender
- * Fires before the component is {@link #rendered}. Return false from an event handler to stop the
- * {@link #render}.
- * @param {Ext.Component} this
- */
- 'beforerender',
- /**
- * @event render
- * Fires after the component markup is {@link #rendered}.
- * @param {Ext.Component} this
- */
- 'render',
- /**
- * @event afterrender
- * Fires after the component rendering is finished.
- *
- * The afterrender event is fired after this Component has been {@link #rendered}, been postprocesed by any
- * afterRender method defined for the Component.
- * @param {Ext.Component} this
- */
- 'afterrender',
- /**
- * @event beforedestroy
- * Fires before the component is {@link #destroy}ed. Return false from an event handler to stop the
- * {@link #destroy}.
- * @param {Ext.Component} this
- */
- 'beforedestroy',
- /**
- * @event destroy
- * Fires after the component is {@link #destroy}ed.
- * @param {Ext.Component} this
- */
- 'destroy',
- /**
- * @event resize
- * Fires after the component is resized.
- * @param {Ext.Component} this
- * @param {Number} adjWidth The box-adjusted width that was set
- * @param {Number} adjHeight The box-adjusted height that was set
- */
- 'resize',
- /**
- * @event move
- * Fires after the component is moved.
- * @param {Ext.Component} this
- * @param {Number} x The new x position
- * @param {Number} y The new y position
- */
- 'move'
- );
- me.getId();
- me.mons = [];
- me.additionalCls = [];
- me.renderData = me.renderData || {};
- me.renderSelectors = me.renderSelectors || {};
- if (me.plugins) {
- me.plugins = [].concat(me.plugins);
- me.constructPlugins();
- }
- me.initComponent();
- // ititComponent gets a chance to change the id property before registering
- Ext.ComponentManager.register(me);
- // Dont pass the config so that it is not applied to 'this' again
- me.mixins.observable.constructor.call(me);
- me.mixins.state.constructor.call(me, config);
- // Save state on resize.
- this.addStateEvents('resize');
- // Move this into Observable?
- if (me.plugins) {
- me.plugins = [].concat(me.plugins);
- for (i = 0, len = me.plugins.length; i < len; i++) {
- me.plugins[i] = me.initPlugin(me.plugins[i]);
- }
- }
- me.loader = me.getLoader();
- if (me.renderTo) {
- me.render(me.renderTo);
- // EXTJSIV-1935 - should be a way to do afterShow or something, but that
- // won't work. Likewise, rendering hidden and then showing (w/autoShow) has
- // implications to afterRender so we cannot do that.
- }
- if (me.autoShow) {
- me.show();
- }
- //<debug>
- if (Ext.isDefined(me.disabledClass)) {
- if (Ext.isDefined(Ext.global.console)) {
- Ext.global.console.warn('Ext.Component: disabledClass has been deprecated. Please use disabledCls.');
- }
- me.disabledCls = me.disabledClass;
- delete me.disabledClass;
- }
- //</debug>
- },
- initComponent: function () {
- // This is called again here to allow derived classes to add plugin configs to the
- // plugins array before calling down to this, the base initComponent.
- this.constructPlugins();
- },
- /**
- * The supplied default state gathering method for the AbstractComponent class.
- *
- * This method returns dimension settings such as `flex`, `anchor`, `width` and `height` along with `collapsed`
- * state.
- *
- * Subclasses which implement more complex state should call the superclass's implementation, and apply their state
- * to the result if this basic state is to be saved.
- *
- * Note that Component state will only be saved if the Component has a {@link #stateId} and there as a StateProvider
- * configured for the document.
- *
- * @return {Object}
- */
- getState: function() {
- var me = this,
- layout = me.ownerCt ? (me.shadowOwnerCt || me.ownerCt).getLayout() : null,
- state = {
- collapsed: me.collapsed
- },
- width = me.width,
- height = me.height,
- cm = me.collapseMemento,
- anchors;
- // If a Panel-local collapse has taken place, use remembered values as the dimensions.
- // TODO: remove this coupling with Panel's privates! All collapse/expand logic should be refactored into one place.
- if (me.collapsed && cm) {
- if (Ext.isDefined(cm.data.width)) {
- width = cm.width;
- }
- if (Ext.isDefined(cm.data.height)) {
- height = cm.height;
- }
- }
- // If we have flex, only store the perpendicular dimension.
- if (layout && me.flex) {
- state.flex = me.flex;
- if (layout.perpendicularPrefix) {
- state[layout.perpendicularPrefix] = me['get' + layout.perpendicularPrefixCap]();
- } else {
- //<debug>
- if (Ext.isDefined(Ext.global.console)) {
- Ext.global.console.warn('Ext.Component: Specified a flex value on a component not inside a Box layout');
- }
- //</debug>
- }
- }
- // If we have anchor, only store dimensions which are *not* being anchored
- else if (layout && me.anchor) {
- state.anchor = me.anchor;
- anchors = me.anchor.split(' ').concat(null);
- if (!anchors[0]) {
- if (me.width) {
- state.width = width;
- }
- }
- if (!anchors[1]) {
- if (me.height) {
- state.height = height;
- }
- }
- }
- // Store dimensions.
- else {
- if (me.width) {
- state.width = width;
- }
- if (me.height) {
- state.height = height;
- }
- }
- // Don't save dimensions if they are unchanged from the original configuration.
- if (state.width == me.initialConfig.width) {
- delete state.width;
- }
- if (state.height == me.initialConfig.height) {
- delete state.height;
- }
- // If a Box layout was managing the perpendicular dimension, don't save that dimension
- if (layout && layout.align && (layout.align.indexOf('stretch') !== -1)) {
- delete state[layout.perpendicularPrefix];
- }
- return state;
- },
- show: Ext.emptyFn,
- animate: function(animObj) {
- var me = this,
- to;
- animObj = animObj || {};
- to = animObj.to || {};
- if (Ext.fx.Manager.hasFxBlock(me.id)) {
- return me;
- }
- // Special processing for animating Component dimensions.
- if (!animObj.dynamic && (to.height || to.width)) {
- var curWidth = me.getWidth(),
- w = curWidth,
- curHeight = me.getHeight(),
- h = curHeight,
- needsResize = false;
- if (to.height && to.height > curHeight) {
- h = to.height;
- needsResize = true;
- }
- if (to.width && to.width > curWidth) {
- w = to.width;
- needsResize = true;
- }
- // If any dimensions are being increased, we must resize the internal structure
- // of the Component, but then clip it by sizing its encapsulating element back to original dimensions.
- // The animation will then progressively reveal the larger content.
- if (needsResize) {
- var clearWidth = !Ext.isNumber(me.width),
- clearHeight = !Ext.isNumber(me.height);
- me.componentLayout.childrenChanged = true;
- me.setSize(w, h, me.ownerCt);
- me.el.setSize(curWidth, curHeight);
- if (clearWidth) {
- delete me.width;
- }
- if (clearHeight) {
- delete me.height;
- }
- }
- }
- return me.mixins.animate.animate.apply(me, arguments);
- },
- /**
- * This method finds the topmost active layout who's processing will eventually determine the size and position of
- * this Component.
- *
- * This method is useful when dynamically adding Components into Containers, and some processing must take place
- * after the final sizing and positioning of the Component has been performed.
- *
- * @return {Ext.Component}
- */
- findLayoutController: function() {
- return this.findParentBy(function(c) {
- // Return true if we are at the root of the Container tree
- // or this Container's layout is busy but the next one up is not.
- return !c.ownerCt || (c.layout.layoutBusy && !c.ownerCt.layout.layoutBusy);
- });
- },
- onShow : function() {
- // Layout if needed
- var needsLayout = this.needsLayout;
- if (Ext.isObject(needsLayout)) {
- this.doComponentLayout(needsLayout.width, needsLayout.height, needsLayout.isSetSize, needsLayout.ownerCt);
- }
- },
- constructPlugin: function(plugin) {
- if (plugin.ptype && typeof plugin.init != 'function') {
- plugin.cmp = this;
- plugin = Ext.PluginManager.create(plugin);
- }
- else if (typeof plugin == 'string') {
- plugin = Ext.PluginManager.create({
- ptype: plugin,
- cmp: this
- });
- }
- return plugin;
- },
- /**
- * Ensures that the plugins array contains fully constructed plugin instances. This converts any configs into their
- * appropriate instances.
- */
- constructPlugins: function() {
- var me = this,
- plugins = me.plugins,
- i, len;
- if (plugins) {
- for (i = 0, len = plugins.length; i < len; i++) {
- // this just returns already-constructed plugin instances...
- plugins[i] = me.constructPlugin(plugins[i]);
- }
- }
- },
- // @private
- initPlugin : function(plugin) {
- plugin.init(this);
- return plugin;
- },
- /**
- * Handles autoRender. Floating Components may have an ownerCt. If they are asking to be constrained, constrain them
- * within that ownerCt, and have their z-index managed locally. Floating Components are always rendered to
- * document.body
- */
- doAutoRender: function() {
- var me = this;
- if (me.floating) {
- me.render(document.body);
- } else {
- me.render(Ext.isBoolean(me.autoRender) ? Ext.getBody() : me.autoRender);
- }
- },
- // @private
- render : function(container, position) {
- var me = this;
- if (!me.rendered && me.fireEvent('beforerender', me) !== false) {
- // Flag set during the render process.
- // It can be used to inhibit event-driven layout calls during the render phase
- me.rendering = true;
- // If this.el is defined, we want to make sure we are dealing with
- // an Ext Element.
- if (me.el) {
- me.el = Ext.get(me.el);
- }
- // Perform render-time processing for floating Components
- if (me.floating) {
- me.onFloatRender();
- }
- container = me.initContainer(container);
- me.onRender(container, position);
- // Tell the encapsulating element to hide itself in the way the Component is configured to hide
- // This means DISPLAY, VISIBILITY or OFFSETS.
- me.el.setVisibilityMode(Ext.Element[me.hideMode.toUpperCase()]);
- if (me.overCls) {
- me.el.hover(me.addOverCls, me.removeOverCls, me);
- }
- me.fireEvent('render', me);
- me.initContent();
- me.afterRender(container);
- me.fireEvent('afterrender', me);
- me.initEvents();
- if (me.hidden) {
- // Hiding during the render process should not perform any ancillary
- // actions that the full hide process does; It is not hiding, it begins in a hidden state.'
- // So just make the element hidden according to the configured hideMode
- me.el.hide();
- }
- if (me.disabled) {
- // pass silent so the event doesn't fire the first time.
- me.disable(true);
- }
- // Delete the flag once the rendering is done.
- delete me.rendering;
- }
- return me;
- },
- // @private
- onRender : function(container, position) {
- var me = this,
- el = me.el,
- styles = me.initStyles(),
- renderTpl, renderData, i;
- position = me.getInsertPosition(position);
- if (!el) {
- if (position) {
- el = Ext.DomHelper.insertBefore(position, me.getElConfig(), true);
- }
- else {
- el = Ext.DomHelper.append(container, me.getElConfig(), true);
- }
- }
- else if (me.allowDomMove !== false) {
- if (position) {
- container.dom.insertBefore(el.dom, position);
- } else {
- container.dom.appendChild(el.dom);
- }
- }
- if (Ext.scopeResetCSS && !me.ownerCt) {
- // If this component's el is the body element, we add the reset class to the html tag
- if (el.dom == Ext.getBody().dom) {
- el.parent().addCls(Ext.baseCSSPrefix + 'reset');
- }
- else {
- // Else we wrap this element in an element that adds the reset class.
- me.resetEl = el.wrap({
- cls: Ext.baseCSSPrefix + 'reset'
- });
- }
- }
- me.setUI(me.ui);
- el.addCls(me.initCls());
- el.setStyle(styles);
- // Here we check if the component has a height set through style or css.
- // If it does then we set the this.height to that value and it won't be
- // considered an auto height component
- // if (this.height === undefined) {
- // var height = el.getHeight();
- // // This hopefully means that the panel has an explicit height set in style or css
- // if (height - el.getPadding('tb') - el.getBorderWidth('tb') > 0) {
- // this.height = height;
- // }
- // }
- me.el = el;
- me.initFrame();
- renderTpl = me.initRenderTpl();
- if (renderTpl) {
- renderData = me.initRenderData();
- renderTpl.append(me.getTargetEl(), renderData);
- }
- me.applyRenderSelectors();
- me.rendered = true;
- },
- // @private
- afterRender : function() {
- var me = this,
- pos,
- xy;
- me.getComponentLayout();
- // Set the size if a size is configured, or if this is the outermost Container.
- // Also, if this is a collapsed Panel, it needs an initial component layout
- // to lay out its header so that it can have a height determined.
- if (me.collapsed || (!me.ownerCt || (me.height || me.width))) {
- me.setSize(me.width, me.height);
- } else {
- // It is expected that child items be rendered before this method returns and
- // the afterrender event fires. Since we aren't going to do the layout now, we
- // must render the child items. This is handled implicitly above in the layout
- // caused by setSize.
- me.renderChildren();
- }
- // For floaters, calculate x and y if they aren't defined by aligning
- // the sized element to the center of either the container or the ownerCt
- if (me.floating && (me.x === undefined || me.y === undefined)) {
- if (me.floatParent) {
- xy = me.el.getAlignToXY(me.floatParent.getTargetEl(), 'c-c');
- pos = me.floatParent.getTargetEl().translatePoints(xy[0], xy[1]);
- } else {
- xy = me.el.getAlignToXY(me.container, 'c-c');
- pos = me.container.translatePoints(xy[0], xy[1]);
- }
- me.x = me.x === undefined ? pos.left: me.x;
- me.y = me.y === undefined ? pos.top: me.y;
- }
- if (Ext.isDefined(me.x) || Ext.isDefined(me.y)) {
- me.setPosition(me.x, me.y);
- }
- if (me.styleHtmlContent) {
- me.getTargetEl().addCls(me.styleHtmlCls);
- }
- },
- /**
- * @private
- * Called by Component#doAutoRender
- *
- * Register a Container configured `floating: true` with this Component's {@link Ext.ZIndexManager ZIndexManager}.
- *
- * Components added in ths way will not participate in any layout, but will be rendered
- * upon first show in the way that {@link Ext.window.Window Window}s are.
- */
- registerFloatingItem: function(cmp) {
- var me = this;
- if (!me.floatingItems) {
- me.floatingItems = Ext.create('Ext.ZIndexManager', me);
- }
- me.floatingItems.register(cmp);
- },
- renderChildren: function () {
- var me = this,
- layout = me.getComponentLayout();
- me.suspendLayout = true;
- layout.renderChildren();
- delete me.suspendLayout;
- },
- frameCls: Ext.baseCSSPrefix + 'frame',
- frameIdRegex: /[-]frame\d+[TMB][LCR]$/,
- frameElementCls: {
- tl: [],
- tc: [],
- tr: [],
- ml: [],
- mc: [],
- mr: [],
- bl: [],
- bc: [],
- br: []
- },
- frameTpl: [
- '<tpl if="top">',
- '<tpl if="left"><div id="{fgid}TL" class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl></tpl>" style="background-position: {tl}; padding-left: {frameWidth}px" role="presentation"></tpl>',
- '<tpl if="right"><div id="{fgid}TR" class="{frameCls}-tr {baseCls}-tr {baseCls}-{ui}-tr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl></tpl>" style="background-position: {tr}; padding-right: {frameWidth}px" role="presentation"></tpl>',
- '<div id="{fgid}TC" class="{frameCls}-tc {baseCls}-tc {baseCls}-{ui}-tc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl></tpl>" style="background-position: {tc}; height: {frameWidth}px" role="presentation"></div>',
- '<tpl if="right"></div></tpl>',
- '<tpl if="left"></div></tpl>',
- '</tpl>',
- '<tpl if="left"><div id="{fgid}ML" class="{frameCls}-ml {baseCls}-ml {baseCls}-{ui}-ml<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl></tpl>" style="background-position: {ml}; padding-left: {frameWidth}px" role="presentation"></tpl>',
- '<tpl if="right"><div id="{fgid}MR" class="{frameCls}-mr {baseCls}-mr {baseCls}-{ui}-mr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl></tpl>" style="background-position: {mr}; padding-right: {frameWidth}px" role="presentation"></tpl>',
- '<div id="{fgid}MC" class="{frameCls}-mc {baseCls}-mc {baseCls}-{ui}-mc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl></tpl>" role="presentation"></div>',
- '<tpl if="right"></div></tpl>',
- '<tpl if="left"></div></tpl>',
- '<tpl if="bottom">',
- '<tpl if="left"><div id="{fgid}BL" class="{frameCls}-bl {baseCls}-bl {baseCls}-{ui}-bl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl></tpl>" style="background-position: {bl}; padding-left: {frameWidth}px" role="presentation"></tpl>',
- '<tpl if="right"><div id="{fgid}BR" class="{frameCls}-br {baseCls}-br {baseCls}-{ui}-br<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl></tpl>" style="background-position: {br}; padding-right: {frameWidth}px" role="presentation"></tpl>',
- '<div id="{fgid}BC" class="{frameCls}-bc {baseCls}-bc {baseCls}-{ui}-bc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl></tpl>" style="background-position: {bc}; height: {frameWidth}px" role="presentation"></div>',
- '<tpl if="right"></div></tpl>',
- '<tpl if="left"></div></tpl>',
- '</tpl>'
- ],
- frameTableTpl: [
- '<table><tbody>',
- '<tpl if="top">',
- '<tr>',
- '<tpl if="left"><td id="{fgid}TL" class="{frameCls}-tl {baseCls}-tl {baseCls}-{ui}-tl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tl</tpl></tpl>" style="background-position: {tl}; padding-left:{frameWidth}px" role="presentation"></td></tpl>',
- '<td id="{fgid}TC" class="{frameCls}-tc {baseCls}-tc {baseCls}-{ui}-tc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tc</tpl></tpl>" style="background-position: {tc}; height: {frameWidth}px" role="presentation"></td>',
- '<tpl if="right"><td id="{fgid}TR" class="{frameCls}-tr {baseCls}-tr {baseCls}-{ui}-tr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-tr</tpl></tpl>" style="background-position: {tr}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
- '</tr>',
- '</tpl>',
- '<tr>',
- '<tpl if="left"><td id="{fgid}ML" class="{frameCls}-ml {baseCls}-ml {baseCls}-{ui}-ml<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-ml</tpl></tpl>" style="background-position: {ml}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
- '<td id="{fgid}MC" class="{frameCls}-mc {baseCls}-mc {baseCls}-{ui}-mc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mc</tpl></tpl>" style="background-position: 0 0;" role="presentation"></td>',
- '<tpl if="right"><td id="{fgid}MR" class="{frameCls}-mr {baseCls}-mr {baseCls}-{ui}-mr<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-mr</tpl></tpl>" style="background-position: {mr}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
- '</tr>',
- '<tpl if="bottom">',
- '<tr>',
- '<tpl if="left"><td id="{fgid}BL" class="{frameCls}-bl {baseCls}-bl {baseCls}-{ui}-bl<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bl</tpl></tpl>" style="background-position: {bl}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
- '<td id="{fgid}BC" class="{frameCls}-bc {baseCls}-bc {baseCls}-{ui}-bc<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-bc</tpl></tpl>" style="background-position: {bc}; height: {frameWidth}px" role="presentation"></td>',
- '<tpl if="right"><td id="{fgid}BR" class="{frameCls}-br {baseCls}-br {baseCls}-{ui}-br<tpl if="uiCls"><tpl for="uiCls"> {parent.baseCls}-{parent.ui}-{.}-br</tpl></tpl>" style="background-position: {br}; padding-left: {frameWidth}px" role="presentation"></td></tpl>',
- '</tr>',
- '</tpl>',
- '</tbody></table>'
- ],
- /**
- * @private
- */
- initFrame : function() {
- if (Ext.supports.CSS3BorderRadius) {
- return false;
- }
- var me = this,
- frameInfo = me.getFrameInfo(),
- frameWidth = frameInfo.width,
- frameTpl = me.getFrameTpl(frameInfo.table),
- frameGenId;
- if (me.frame) {
- // since we render id's into the markup and id's NEED to be unique, we have a
- // simple strategy for numbering their generations.
- me.frameGenId = frameGenId = (me.frameGenId || 0) + 1;
- frameGenId = me.id + '-frame' + frameGenId;
- // Here we render the frameTpl to this component. This inserts the 9point div or the table framing.
- frameTpl.insertFirst(me.el, Ext.apply({}, {
- fgid: frameGenId,
- ui: me.ui,
- uiCls: me.uiCls,
- frameCls: me.frameCls,
- baseCls: me.baseCls,
- frameWidth: frameWidth,
- top: !!frameInfo.top,
- left: !!frameInfo.left,
- right: !!frameInfo.right,
- bottom: !!frameInfo.bottom
- }, me.getFramePositions(frameInfo)));
- // The frameBody is returned in getTargetEl, so that layouts render items to the correct target.=
- me.frameBody = me.el.down('.' + me.frameCls + '-mc');
- // Clean out the childEls for the old frame elements (the majority of the els)
- me.removeChildEls(function (c) {
- return c.id && me.frameIdRegex.test(c.id);
- });
- // Add the childEls for each of the new frame elements
- Ext.each(['TL','TC','TR','ML','MC','MR','BL','BC','BR'], function (suffix) {
- me.childEls.push({ name: 'frame' + suffix, id: frameGenId + suffix });
- });
- }
- },
- updateFrame: function() {
- if (Ext.supports.CSS3BorderRadius) {
- return false;
- }
- var me = this,
- wasTable = this.frameSize && this.frameSize.table,
- oldFrameTL = this.frameTL,
- oldFrameBL = this.frameBL,
- oldFrameML = this.frameML,
- oldFrameMC = this.frameMC,
- newMCClassName;
- this.initFrame();
- if (oldFrameMC) {
- if (me.frame) {
- // Reapply render selectors
- delete me.frameTL;
- delete me.frameTC;
- delete me.frameTR;
- delete me.frameML;
- delete me.frameMC;
- delete me.frameMR;
- delete me.frameBL;
- delete me.frameBC;
- delete me.frameBR;
- this.applyRenderSelectors();
- // Store the class names set on the new mc
- newMCClassName = this.frameMC.dom.className;
- // Replace the new mc with the old mc
- oldFrameMC.insertAfter(this.frameMC);
- this.frameMC.remove();
- // Restore the reference to the old frame mc as the framebody
- this.frameBody = this.frameMC = oldFrameMC;
- // Apply the new mc classes to the old mc element
- oldFrameMC.dom.className = newMCClassName;
- // Remove the old framing
- if (wasTable) {
- me.el.query('> table')[1].remove();
- }
- else {
- if (oldFrameTL) {
- oldFrameTL.remove();
- }
- if (oldFrameBL) {
- oldFrameBL.remove();
- }
- oldFrameML.remove();
- }
- }
- else {
- // We were framed but not anymore. Move all content from the old frame to the body
- }
- }
- else if (me.frame) {
- this.applyRenderSelectors();
- }
- },
- getFrameInfo: function() {
- if (Ext.supports.CSS3BorderRadius) {
- return false;
- }
- var me = this,
- left = me.el.getStyle('background-position-x'),
- top = me.el.getStyle('background-position-y'),
- info, frameInfo = false, max;
- // Some browsers dont support background-position-x and y, so for those
- // browsers let's split background-position into two parts.
- if (!left && !top) {
- info = me.el.getStyle('background-position').split(' ');
- left = info[0];
- top = info[1];
- }
- // We actually pass a string in the form of '[type][tl][tr]px [type][br][bl]px' as
- // the background position of this.el from the css to indicate to IE that this component needs
- // framing. We parse it here and change the markup accordingly.
- if (parseInt(left, 10) >= 1000000 && parseInt(top, 10) >= 1000000) {
- max = Math.max;
- frameInfo = {
- // Table markup starts with 110, div markup with 100.
- table: left.substr(0, 3) == '110',
- // Determine if we are dealing with a horizontal or vertical component
- vertical: top.substr(0, 3) == '110',
- // Get and parse the different border radius sizes
- top: max(left.substr(3, 2), left.substr(5, 2)),
- right: max(left.substr(5, 2), top.substr(3, 2)),
- bottom: max(top.substr(3, 2), top.substr(5, 2)),
- left: max(top.substr(5, 2), left.substr(3, 2))
- };
- frameInfo.width = max(frameInfo.top, frameInfo.right, frameInfo.bottom, frameInfo.left);
- // Just to be sure we set the background image of the el to none.
- me.el.setStyle('background-image', 'none');
- }
- // This happens when you set frame: true explicitly without using the x-frame mixin in sass.
- // This way IE can't figure out what sizes to use and thus framing can't work.
- if (me.frame === true && !frameInfo) {
- //<debug error>
- Ext.Error.raise("You have set frame: true explicity on this component while it doesn't have any " +
- "framing defined in the CSS template. In this case IE can't figure out what sizes " +
- "to use and thus framing on this component will be disabled.");
- //</debug>
- }
- me.frame = me.frame || !!frameInfo;
- me.frameSize = frameInfo || false;
- return frameInfo;
- },
- getFramePositions: function(frameInfo) {
- var me = this,
- frameWidth = frameInfo.width,
- dock = me.dock,
- positions, tc, bc, ml, mr;
- if (frameInfo.vertical) {
- tc = '0 -' + (frameWidth * 0) + 'px';
- bc = '0 -' + (frameWidth * 1) + 'px';
- if (dock && dock == "right") {
- tc = 'right -' + (frameWidth * 0) + 'px';
- bc = 'right -' + (frameWidth * 1) + 'px';
- }
- positions = {
- tl: '0 -' + (frameWidth * 0) + 'px',
- tr: '0 -' + (frameWidth * 1) + 'px',
- bl: '0 -' + (frameWidth * 2) + 'px',
- br: '0 -' + (frameWidth * 3) + 'px',
- ml: '-' + (frameWidth * 1) + 'px 0',
- mr: 'right 0',
- tc: tc,
- bc: bc
- };
- } else {
- ml = '-' + (frameWidth * 0) + 'px 0';
- mr = 'right 0';
- if (dock && dock == "bottom") {
- ml = 'left bottom';
- mr = 'right bottom';
- }
- positions = {
- tl: '0 -' + (frameWidth * 2) + 'px',
- tr: 'right -' + (frameWidth * 3) + 'px',
- bl: '0 -' + (frameWidth * 4) + 'px',
- br: 'right -' + (frameWidth * 5) + 'px',
- ml: ml,
- mr: mr,
- tc: '0 -' + (frameWidth * 0) + 'px',
- bc: '0 -' + (frameWidth * 1) + 'px'
- };
- }
- return positions;
- },
- /**
- * @private
- */
- getFrameTpl : function(table) {
- return table ? this.getTpl('frameTableTpl') : this.getTpl('frameTpl');
- },
- /**
- * Creates an array of class names from the configurations to add to this Component's `el` on render.
- *
- * Private, but (possibly) used by ComponentQuery for selection by class name if Component is not rendered.
- *
- * @return {String[]} An array of class names with which the Component's element will be rendered.
- * @private
- */
- initCls: function() {
- var me = this,
- cls = [];
- cls.push(me.baseCls);
- //<deprecated since=0.99>
- if (Ext.isDefined(me.cmpCls)) {
- if (Ext.isDefined(Ext.global.console)) {
- Ext.global.console.warn('Ext.Component: cmpCls has been deprecated. Please use componentCls.');
- }
- me.componentCls = me.cmpCls;
- delete me.cmpCls;
- }
- //</deprecated>
- if (me.componentCls) {
- cls.push(me.componentCls);
- } else {
- me.componentCls = me.baseCls;
- }
- if (me.cls) {
- cls.push(me.cls);
- delete me.cls;
- }
- return cls.concat(me.additionalCls);
- },
- /**
- * Sets the UI for the component. This will remove any existing UIs on the component. It will also loop through any
- * uiCls set on the component and rename them so they include the new UI
- * @param {String} ui The new UI for the component
- */
- setUI: function(ui) {
- var me = this,
- oldUICls = Ext.Array.clone(me.uiCls),
- newUICls = [],
- classes = [],
- cls,
- i;
- //loop through all exisiting uiCls and update the ui in them
- for (i = 0; i < oldUICls.length; i++) {
- cls = oldUICls[i];
- classes = classes.concat(me.removeClsWithUI(cls, true));
- newUICls.push(cls);
- }
- if (classes.length) {
- me.removeCls(classes);
- }
- //remove the UI from the element
- me.removeUIFromElement();
- //set the UI
- me.ui = ui;
- //add the new UI to the elemend
- me.addUIToElement();
- //loop through all exisiting uiCls and update the ui in them
- classes = [];
- for (i = 0; i < newUICls.length; i++) {
- cls = newUICls[i];
- classes = classes.concat(me.addClsWithUI(cls, true));
- }
- if (classes.length) {
- me.addCls(classes);
- }
- },
- /**
- * Adds a cls to the uiCls array, which will also call {@link #addUIClsToElement} and adds to all elements of this
- * component.
- * @param {String/String[]} cls A string or an array of strings to add to the uiCls
- * @param {Object} skip (Boolean) skip True to skip adding it to the class and do it later (via the return)
- */
- addClsWithUI: function(cls, skip) {
- var me = this,
- classes = [],
- i;
- if (!Ext.isArray(cls)) {
- cls = [cls];
- }
- for (i = 0; i < cls.length; i++) {
- if (cls[i] && !me.hasUICls(cls[i])) {
- me.uiCls = Ext.Array.clone(me.uiCls);
- me.uiCls.push(cls[i]);
- classes = classes.concat(me.addUIClsToElement(cls[i]));
- }
- }
- if (skip !== true) {
- me.addCls(classes);
- }
- return classes;
- },
- /**
- * Removes a cls to the uiCls array, which will also call {@link #removeUIClsFromElement} and removes it from all
- * elements of this component.
- * @param {String/String[]} cls A string or an array of strings to remove to the uiCls
- */
- removeClsWithUI: function(cls, skip) {
- var me = this,
- classes = [],
- i;
- if (!Ext.isArray(cls)) {
- cls = [cls];
- }
- for (i = 0; i < cls.length; i++) {
- if (cls[i] && me.hasUICls(cls[i])) {
- me.uiCls = Ext.Array.remove(me.uiCls, cls[i]);
- classes = classes.concat(me.removeUIClsFromElement(cls[i]));
- }
- }
- if (skip !== true) {
- me.removeCls(classes);
- }
- return classes;
- },
- /**
- * Checks if there is currently a specified uiCls
- * @param {String} cls The cls to check
- */
- hasUICls: function(cls) {
- var me = this,
- uiCls = me.uiCls || [];
- return Ext.Array.contains(uiCls, cls);
- },
- /**
- * Method which adds a specified UI + uiCls to the components element. Can be overridden to remove the UI from more
- * than just the components element.
- * @param {String} ui The UI to remove from the element
- */
- addUIClsToElement: function(cls, force) {
- var me = this,
- result = [],
- frameElementCls = me.frameElementCls;
- result.push(Ext.baseCSSPrefix + cls);
- result.push(me.baseCls + '-' + cls);
- result.push(me.baseCls + '-' + me.ui + '-' + cls);
- if (!force && me.frame && !Ext.supports.CSS3BorderRadius) {
- // define each element of the frame
- var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
- classes, i, j, el;
- // loop through each of them, and if they are defined add the ui
- for (i = 0; i < els.length; i++) {
- el = me['frame' + els[i].toUpperCase()];
- classes = [me.baseCls + '-' + me.ui + '-' + els[i], me.baseCls + '-' + me.ui + '-' + cls + '-' + els[i]];
- if (el && el.dom) {
- el.addCls(classes);
- } else {
- for (j = 0; j < classes.length; j++) {
- if (Ext.Array.indexOf(frameElementCls[els[i]], classes[j]) == -1) {
- frameElementCls[els[i]].push(classes[j]);
- }
- }
- }
- }
- }
- me.frameElementCls = frameElementCls;
- return result;
- },
- /**
- * Method which removes a specified UI + uiCls from the components element. The cls which is added to the element
- * will be: `this.baseCls + '-' + ui`
- * @param {String} ui The UI to add to the element
- */
- removeUIClsFromElement: function(cls, force) {
- var me = this,
- result = [],
- frameElementCls = me.frameElementCls;
- result.push(Ext.baseCSSPrefix + cls);
- result.push(me.baseCls + '-' + cls);
- result.push(me.baseCls + '-' + me.ui + '-' + cls);
- if (!force && me.frame && !Ext.supports.CSS3BorderRadius) {
- // define each element of the frame
- var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
- i, el;
- cls = me.baseCls + '-' + me.ui + '-' + cls + '-' + els[i];
- // loop through each of them, and if they are defined add the ui
- for (i = 0; i < els.length; i++) {
- el = me['frame' + els[i].toUpperCase()];
- if (el && el.dom) {
- el.removeCls(cls);
- } else {
- Ext.Array.remove(frameElementCls[els[i]], cls);
- }
- }
- }
- me.frameElementCls = frameElementCls;
- return result;
- },
- /**
- * Method which adds a specified UI to the components element.
- * @private
- */
- addUIToElement: function(force) {
- var me = this,
- frameElementCls = me.frameElementCls;
- me.addCls(me.baseCls + '-' + me.ui);
- if (me.frame && !Ext.supports.CSS3BorderRadius) {
- // define each element of the frame
- var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
- i, el, cls;
- // loop through each of them, and if they are defined add the ui
- for (i = 0; i < els.length; i++) {
- el = me['frame' + els[i].toUpperCase()];
- cls = me.baseCls + '-' + me.ui + '-' + els[i];
- if (el) {
- el.addCls(cls);
- } else {
- if (!Ext.Array.contains(frameElementCls[els[i]], cls)) {
- frameElementCls[els[i]].push(cls);
- }
- }
- }
- }
- },
- /**
- * Method which removes a specified UI from the components element.
- * @private
- */
- removeUIFromElement: function() {
- var me = this,
- frameElementCls = me.frameElementCls;
- me.removeCls(me.baseCls + '-' + me.ui);
- if (me.frame && !Ext.supports.CSS3BorderRadius) {
- // define each element of the frame
- var els = ['tl', 'tc', 'tr', 'ml', 'mc', 'mr', 'bl', 'bc', 'br'],
- i, j, el, cls;
- // loop through each of them, and if they are defined add the ui
- for (i = 0; i < els.length; i++) {
- el = me['frame' + els[i].toUpperCase()];
- cls = me.baseCls + '-' + me.ui + '-' + els[i];
- if (el) {
- el.removeCls(cls);
- } else {
- Ext.Array.remove(frameElementCls[els[i]], cls);
- }
- }
- }
- },
- getElConfig : function() {
- if (Ext.isString(this.autoEl)) {
- this.autoEl = {
- tag: this.autoEl
- };
- }
- var result = this.autoEl || {tag: 'div'};
- result.id = this.id;
- return result;
- },
- /**
- * This function takes the position argument passed to onRender and returns a DOM element that you can use in the
- * insertBefore.
- * @param {String/Number/Ext.Element/HTMLElement} position Index, element id or element you want to put this
- * component before.
- * @return {HTMLElement} DOM element that you can use in the insertBefore
- */
- getInsertPosition: function(position) {
- // Convert the position to an element to insert before
- if (position !== undefined) {
- if (Ext.isNumber(position)) {
- position = this.container.dom.childNodes[position];
- }
- else {
- position = Ext.getDom(position);
- }
- }
- return position;
- },
- /**
- * Adds ctCls to container.
- * @return {Ext.Element} The initialized container
- * @private
- */
- initContainer: function(container) {
- var me = this;
- // If you render a component specifying the el, we get the container
- // of the el, and make sure we dont move the el around in the dom
- // during the render
- if (!container && me.el) {
- container = me.el.dom.parentNode;
- me.allowDomMove = false;
- }
- me.container = Ext.get(container);
- if (me.ctCls) {
- me.container.addCls(me.ctCls);
- }
- return me.container;
- },
- /**
- * Initialized the renderData to be used when rendering the renderTpl.
- * @return {Object} Object with keys and values that are going to be applied to the renderTpl
- * @private
- */
- initRenderData: function() {
- var me = this;
- return Ext.applyIf(me.renderData, {
- id: me.id,
- ui: me.ui,
- uiCls: me.uiCls,
- baseCls: me.baseCls,
- componentCls: me.componentCls,
- frame: me.frame
- });
- },
- /**
- * @private
- */
- getTpl: function(name) {
- var me = this,
- prototype = me.self.prototype,
- ownerPrototype,
- tpl;
- if (me.hasOwnProperty(name)) {
- tpl = me[name];
- if (tpl && !(tpl instanceof Ext.XTemplate)) {
- me[name] = Ext.ClassManager.dynInstantiate('Ext.XTemplate', tpl);
- }
- return me[name];
- }
- if (!(prototype[name] instanceof Ext.XTemplate)) {
- ownerPrototype = prototype;
- do {
- if (ownerPrototype.hasOwnProperty(name)) {
- tpl = ownerPrototype[name];
- if (tpl && !(tpl instanceof Ext.XTemplate)) {
- ownerPrototype[name] = Ext.ClassManager.dynInstantiate('Ext.XTemplate', tpl);
- break;
- }
- }
- ownerPrototype = ownerPrototype.superclass;
- } while (ownerPrototype);
- }
- return prototype[name];
- },
- /**
- * Initializes the renderTpl.
- * @return {Ext.XTemplate} The renderTpl XTemplate instance.
- * @private
- */
- initRenderTpl: function() {
- return this.getTpl('renderTpl');
- },
- /**
- * Converts style definitions to String.
- * @return {String} A CSS style string with style, padding, margin and border.
- * @private
- */
- initStyles: function() {
- var style = {},
- me = this,
- Element = Ext.Element;
- if (Ext.isString(me.style)) {
- style = Element.parseStyles(me.style);
- } else {
- style = Ext.apply({}, me.style);
- }
- // Convert the padding, margin and border properties from a space seperated string
- // into a proper style string
- if (me.padding !== undefined) {
- style.padding = Element.unitizeBox((me.padding === true) ? 5 : me.padding);
- }
- if (me.margin !== undefined) {
- style.margin = Element.unitizeBox((me.margin === true) ? 5 : me.margin);
- }
- delete me.style;
- return style;
- },
- /**
- * Initializes this components contents. It checks for the properties html, contentEl and tpl/data.
- * @private
- */
- initContent: function() {
- var me = this,
- target = me.getTargetEl(),
- contentEl,
- pre;
- if (me.html) {
- target.update(Ext.DomHelper.markup(me.html));
- delete me.html;
- }
- if (me.contentEl) {
- contentEl = Ext.get(me.contentEl);
- pre = Ext.baseCSSPrefix;
- contentEl.removeCls([pre + 'hidden', pre + 'hide-display', pre + 'hide-offsets', pre + 'hide-nosize']);
- target.appendChild(contentEl.dom);
- }
- if (me.tpl) {
- // Make sure this.tpl is an instantiated XTemplate
- if (!me.tpl.isTemplate) {
- me.tpl = Ext.create('Ext.XTemplate', me.tpl);
- }
- if (me.data) {
- me.tpl[me.tplWriteMode](target, me.data);
- delete me.data;
- }
- }
- },
- // @private
- initEvents : function() {
- var me = this,
- afterRenderEvents = me.afterRenderEvents,
- el,
- property,
- fn = function(listeners){
- me.mon(el, listeners);
- };
- if (afterRenderEvents) {
- for (property in afterRenderEvents) {
- if (afterRenderEvents.hasOwnProperty(property)) {
- el = me[property];
- if (el && el.on) {
- Ext.each(afterRenderEvents[property], fn);
- }
- }
- }
- }
- },
- /**
- * Adds each argument passed to this method to the {@link #childEls} array.
- */
- addChildEls: function () {
- var me = this,
- childEls = me.childEls || (me.childEls = []);
- childEls.push.apply(childEls, arguments);
- },
- /**
- * Removes items in the childEls array based on the return value of a supplied test function. The function is called
- * with a entry in childEls and if the test function return true, that entry is removed. If false, that entry is
- * kept.
- * @param {Function} testFn The test function.
- */
- removeChildEls: function (testFn) {
- var me = this,
- old = me.childEls,
- keepers = (me.childEls = []),
- n, i, cel;
- for (i = 0, n = old.length; i < n; ++i) {
- cel = old[i];
- if (!testFn(cel)) {
- keepers.push(cel);
- }
- }
- },
- /**
- * Sets references to elements inside the component. This applies {@link #renderSelectors}
- * as well as {@link #childEls}.
- * @private
- */
- applyRenderSelectors: function() {
- var me = this,
- childEls = me.childEls,
- selectors = me.renderSelectors,
- el = me.el,
- dom = el.dom,
- baseId, childName, childId, i, selector;
- if (childEls) {
- baseId = me.id + '-';
- for (i = childEls.length; i--; ) {
- childName = childId = childEls[i];
- if (typeof(childName) != 'string') {
- childId = childName.id || (baseId + childName.itemId);
- childName = childName.name;
- } else {
- childId = baseId + childId;
- }
- // We don't use Ext.get because that is 3x (or more) slower on IE6-8. Since
- // we know the el's are children of our el we use getById instead:
- me[childName] = el.getById(childId);
- }
- }
- // We still support renderSelectors. There are a few places in the framework that
- // need them and they are a documented part of the API. In fact, we support mixing
- // childEls and renderSelectors (no reason not to).
- if (selectors) {
- for (selector in selectors) {
- if (selectors.hasOwnProperty(selector) && selectors[selector]) {
- me[selector] = Ext.get(Ext.DomQuery.selectNode(selectors[selector], dom));
- }
- }
- }
- },
- /**
- * Tests whether this Component matches the selector string.
- * @param {String} selector The selector string to test against.
- * @return {Boolean} True if this Component matches the selector.
- */
- is: function(selector) {
- return Ext.ComponentQuery.is(this, selector);
- },
- /**
- * Walks up the `ownerCt` axis looking for an ancestor Container which matches the passed simple selector.
- *
- * Example:
- *
- * var owningTabPanel = grid.up('tabpanel');
- *
- * @param {String} [selector] The simple selector to test.
- * @return {Ext.container.Container} The matching ancestor Container (or `undefined` if no match was found).
- */
- up: function(selector) {
- var result = this.ownerCt;
- if (selector) {
- for (; result; result = result.ownerCt) {
- if (Ext.ComponentQuery.is(result, selector)) {
- return result;
- }
- }
- }
- return result;
- },
- /**
- * Returns the next sibling of this Component.
- *
- * Optionally selects the next sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery} selector.
- *
- * May also be refered to as **`next()`**
- *
- * Note that this is limited to siblings, and if no siblings of the item match, `null` is returned. Contrast with
- * {@link #nextNode}
- * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following items.
- * @return {Ext.Component} The next sibling (or the next sibling which matches the selector).
- * Returns null if there is no matching sibling.
- */
- nextSibling: function(selector) {
- var o = this.ownerCt, it, last, idx, c;
- if (o) {
- it = o.items;
- idx = it.indexOf(this) + 1;
- if (idx) {
- if (selector) {
- for (last = it.getCount(); idx < last; idx++) {
- if ((c = it.getAt(idx)).is(selector)) {
- return c;
- }
- }
- } else {
- if (idx < it.getCount()) {
- return it.getAt(idx);
- }
- }
- }
- }
- return null;
- },
- /**
- * Returns the previous sibling of this Component.
- *
- * Optionally selects the previous sibling which matches the passed {@link Ext.ComponentQuery ComponentQuery}
- * selector.
- *
- * May also be refered to as **`prev()`**
- *
- * Note that this is limited to siblings, and if no siblings of the item match, `null` is returned. Contrast with
- * {@link #previousNode}
- * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the preceding items.
- * @return {Ext.Component} The previous sibling (or the previous sibling which matches the selector).
- * Returns null if there is no matching sibling.
- */
- previousSibling: function(selector) {
- var o = this.ownerCt, it, idx, c;
- if (o) {
- it = o.items;
- idx = it.indexOf(this);
- if (idx != -1) {
- if (selector) {
- for (--idx; idx >= 0; idx--) {
- if ((c = it.getAt(idx)).is(selector)) {
- return c;
- }
- }
- } else {
- if (idx) {
- return it.getAt(--idx);
- }
- }
- }
- }
- return null;
- },
- /**
- * Returns the previous node in the Component tree in tree traversal order.
- *
- * Note that this is not limited to siblings, and if invoked upon a node with no matching siblings, will walk the
- * tree in reverse order to attempt to find a match. Contrast with {@link #previousSibling}.
- * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the preceding nodes.
- * @return {Ext.Component} The previous node (or the previous node which matches the selector).
- * Returns null if there is no matching node.
- */
- previousNode: function(selector, includeSelf) {
- var node = this,
- result,
- it, len, i;
- // If asked to include self, test me
- if (includeSelf && node.is(selector)) {
- return node;
- }
- result = this.prev(selector);
- if (result) {
- return result;
- }
- if (node.ownerCt) {
- for (it = node.ownerCt.items.items, i = Ext.Array.indexOf(it, node) - 1; i > -1; i--) {
- if (it[i].query) {
- result = it[i].query(selector);
- result = result[result.length - 1];
- if (result) {
- return result;
- }
- }
- }
- return node.ownerCt.previousNode(selector, true);
- }
- },
- /**
- * Returns the next node in the Component tree in tree traversal order.
- *
- * Note that this is not limited to siblings, and if invoked upon a node with no matching siblings, will walk the
- * tree to attempt to find a match. Contrast with {@link #nextSibling}.
- * @param {String} [selector] A {@link Ext.ComponentQuery ComponentQuery} selector to filter the following nodes.
- * @return {Ext.Component} The next node (or the next node which matches the selector).
- * Returns null if there is no matching node.
- */
- nextNode: function(selector, includeSelf) {
- var node = this,
- result,
- it, len, i;
- // If asked to include self, test me
- if (includeSelf && node.is(selector)) {
- return node;
- }
- result = this.next(selector);
- if (result) {
- return result;
- }
- if (node.ownerCt) {
- for (it = node.ownerCt.items, i = it.indexOf(node) + 1, it = it.items, len = it.length; i < len; i++) {
- if (it[i].down) {
- result = it[i].down(selector);
- if (result) {
- return result;
- }
- }
- }
- return node.ownerCt.nextNode(selector);
- }
- },
- /**
- * Retrieves the id of this component. Will autogenerate an id if one has not already been set.
- * @return {String}
- */
- getId : function() {
- return this.id || (this.id = 'ext-comp-' + (this.getAutoId()));
- },
- getItemId : function() {
- return this.itemId || this.id;
- },
- /**
- * Retrieves the top level element representing this component.
- * @return {Ext.core.Element}
- */
- getEl : function() {
- return this.el;
- },
- /**
- * This is used to determine where to insert the 'html', 'contentEl' and 'items' in this component.
- * @private
- */
- getTargetEl: function() {
- return this.frameBody || this.el;
- },
- /**
- * Tests whether or not this Component is of a specific xtype. This can test whether this Component is descended
- * from the xtype (default) or whether it is directly of the xtype specified (shallow = true).
- *
- * **If using your own subclasses, be aware that a Component must register its own xtype to participate in
- * determination of inherited xtypes.**
- *
- * For a list of all available xtypes, see the {@link Ext.Component} header.
- *
- * Example usage:
- *
- * var t = new Ext.form.field.Text();
- * var isText = t.isXType('textfield'); // true
- * var isBoxSubclass = t.isXType('field'); // true, descended from Ext.form.field.Base
- * var isBoxInstance = t.isXType('field', true); // false, not a direct Ext.form.field.Base instance
- *
- * @param {String} xtype The xtype to check for this Component
- * @param {Boolean} [shallow=false] True to check whether this Component is directly of the specified xtype, false to
- * check whether this Component is descended from the xtype.
- * @return {Boolean} True if this component descends from the specified xtype, false otherwise.
- */
- isXType: function(xtype, shallow) {
- //assume a string by default
- if (Ext.isFunction(xtype)) {
- xtype = xtype.xtype;
- //handle being passed the class, e.g. Ext.Component
- } else if (Ext.isObject(xtype)) {
- xtype = xtype.statics().xtype;
- //handle being passed an instance
- }
- return !shallow ? ('/' + this.getXTypes() + '/').indexOf('/' + xtype + '/') != -1: this.self.xtype == xtype;
- },
- /**
- * Returns this Component's xtype hierarchy as a slash-delimited string. For a list of all available xtypes, see the
- * {@link Ext.Component} header.
- *
- * **If using your own subclasses, be aware that a Component must register its own xtype to participate in
- * determination of inherited xtypes.**
- *
- * Example usage:
- *
- * var t = new Ext.form.field.Text();
- * alert(t.getXTypes()); // alerts 'component/field/textfield'
- *
- * @return {String} The xtype hierarchy string
- */
- getXTypes: function() {
- var self = this.self,
- xtypes, parentPrototype, parentXtypes;
- if (!self.xtypes) {
- xtypes = [];
- parentPrototype = this;
- while (parentPrototype) {
- parentXtypes = parentPrototype.xtypes;
- if (parentXtypes !== undefined) {
- xtypes.unshift.apply(xtypes, parentXtypes);
- }
- parentPrototype = parentPrototype.superclass;
- }
- self.xtypeChain = xtypes;
- self.xtypes = xtypes.join('/');
- }
- return self.xtypes;
- },
- /**
- * Update the content area of a component.
- * @param {String/Object} htmlOrData If this component has been configured with a template via the tpl config then
- * it will use this argument as data to populate the template. If this component was not configured with a template,
- * the components content area will be updated via Ext.Element update
- * @param {Boolean} [loadScripts=false] Only legitimate when using the html configuration.
- * @param {Function} [callback] Only legitimate when using the html configuration. Callback to execute when
- * scripts have finished loading
- */
- update : function(htmlOrData, loadScripts, cb) {
- var me = this;
- if (me.tpl && !Ext.isString(htmlOrData)) {
- me.data = htmlOrData;
- if (me.rendered) {
- me.tpl[me.tplWriteMode](me.getTargetEl(), htmlOrData || {});
- }
- } else {
- me.html = Ext.isObject(htmlOrData) ? Ext.DomHelper.markup(htmlOrData) : htmlOrData;
- if (me.rendered) {
- me.getTargetEl().update(me.html, loadScripts, cb);
- }
- }
- if (me.rendered) {
- me.doComponentLayout();
- }
- },
- /**
- * Convenience function to hide or show this component by boolean.
- * @param {Boolean} visible True to show, false to hide
- * @return {Ext.Component} this
- */
- setVisible : function(visible) {
- return this[visible ? 'show': 'hide']();
- },
- /**
- * Returns true if this component is visible.
- *
- * @param {Boolean} [deep=false] Pass `true` to interrogate the visibility status of all parent Containers to
- * determine whether this Component is truly visible to the user.
- *
- * Generally, to determine whether a Component is hidden, the no argument form is needed. For example when creating
- * dynamically laid out UIs in a hidden Container before showing them.
- *
- * @return {Boolean} True if this component is visible, false otherwise.
- */
- isVisible: function(deep) {
- var me = this,
- child = me,
- visible = !me.hidden,
- ancestor = me.ownerCt;
- // Clear hiddenOwnerCt property
- me.hiddenAncestor = false;
- if (me.destroyed) {
- return false;
- }
- if (deep && visible && me.rendered && ancestor) {
- while (ancestor) {
- // If any ancestor is hidden, then this is hidden.
- // If an ancestor Panel (only Panels have a collapse method) is collapsed,
- // then its layoutTarget (body) is hidden, so this is hidden unless its within a
- // docked item; they are still visible when collapsed (Unless they themseves are hidden)
- if (ancestor.hidden || (ancestor.collapsed &&
- !(ancestor.getDockedItems && Ext.Array.contains(ancestor.getDockedItems(), child)))) {
- // Store hiddenOwnerCt property if needed
- me.hiddenAncestor = ancestor;
- visible = false;
- break;
- }
- child = ancestor;
- ancestor = ancestor.ownerCt;
- }
- }
- return visible;
- },
- /**
- * Enable the component
- * @param {Boolean} [silent=false] Passing true will supress the 'enable' event from being fired.
- */
- enable: function(silent) {
- var me = this;
- if (me.rendered) {
- me.el.removeCls(me.disabledCls);
- me.el.dom.disabled = false;
- me.onEnable();
- }
- me.disabled = false;
- if (silent !== true) {
- me.fireEvent('enable', me);
- }
- return me;
- },
- /**
- * Disable the component.
- * @param {Boolean} [silent=false] Passing true will supress the 'disable' event from being fired.
- */
- disable: function(silent) {
- var me = this;
- if (me.rendered) {
- me.el.addCls(me.disabledCls);
- me.el.dom.disabled = true;
- me.onDisable();
- }
- me.disabled = true;
- if (silent !== true) {
- me.fireEvent('disable', me);
- }
- return me;
- },
- // @private
- onEnable: function() {
- if (this.maskOnDisable) {
- this.el.unmask();
- }
- },
- // @private
- onDisable : function() {
- if (this.maskOnDisable) {
- this.el.mask();
- }
- },
- /**
- * Method to determine whether this Component is currently disabled.
- * @return {Boolean} the disabled state of this Component.
- */
- isDisabled : function() {
- return this.disabled;
- },
- /**
- * Enable or disable the component.
- * @param {Boolean} disabled True to disable.
- */
- setDisabled : function(disabled) {
- return this[disabled ? 'disable': 'enable']();
- },
- /**
- * Method to determine whether this Component is currently set to hidden.
- * @return {Boolean} the hidden state of this Component.
- */
- isHidden : function() {
- return this.hidden;
- },
- /**
- * Adds a CSS class to the top level element representing this component.
- * @param {String} cls The CSS class name to add
- * @return {Ext.Component} Returns the Component to allow method chaining.
- */
- addCls : function(className) {
- var me = this;
- if (!className) {
- return me;
- }
- if (!Ext.isArray(className)){
- className = className.replace(me.trimRe, '').split(me.spacesRe);
- }
- if (me.rendered) {
- me.el.addCls(className);
- }
- else {
- me.additionalCls = Ext.Array.unique(me.additionalCls.concat(className));
- }
- return me;
- },
- /**
- * Adds a CSS class to the top level element representing this component.
- * @param {String} cls The CSS class name to add
- * @return {Ext.Component} Returns the Component to allow method chaining.
- */
- addClass : function() {
- return this.addCls.apply(this, arguments);
- },
- /**
- * Removes a CSS class from the top level element representing this component.
- * @param {Object} className
- * @return {Ext.Component} Returns the Component to allow method chaining.
- */
- removeCls : function(className) {
- var me = this;
- if (!className) {
- return me;
- }
- if (!Ext.isArray(className)){
- className = className.replace(me.trimRe, '').split(me.spacesRe);
- }
- if (me.rendered) {
- me.el.removeCls(className);
- }
- else if (me.additionalCls.length) {
- Ext.each(className, function(cls) {
- Ext.Array.remove(me.additionalCls, cls);
- });
- }
- return me;
- },
- //<debug>
- removeClass : function() {
- if (Ext.isDefined(Ext.global.console)) {
- Ext.global.console.warn('Ext.Component: removeClass has been deprecated. Please use removeCls.');
- }
- return this.removeCls.apply(this, arguments);
- },
- //</debug>
- addOverCls: function() {
- var me = this;
- if (!me.disabled) {
- me.el.addCls(me.overCls);
- }
- },
- removeOverCls: function() {
- this.el.removeCls(this.overCls);
- },
- addListener : function(element, listeners, scope, options) {
- var me = this,
- fn,
- option;
- if (Ext.isString(element) && (Ext.isObject(listeners) || options && options.element)) {
- if (options.element) {
- fn = listeners;
- listeners = {};
- listeners[element] = fn;
- element = options.element;
- if (scope) {
- listeners.scope = scope;
- }
- for (option in options) {
- if (options.hasOwnProperty(option)) {
- if (me.eventOptionsRe.test(option)) {
- listeners[option] = options[option];
- }
- }
- }
- }
- // At this point we have a variable called element,
- // and a listeners object that can be passed to on
- if (me[element] && me[element].on) {
- me.mon(me[element], listeners);
- } else {
- me.afterRenderEvents = me.afterRenderEvents || {};
- if (!me.afterRenderEvents[element]) {
- me.afterRenderEvents[element] = [];
- }
- me.afterRenderEvents[element].push(listeners);
- }
- }
- return me.mixins.observable.addListener.apply(me, arguments);
- },
- // inherit docs
- removeManagedListenerItem: function(isClear, managedListener, item, ename, fn, scope){
- var me = this,
- element = managedListener.options ? managedListener.options.element : null;
- if (element) {
- element = me[element];
- if (element && element.un) {
- if (isClear || (managedListener.item === item && managedListener.ename === ename && (!fn || managedListener.fn === fn) && (!scope || managedListener.scope === scope))) {
- element.un(managedListener.ename, managedListener.fn, managedListener.scope);
- if (!isClear) {
- Ext.Array.remove(me.managedListeners, managedListener);
- }
- }
- }
- } else {
- return me.mixins.observable.removeManagedListenerItem.apply(me, arguments);
- }
- },
- /**
- * Provides the link for Observable's fireEvent method to bubble up the ownership hierarchy.
- * @return {Ext.container.Container} the Container which owns this Component.
- */
- getBubbleTarget : function() {
- return this.ownerCt;
- },
- /**
- * Method to determine whether this Component is floating.
- * @return {Boolean} the floating state of this component.
- */
- isFloating : function() {
- return this.floating;
- },
- /**
- * Method to determine whether this Component is draggable.
- * @return {Boolean} the draggable state of this component.
- */
- isDraggable : function() {
- return !!this.draggable;
- },
- /**
- * Method to determine whether this Component is droppable.
- * @return {Boolean} the droppable state of this component.
- */
- isDroppable : function() {
- return !!this.droppable;
- },
- /**
- * @private
- * Method to manage awareness of when components are added to their
- * respective Container, firing an added event.
- * References are established at add time rather than at render time.
- * @param {Ext.container.Container} container Container which holds the component
- * @param {Number} pos Position at which the component was added
- */
- onAdded : function(container, pos) {
- this.ownerCt = container;
- this.fireEvent('added', this, container, pos);
- },
- /**
- * @private
- * Method to manage awareness of when components are removed from their
- * respective Container, firing an removed event. References are properly
- * cleaned up after removing a component from its owning container.
- */
- onRemoved : function() {
- var me = this;
- me.fireEvent('removed', me, me.ownerCt);
- delete me.ownerCt;
- },
- // @private
- beforeDestroy : Ext.emptyFn,
- // @private
- // @private
- onResize : Ext.emptyFn,
- /**
- * Sets the width and height of this Component. This method fires the {@link #resize} event. This method can accept
- * either width and height as separate arguments, or you can pass a size object like `{width:10, height:20}`.
- *
- * @param {Number/String/Object} width The new width to set. This may be one of:
- *
- * - A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
- * - A String used to set the CSS width style.
- * - A size object in the format `{width: widthValue, height: heightValue}`.
- * - `undefined` to leave the width unchanged.
- *
- * @param {Number/String} height The new height to set (not required if a size object is passed as the first arg).
- * This may be one of:
- *
- * - A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
- * - A String used to set the CSS height style. Animation may **not** be used.
- * - `undefined` to leave the height unchanged.
- *
- * @return {Ext.Component} this
- */
- setSize : function(width, height) {
- var me = this,
- layoutCollection;
- // support for standard size objects
- if (Ext.isObject(width)) {
- height = width.height;
- width = width.width;
- }
- // Constrain within configured maxima
- if (Ext.isNumber(width)) {
- width = Ext.Number.constrain(width, me.minWidth, me.maxWidth);
- }
- if (Ext.isNumber(height)) {
- height = Ext.Number.constrain(height, me.minHeight, me.maxHeight);
- }
- if (!me.rendered || !me.isVisible()) {
- // If an ownerCt is hidden, add my reference onto the layoutOnShow stack. Set the needsLayout flag.
- if (me.hiddenAncestor) {
- layoutCollection = me.hiddenAncestor.layoutOnShow;
- layoutCollection.remove(me);
- layoutCollection.add(me);
- }
- me.needsLayout = {
- width: width,
- height: height,
- isSetSize: true
- };
- if (!me.rendered) {
- me.width = (width !== undefined) ? width : me.width;
- me.height = (height !== undefined) ? height : me.height;
- }
- return me;
- }
- me.doComponentLayout(width, height, true);
- return me;
- },
- isFixedWidth: function() {
- var me = this,
- layoutManagedWidth = me.layoutManagedWidth;
- if (Ext.isDefined(me.width) || layoutManagedWidth == 1) {
- return true;
- }
- if (layoutManagedWidth == 2) {
- return false;
- }
- return (me.ownerCt && me.ownerCt.isFixedWidth());
- },
- isFixedHeight: function() {
- var me = this,
- layoutManagedHeight = me.layoutManagedHeight;
- if (Ext.isDefined(me.height) || layoutManagedHeight == 1) {
- return true;
- }
- if (layoutManagedHeight == 2) {
- return false;
- }
- return (me.ownerCt && me.ownerCt.isFixedHeight());
- },
- setCalculatedSize : function(width, height, callingContainer) {
- var me = this,
- layoutCollection;
- // support for standard size objects
- if (Ext.isObject(width)) {
- callingContainer = width.ownerCt;
- height = width.height;
- width = width.width;
- }
- // Constrain within configured maxima
- if (Ext.isNumber(width)) {
- width = Ext.Number.constrain(width, me.minWidth, me.maxWidth);
- }
- if (Ext.isNumber(height)) {
- height = Ext.Number.constrain(height, me.minHeight, me.maxHeight);
- }
- if (!me.rendered || !me.isVisible()) {
- // If an ownerCt is hidden, add my reference onto the layoutOnShow stack. Set the needsLayout flag.
- if (me.hiddenAncestor) {
- layoutCollection = me.hiddenAncestor.layoutOnShow;
- layoutCollection.remove(me);
- layoutCollection.add(me);
- }
- me.needsLayout = {
- width: width,
- height: height,
- isSetSize: false,
- ownerCt: callingContainer
- };
- return me;
- }
- me.doComponentLayout(width, height, false, callingContainer);
- return me;
- },
- /**
- * This method needs to be called whenever you change something on this component that requires the Component's
- * layout to be recalculated.
- * @param {Object} width
- * @param {Object} height
- * @param {Object} isSetSize
- * @param {Object} callingContainer
- * @return {Ext.container.Container} this
- */
- doComponentLayout : function(width, height, isSetSize, callingContainer) {
- var me = this,
- componentLayout = me.getComponentLayout(),
- lastComponentSize = componentLayout.lastComponentSize || {
- width: undefined,
- height: undefined
- };
- // collapsed state is not relevant here, so no testing done.
- // Only Panels have a collapse method, and that just sets the width/height such that only
- // a single docked Header parallel to the collapseTo side are visible, and the Panel body is hidden.
- if (me.rendered && componentLayout) {
- // If no width passed, then only insert a value if the Component is NOT ALLOWED to autowidth itself.
- if (!Ext.isDefined(width)) {
- if (me.isFixedWidth()) {
- width = Ext.isDefined(me.width) ? me.width : lastComponentSize.width;
- }
- }
- // If no height passed, then only insert a value if the Component is NOT ALLOWED to autoheight itself.
- if (!Ext.isDefined(height)) {
- if (me.isFixedHeight()) {
- height = Ext.isDefined(me.height) ? me.height : lastComponentSize.height;
- }
- }
- if (isSetSize) {
- me.width = width;
- me.height = height;
- }
- componentLayout.layout(width, height, isSetSize, callingContainer);
- }
- return me;
- },
- /**
- * Forces this component to redo its componentLayout.
- */
- forceComponentLayout: function () {
- this.doComponentLayout();
- },
- // @private
- setComponentLayout : function(layout) {
- var currentLayout = this.componentLayout;
- if (currentLayout && currentLayout.isLayout && currentLayout != layout) {
- currentLayout.setOwner(null);
- }
- this.componentLayout = layout;
- layout.setOwner(this);
- },
- getComponentLayout : function() {
- var me = this;
- if (!me.componentLayout || !me.componentLayout.isLayout) {
- me.setComponentLayout(Ext.layout.Layout.create(me.componentLayout, 'autocomponent'));
- }
- return me.componentLayout;
- },
- /**
- * Occurs after componentLayout is run.
- * @param {Number} adjWidth The box-adjusted width that was set
- * @param {Number} adjHeight The box-adjusted height that was set
- * @param {Boolean} isSetSize Whether or not the height/width are stored on the component permanently
- * @param {Ext.Component} callingContainer Container requesting the layout. Only used when isSetSize is false.
- */
- afterComponentLayout: function(width, height, isSetSize, callingContainer) {
- var me = this,
- layout = me.componentLayout,
- oldSize = me.preLayoutSize;
- ++me.componentLayoutCounter;
- if (!oldSize || ((width !== oldSize.width) || (height !== oldSize.height))) {
- me.fireEvent('resize', me, width, height);
- }
- },
- /**
- * Occurs before componentLayout is run. Returning false from this method will prevent the componentLayout from
- * being executed.
- * @param {Number} adjWidth The box-adjusted width that was set
- * @param {Number} adjHeight The box-adjusted height that was set
- * @param {Boolean} isSetSize Whether or not the height/width are stored on the component permanently
- * @param {Ext.Component} callingContainer Container requesting sent the layout. Only used when isSetSize is false.
- */
- beforeComponentLayout: function(width, height, isSetSize, callingContainer) {
- this.preLayoutSize = this.componentLayout.lastComponentSize;
- return true;
- },
- /**
- * Sets the left and top of the component. To set the page XY position instead, use
- * {@link Ext.Component#setPagePosition setPagePosition}. This method fires the {@link #move} event.
- * @param {Number} left The new left
- * @param {Number} top The new top
- * @return {Ext.Component} this
- */
- setPosition : function(x, y) {
- var me = this;
- if (Ext.isObject(x)) {
- y = x.y;
- x = x.x;
- }
- if (!me.rendered) {
- return me;
- }
- if (x !== undefined || y !== undefined) {
- me.el.setBox(x, y);
- me.onPosition(x, y);
- me.fireEvent('move', me, x, y);
- }
- return me;
- },
- /**
- * @private
- * Called after the component is moved, this method is empty by default but can be implemented by any
- * subclass that needs to perform custom logic after a move occurs.
- * @param {Number} x The new x position
- * @param {Number} y The new y position
- */
- onPosition: Ext.emptyFn,
- /**
- * Sets the width of the component. This method fires the {@link #resize} event.
- *
- * @param {Number} width The new width to setThis may be one of:
- *
- * - A Number specifying the new width in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
- * - A String used to set the CSS width style.
- *
- * @return {Ext.Component} this
- */
- setWidth : function(width) {
- return this.setSize(width);
- },
- /**
- * Sets the height of the component. This method fires the {@link #resize} event.
- *
- * @param {Number} height The new height to set. This may be one of:
- *
- * - A Number specifying the new height in the {@link #getEl Element}'s {@link Ext.Element#defaultUnit}s (by default, pixels).
- * - A String used to set the CSS height style.
- * - _undefined_ to leave the height unchanged.
- *
- * @return {Ext.Component} this
- */
- setHeight : function(height) {
- return this.setSize(undefined, height);
- },
- /**
- * Gets the current size of the component's underlying element.
- * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
- */
- getSize : function() {
- return this.el.getSize();
- },
- /**
- * Gets the current width of the component's underlying element.
- * @return {Number}
- */
- getWidth : function() {
- return this.el.getWidth();
- },
- /**
- * Gets the current height of the component's underlying element.
- * @return {Number}
- */
- getHeight : function() {
- return this.el.getHeight();
- },
- /**
- * Gets the {@link Ext.ComponentLoader} for this Component.
- * @return {Ext.ComponentLoader} The loader instance, null if it doesn't exist.
- */
- getLoader: function(){
- var me = this,
- autoLoad = me.autoLoad ? (Ext.isObject(me.autoLoad) ? me.autoLoad : {url: me.autoLoad}) : null,
- loader = me.loader || autoLoad;
- if (loader) {
- if (!loader.isLoader) {
- me.loader = Ext.create('Ext.ComponentLoader', Ext.apply({
- target: me,
- autoLoad: autoLoad
- }, loader));
- } else {
- loader.setTarget(me);
- }
- return me.loader;
- }
- return null;
- },
- /**
- * This method allows you to show or hide a LoadMask on top of this component.
- *
- * @param {Boolean/Object/String} load True to show the default LoadMask, a config object that will be passed to the
- * LoadMask constructor, or a message String to show. False to hide the current LoadMask.
- * @param {Boolean} [targetEl=false] True to mask the targetEl of this Component instead of the `this.el`. For example,
- * setting this to true on a Panel will cause only the body to be masked.
- * @return {Ext.LoadMask} The LoadMask instance that has just been shown.
- */
- setLoading : function(load, targetEl) {
- var me = this,
- config;
- if (me.rendered) {
- if (load !== false && !me.collapsed) {
- if (Ext.isObject(load)) {
- config = load;
- }
- else if (Ext.isString(load)) {
- config = {msg: load};
- }
- else {
- config = {};
- }
- me.loadMask = me.loadMask || Ext.create('Ext.LoadMask', targetEl ? me.getTargetEl() : me.el, config);
- me.loadMask.show();
- } else if (me.loadMask) {
- Ext.destroy(me.loadMask);
- me.loadMask = null;
- }
- }
- return me.loadMask;
- },
- /**
- * Sets the dock position of this component in its parent panel. Note that this only has effect if this item is part
- * of the dockedItems collection of a parent that has a DockLayout (note that any Panel has a DockLayout by default)
- * @param {Object} dock The dock position.
- * @param {Boolean} [layoutParent=false] True to re-layout parent.
- * @return {Ext.Component} this
- */
- setDocked : function(dock, layoutParent) {
- var me = this;
- me.dock = dock;
- if (layoutParent && me.ownerCt && me.rendered) {
- me.ownerCt.doComponentLayout();
- }
- return me;
- },
- onDestroy : function() {
- var me = this;
- if (me.monitorResize && Ext.EventManager.resizeEvent) {
- Ext.EventManager.resizeEvent.removeListener(me.setSize, me);
- }
- // Destroying the floatingItems ZIndexManager will also destroy descendant floating Components
- Ext.destroy(
- me.componentLayout,
- me.loadMask,
- me.floatingItems
- );
- },
- /**
- * Remove any references to elements added via renderSelectors/childEls
- * @private
- */
- cleanElementRefs: function(){
- var me = this,
- i = 0,
- childEls = me.childEls,
- selectors = me.renderSelectors,
- selector,
- name,
- len;
- if (me.rendered) {
- if (childEls) {
- for (len = childEls.length; i < len; ++i) {
- name = childEls[i];
- if (typeof(name) != 'string') {
- name = name.name;
- }
- delete me[name];
- }
- }
- if (selectors) {
- for (selector in selectors) {
- if (selectors.hasOwnProperty(selector)) {
- delete me[selector];
- }
- }
- }
- }
- delete me.rendered;
- delete me.el;
- delete me.frameBody;
- },
- /**
- * Destroys the Component.
- */
- destroy : function() {
- var me = this;
- if (!me.isDestroyed) {
- if (me.fireEvent('beforedestroy', me) !== false) {
- me.destroying = true;
- me.beforeDestroy();
- if (me.floating) {
- delete me.floatParent;
- // A zIndexManager is stamped into a *floating* Component when it is added to a Container.
- // If it has no zIndexManager at render time, it is assigned to the global Ext.WindowManager instance.
- if (me.zIndexManager) {
- me.zIndexManager.unregister(me);
- }
- } else if (me.ownerCt && me.ownerCt.remove) {
- me.ownerCt.remove(me, false);
- }
- me.onDestroy();
- // Attempt to destroy all plugins
- Ext.destroy(me.plugins);
- if (me.rendered) {
- me.el.remove();
- }
- me.fireEvent('destroy', me);
- Ext.ComponentManager.unregister(me);
- me.mixins.state.destroy.call(me);
- me.clearListeners();
- // make sure we clean up the element references after removing all events
- me.cleanElementRefs();
- me.destroying = false;
- me.isDestroyed = true;
- }
- }
- },
- /**
- * Retrieves a plugin by its pluginId which has been bound to this component.
- * @param {Object} pluginId
- * @return {Ext.AbstractPlugin} plugin instance.
- */
- getPlugin: function(pluginId) {
- var i = 0,
- plugins = this.plugins,
- ln = plugins.length;
- for (; i < ln; i++) {
- if (plugins[i].pluginId === pluginId) {
- return plugins[i];
- }
- }
- },
- /**
- * Determines whether this component is the descendant of a particular container.
- * @param {Ext.Container} container
- * @return {Boolean} True if it is.
- */
- isDescendantOf: function(container) {
- return !!this.findParentBy(function(p){
- return p === container;
- });
- }
- }, function() {
- this.createAlias({
- on: 'addListener',
- prev: 'previousSibling',
- next: 'nextSibling'
- });
- });
- /**
- * The AbstractPlugin class is the base class from which user-implemented plugins should inherit.
- *
- * This class defines the essential API of plugins as used by Components by defining the following methods:
- *
- * - `init` : The plugin initialization method which the owning Component calls at Component initialization time.
- *
- * The Component passes itself as the sole parameter.
- *
- * Subclasses should set up bidirectional links between the plugin and its client Component here.
- *
- * - `destroy` : The plugin cleanup method which the owning Component calls at Component destruction time.
- *
- * Use this method to break links between the plugin and the Component and to free any allocated resources.
- *
- * - `enable` : The base implementation just sets the plugin's `disabled` flag to `false`
- *
- * - `disable` : The base implementation just sets the plugin's `disabled` flag to `true`
- */
- Ext.define('Ext.AbstractPlugin', {
- disabled: false,
- constructor: function(config) {
- //<debug>
- if (!config.cmp && Ext.global.console) {
- Ext.global.console.warn("Attempted to attach a plugin ");
- }
- //</debug>
- Ext.apply(this, config);
- },
- getCmp: function() {
- return this.cmp;
- },
- /**
- * @method
- * The init method is invoked after initComponent method has been run for the client Component.
- *
- * The supplied implementation is empty. Subclasses should perform plugin initialization, and set up bidirectional
- * links between the plugin and its client Component in their own implementation of this method.
- * @param {Ext.Component} client The client Component which owns this plugin.
- */
- init: Ext.emptyFn,
- /**
- * @method
- * The destroy method is invoked by the owning Component at the time the Component is being destroyed.
- *
- * The supplied implementation is empty. Subclasses should perform plugin cleanup in their own implementation of
- * this method.
- */
- destroy: Ext.emptyFn,
- /**
- * The base implementation just sets the plugin's `disabled` flag to `false`
- *
- * Plugin subclasses which need more complex processing may implement an overriding implementation.
- */
- enable: function() {
- this.disabled = false;
- },
- /**
- * The base implementation just sets the plugin's `disabled` flag to `true`
- *
- * Plugin subclasses which need more complex processing may implement an overriding implementation.
- */
- disable: function() {
- this.disabled = true;
- }
- });
- /**
- * The Connection class encapsulates a connection to the page's originating domain, allowing requests to be made either
- * to a configured URL, or to a URL specified at request time.
- *
- * Requests made by this class are asynchronous, and will return immediately. No data from the server will be available
- * to the statement immediately following the {@link #request} call. To process returned data, use a success callback
- * in the request options object, or an {@link #requestcomplete event listener}.
- *
- * # File Uploads
- *
- * File uploads are not performed using normal "Ajax" techniques, that is they are not performed using XMLHttpRequests.
- * Instead the form is submitted in the standard manner with the DOM <form> element temporarily modified to have its
- * target set to refer to a dynamically generated, hidden <iframe> which is inserted into the document but removed
- * after the return data has been gathered.
- *
- * The server response is parsed by the browser to create the document for the IFRAME. If the server is using JSON to
- * send the return object, then the Content-Type header must be set to "text/html" in order to tell the browser to
- * insert the text unchanged into the document body.
- *
- * Characters which are significant to an HTML parser must be sent as HTML entities, so encode `<` as `<`, `&` as
- * `&` etc.
- *
- * The response text is retrieved from the document, and a fake XMLHttpRequest object is created containing a
- * responseText property in order to conform to the requirements of event handlers and callbacks.
- *
- * Be aware that file upload packets are sent with the content type multipart/form and some server technologies
- * (notably JEE) may require some custom processing in order to retrieve parameter names and parameter values from the
- * packet content.
- *
- * Also note that it's not possible to check the response code of the hidden iframe, so the success handler will ALWAYS fire.
- */
- Ext.define('Ext.data.Connection', {
- mixins: {
- observable: 'Ext.util.Observable'
- },
- statics: {
- requestId: 0
- },
- url: null,
- async: true,
- method: null,
- username: '',
- password: '',
- /**
- * @cfg {Boolean} disableCaching
- * True to add a unique cache-buster param to GET requests.
- */
- disableCaching: true,
- /**
- * @cfg {Boolean} withCredentials
- * True to set `withCredentials = true` on the XHR object
- */
- withCredentials: false,
- /**
- * @cfg {Boolean} cors
- * True to enable CORS support on the XHR object. Currently the only effect of this option
- * is to use the XDomainRequest object instead of XMLHttpRequest if the browser is IE8 or above.
- */
- cors: false,
- /**
- * @cfg {String} disableCachingParam
- * Change the parameter which is sent went disabling caching through a cache buster.
- */
- disableCachingParam: '_dc',
- /**
- * @cfg {Number} timeout
- * The timeout in milliseconds to be used for requests.
- */
- timeout : 30000,
- /**
- * @cfg {Object} extraParams
- * Any parameters to be appended to the request.
- */
- useDefaultHeader : true,
- defaultPostHeader : 'application/x-www-form-urlencoded; charset=UTF-8',
- useDefaultXhrHeader : true,
- defaultXhrHeader : 'XMLHttpRequest',
- constructor : function(config) {
- config = config || {};
- Ext.apply(this, config);
- this.addEvents(
- /**
- * @event beforerequest
- * Fires before a network request is made to retrieve a data object.
- * @param {Ext.data.Connection} conn This Connection object.
- * @param {Object} options The options config object passed to the {@link #request} method.
- */
- 'beforerequest',
- /**
- * @event requestcomplete
- * Fires if the request was successfully completed.
- * @param {Ext.data.Connection} conn This Connection object.
- * @param {Object} response The XHR object containing the response data.
- * See [The XMLHttpRequest Object](http://www.w3.org/TR/XMLHttpRequest/) for details.
- * @param {Object} options The options config object passed to the {@link #request} method.
- */
- 'requestcomplete',
- /**
- * @event requestexception
- * Fires if an error HTTP status was returned from the server.
- * See [HTTP Status Code Definitions](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
- * for details of HTTP status codes.
- * @param {Ext.data.Connection} conn This Connection object.
- * @param {Object} response The XHR object containing the response data.
- * See [The XMLHttpRequest Object](http://www.w3.org/TR/XMLHttpRequest/) for details.
- * @param {Object} options The options config object passed to the {@link #request} method.
- */
- 'requestexception'
- );
- this.requests = {};
- this.mixins.observable.constructor.call(this);
- },
- /**
- * Sends an HTTP request to a remote server.
- *
- * **Important:** Ajax server requests are asynchronous, and this call will
- * return before the response has been received. Process any returned data
- * in a callback function.
- *
- * Ext.Ajax.request({
- * url: 'ajax_demo/sample.json',
- * success: function(response, opts) {
- * var obj = Ext.decode(response.responseText);
- * console.dir(obj);
- * },
- * failure: function(response, opts) {
- * console.log('server-side failure with status code ' + response.status);
- * }
- * });
- *
- * To execute a callback function in the correct scope, use the `scope` option.
- *
- * @param {Object} options An object which may contain the following properties:
- *
- * (The options object may also contain any other property which might be needed to perform
- * postprocessing in a callback because it is passed to callback functions.)
- *
- * @param {String/Function} options.url The URL to which to send the request, or a function
- * to call which returns a URL string. The scope of the function is specified by the `scope` option.
- * Defaults to the configured `url`.
- *
- * @param {Object/String/Function} options.params An object containing properties which are
- * used as parameters to the request, a url encoded string or a function to call to get either. The scope
- * of the function is specified by the `scope` option.
- *
- * @param {String} options.method The HTTP method to use
- * for the request. Defaults to the configured method, or if no method was configured,
- * "GET" if no parameters are being sent, and "POST" if parameters are being sent. Note that
- * the method name is case-sensitive and should be all caps.
- *
- * @param {Function} options.callback The function to be called upon receipt of the HTTP response.
- * The callback is called regardless of success or failure and is passed the following parameters:
- * @param {Object} options.callback.options The parameter to the request call.
- * @param {Boolean} options.callback.success True if the request succeeded.
- * @param {Object} options.callback.response The XMLHttpRequest object containing the response data.
- * See [www.w3.org/TR/XMLHttpRequest/](http://www.w3.org/TR/XMLHttpRequest/) for details about
- * accessing elements of the response.
- *
- * @param {Function} options.success The function to be called upon success of the request.
- * The callback is passed the following parameters:
- * @param {Object} options.success.response The XMLHttpRequest object containing the response data.
- * @param {Object} options.success.options The parameter to the request call.
- *
- * @param {Function} options.failure The function to be called upon success of the request.
- * The callback is passed the following parameters:
- * @param {Object} options.failure.response The XMLHttpRequest object containing the response data.
- * @param {Object} options.failure.options The parameter to the request call.
- *
- * @param {Object} options.scope The scope in which to execute the callbacks: The "this" object for
- * the callback function. If the `url`, or `params` options were specified as functions from which to
- * draw values, then this also serves as the scope for those function calls. Defaults to the browser
- * window.
- *
- * @param {Number} options.timeout The timeout in milliseconds to be used for this request.
- * Defaults to 30 seconds.
- *
- * @param {Ext.Element/HTMLElement/String} options.form The `<form>` Element or the id of the `<form>`
- * to pull parameters from.
- *
- * @param {Boolean} options.isUpload **Only meaningful when used with the `form` option.**
- *
- * True if the form object is a file upload (will be set automatically if the form was configured
- * with **`enctype`** `"multipart/form-data"`).
- *
- * File uploads are not performed using normal "Ajax" techniques, that is they are **not**
- * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
- * DOM `<form>` element temporarily modified to have its [target][] set to refer to a dynamically
- * generated, hidden `<iframe>` which is inserted into the document but removed after the return data
- * has been gathered.
- *
- * The server response is parsed by the browser to create the document for the IFRAME. If the
- * server is using JSON to send the return object, then the [Content-Type][] header must be set to
- * "text/html" in order to tell the browser to insert the text unchanged into the document body.
- *
- * The response text is retrieved from the document, and a fake XMLHttpRequest object is created
- * containing a `responseText` property in order to conform to the requirements of event handlers
- * and callbacks.
- *
- * Be aware that file upload packets are sent with the content type [multipart/form][] and some server
- * technologies (notably JEE) may require some custom processing in order to retrieve parameter names
- * and parameter values from the packet content.
- *
- * [target]: http://www.w3.org/TR/REC-html40/present/frames.html#adef-target
- * [Content-Type]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17
- * [multipart/form]: http://www.faqs.org/rfcs/rfc2388.html
- *
- * @param {Object} options.headers Request headers to set for the request.
- *
- * @param {Object} options.xmlData XML document to use for the post. Note: This will be used instead
- * of params for the post data. Any params will be appended to the URL.
- *
- * @param {Object/String} options.jsonData JSON data to use as the post. Note: This will be used
- * instead of params for the post data. Any params will be appended to the URL.
- *
- * @param {Boolean} options.disableCaching True to add a unique cache-buster param to GET requests.
- *
- * @param {Boolean} options.withCredentials True to add the withCredentials property to the XHR object
- *
- * @return {Object} The request object. This may be used to cancel the request.
- */
- request : function(options) {
- options = options || {};
- var me = this,
- scope = options.scope || window,
- username = options.username || me.username,
- password = options.password || me.password || '',
- async,
- requestOptions,
- request,
- headers,
- xhr;
- if (me.fireEvent('beforerequest', me, options) !== false) {
- requestOptions = me.setOptions(options, scope);
- if (this.isFormUpload(options) === true) {
- this.upload(options.form, requestOptions.url, requestOptions.data, options);
- return null;
- }
- // if autoabort is set, cancel the current transactions
- if (options.autoAbort === true || me.autoAbort) {
- me.abort();
- }
- // create a connection object
- if ((options.cors === true || me.cors === true) && Ext.isIe && Ext.ieVersion >= 8) {
- xhr = new XDomainRequest();
- } else {
- xhr = this.getXhrInstance();
- }
- async = options.async !== false ? (options.async || me.async) : false;
- // open the request
- if (username) {
- xhr.open(requestOptions.method, requestOptions.url, async, username, password);
- } else {
- xhr.open(requestOptions.method, requestOptions.url, async);
- }
- if (options.withCredentials === true || me.withCredentials === true) {
- xhr.withCredentials = true;
- }
- headers = me.setupHeaders(xhr, options, requestOptions.data, requestOptions.params);
- // create the transaction object
- request = {
- id: ++Ext.data.Connection.requestId,
- xhr: xhr,
- headers: headers,
- options: options,
- async: async,
- timeout: setTimeout(function() {
- request.timedout = true;
- me.abort(request);
- }, options.timeout || me.timeout)
- };
- me.requests[request.id] = request;
- me.latestId = request.id;
- // bind our statechange listener
- if (async) {
- xhr.onreadystatechange = Ext.Function.bind(me.onStateChange, me, [request]);
- }
- // start the request!
- xhr.send(requestOptions.data);
- if (!async) {
- return this.onComplete(request);
- }
- return request;
- } else {
- Ext.callback(options.callback, options.scope, [options, undefined, undefined]);
- return null;
- }
- },
- /**
- * Uploads a form using a hidden iframe.
- * @param {String/HTMLElement/Ext.Element} form The form to upload
- * @param {String} url The url to post to
- * @param {String} params Any extra parameters to pass
- * @param {Object} options The initial options
- */
- upload: function(form, url, params, options) {
- form = Ext.getDom(form);
- options = options || {};
- var id = Ext.id(),
- frame = document.createElement('iframe'),
- hiddens = [],
- encoding = 'multipart/form-data',
- buf = {
- target: form.target,
- method: form.method,
- encoding: form.encoding,
- enctype: form.enctype,
- action: form.action
- }, hiddenItem;
- /*
- * Originally this behaviour was modified for Opera 10 to apply the secure URL after
- * the frame had been added to the document. It seems this has since been corrected in
- * Opera so the behaviour has been reverted, the URL will be set before being added.
- */
- Ext.fly(frame).set({
- id: id,
- name: id,
- cls: Ext.baseCSSPrefix + 'hide-display',
- src: Ext.SSL_SECURE_URL
- });
- document.body.appendChild(frame);
- // This is required so that IE doesn't pop the response up in a new window.
- if (document.frames) {
- document.frames[id].name = id;
- }
- Ext.fly(form).set({
- target: id,
- method: 'POST',
- enctype: encoding,
- encoding: encoding,
- action: url || buf.action
- });
- // add dynamic params
- if (params) {
- Ext.iterate(Ext.Object.fromQueryString(params), function(name, value){
- hiddenItem = document.createElement('input');
- Ext.fly(hiddenItem).set({
- type: 'hidden',
- value: value,
- name: name
- });
- form.appendChild(hiddenItem);
- hiddens.push(hiddenItem);
- });
- }
- Ext.fly(frame).on('load', Ext.Function.bind(this.onUploadComplete, this, [frame, options]), null, {single: true});
- form.submit();
- Ext.fly(form).set(buf);
- Ext.each(hiddens, function(h) {
- Ext.removeNode(h);
- });
- },
- /**
- * @private
- * Callback handler for the upload function. After we've submitted the form via the iframe this creates a bogus
- * response object to simulate an XHR and populates its responseText from the now-loaded iframe's document body
- * (or a textarea inside the body). We then clean up by removing the iframe
- */
- onUploadComplete: function(frame, options) {
- var me = this,
- // bogus response object
- response = {
- responseText: '',
- responseXML: null
- }, doc, firstChild;
- try {
- doc = frame.contentWindow.document || frame.contentDocument || window.frames[frame.id].document;
- if (doc) {
- if (doc.body) {
- if (/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)) { // json response wrapped in textarea
- response.responseText = firstChild.value;
- } else {
- response.responseText = doc.body.innerHTML;
- }
- }
- //in IE the document may still have a body even if returns XML.
- response.responseXML = doc.XMLDocument || doc;
- }
- } catch (e) {
- }
- me.fireEvent('requestcomplete', me, response, options);
- Ext.callback(options.success, options.scope, [response, options]);
- Ext.callback(options.callback, options.scope, [options, true, response]);
- setTimeout(function(){
- Ext.removeNode(frame);
- }, 100);
- },
- /**
- * Detects whether the form is intended to be used for an upload.
- * @private
- */
- isFormUpload: function(options){
- var form = this.getForm(options);
- if (form) {
- return (options.isUpload || (/multipart\/form-data/i).test(form.getAttribute('enctype')));
- }
- return false;
- },
- /**
- * Gets the form object from options.
- * @private
- * @param {Object} options The request options
- * @return {HTMLElement} The form, null if not passed
- */
- getForm: function(options){
- return Ext.getDom(options.form) || null;
- },
- /**
- * Sets various options such as the url, params for the request
- * @param {Object} options The initial options
- * @param {Object} scope The scope to execute in
- * @return {Object} The params for the request
- */
- setOptions: function(options, scope){
- var me = this,
- params = options.params || {},
- extraParams = me.extraParams,
- urlParams = options.urlParams,
- url = options.url || me.url,
- jsonData = options.jsonData,
- method,
- disableCache,
- data;
- // allow params to be a method that returns the params object
- if (Ext.isFunction(params)) {
- params = params.call(scope, options);
- }
- // allow url to be a method that returns the actual url
- if (Ext.isFunction(url)) {
- url = url.call(scope, options);
- }
- url = this.setupUrl(options, url);
- //<debug>
- if (!url) {
- Ext.Error.raise({
- options: options,
- msg: 'No URL specified'
- });
- }
- //</debug>
- // check for xml or json data, and make sure json data is encoded
- data = options.rawData || options.xmlData || jsonData || null;
- if (jsonData && !Ext.isPrimitive(jsonData)) {
- data = Ext.encode(data);
- }
- // make sure params are a url encoded string and include any extraParams if specified
- if (Ext.isObject(params)) {
- params = Ext.Object.toQueryString(params);
- }
- if (Ext.isObject(extraParams)) {
- extraParams = Ext.Object.toQueryString(extraParams);
- }
- params = params + ((extraParams) ? ((params) ? '&' : '') + extraParams : '');
- urlParams = Ext.isObject(urlParams) ? Ext.Object.toQueryString(urlParams) : urlParams;
- params = this.setupParams(options, params);
- // decide the proper method for this request
- method = (options.method || me.method || ((params || data) ? 'POST' : 'GET')).toUpperCase();
- this.setupMethod(options, method);
- disableCache = options.disableCaching !== false ? (options.disableCaching || me.disableCaching) : false;
- // if the method is get append date to prevent caching
- if (method === 'GET' && disableCache) {
- url = Ext.urlAppend(url, (options.disableCachingParam || me.disableCachingParam) + '=' + (new Date().getTime()));
- }
- // if the method is get or there is json/xml data append the params to the url
- if ((method == 'GET' || data) && params) {
- url = Ext.urlAppend(url, params);
- params = null;
- }
- // allow params to be forced into the url
- if (urlParams) {
- url = Ext.urlAppend(url, urlParams);
- }
- return {
- url: url,
- method: method,
- data: data || params || null
- };
- },
- /**
- * Template method for overriding url
- * @template
- * @private
- * @param {Object} options
- * @param {String} url
- * @return {String} The modified url
- */
- setupUrl: function(options, url){
- var form = this.getForm(options);
- if (form) {
- url = url || form.action;
- }
- return url;
- },
- /**
- * Template method for overriding params
- * @template
- * @private
- * @param {Object} options
- * @param {String} params
- * @return {String} The modified params
- */
- setupParams: function(options, params) {
- var form = this.getForm(options),
- serializedForm;
- if (form && !this.isFormUpload(options)) {
- serializedForm = Ext.Element.serializeForm(form);
- params = params ? (params + '&' + serializedForm) : serializedForm;
- }
- return params;
- },
- /**
- * Template method for overriding method
- * @template
- * @private
- * @param {Object} options
- * @param {String} method
- * @return {String} The modified method
- */
- setupMethod: function(options, method){
- if (this.isFormUpload(options)) {
- return 'POST';
- }
- return method;
- },
- /**
- * Setup all the headers for the request
- * @private
- * @param {Object} xhr The xhr object
- * @param {Object} options The options for the request
- * @param {Object} data The data for the request
- * @param {Object} params The params for the request
- */
- setupHeaders: function(xhr, options, data, params){
- var me = this,
- headers = Ext.apply({}, options.headers || {}, me.defaultHeaders || {}),
- contentType = me.defaultPostHeader,
- jsonData = options.jsonData,
- xmlData = options.xmlData,
- key,
- header;
- if (!headers['Content-Type'] && (data || params)) {
- if (data) {
- if (options.rawData) {
- contentType = 'text/plain';
- } else {
- if (xmlData && Ext.isDefined(xmlData)) {
- contentType = 'text/xml';
- } else if (jsonData && Ext.isDefined(jsonData)) {
- contentType = 'application/json';
- }
- }
- }
- headers['Content-Type'] = contentType;
- }
- if (me.useDefaultXhrHeader && !headers['X-Requested-With']) {
- headers['X-Requested-With'] = me.defaultXhrHeader;
- }
- // set up all the request headers on the xhr object
- try{
- for (key in headers) {
- if (headers.hasOwnProperty(key)) {
- header = headers[key];
- xhr.setRequestHeader(key, header);
- }
- }
- } catch(e) {
- me.fireEvent('exception', key, header);
- }
- return headers;
- },
- /**
- * Creates the appropriate XHR transport for the browser.
- * @private
- */
- getXhrInstance: (function(){
- var options = [function(){
- return new XMLHttpRequest();
- }, function(){
- return new ActiveXObject('MSXML2.XMLHTTP.3.0');
- }, function(){
- return new ActiveXObject('MSXML2.XMLHTTP');
- }, function(){
- return new ActiveXObject('Microsoft.XMLHTTP');
- }], i = 0,
- len = options.length,
- xhr;
- for(; i < len; ++i) {
- try{
- xhr = options[i];
- xhr();
- break;
- }catch(e){}
- }
- return xhr;
- })(),
- /**
- * Determines whether this object has a request outstanding.
- * @param {Object} [request] Defaults to the last transaction
- * @return {Boolean} True if there is an outstanding request.
- */
- isLoading : function(request) {
- if (!request) {
- request = this.getLatest();
- }
- if (!(request && request.xhr)) {
- return false;
- }
- // if there is a connection and readyState is not 0 or 4
- var state = request.xhr.readyState;
- return !(state === 0 || state == 4);
- },
- /**
- * Aborts an active request.
- * @param {Object} [request] Defaults to the last request
- */
- abort : function(request) {
- var me = this;
-
- if (!request) {
- request = me.getLatest();
- }
- if (request && me.isLoading(request)) {
- /*
- * Clear out the onreadystatechange here, this allows us
- * greater control, the browser may/may not fire the function
- * depending on a series of conditions.
- */
- request.xhr.onreadystatechange = null;
- request.xhr.abort();
- me.clearTimeout(request);
- if (!request.timedout) {
- request.aborted = true;
- }
- me.onComplete(request);
- me.cleanup(request);
- }
- },
-
- /**
- * Aborts all active requests
- */
- abortAll: function(){
- var requests = this.requests,
- id;
-
- for (id in requests) {
- if (requests.hasOwnProperty(id)) {
- this.abort(requests[id]);
- }
- }
- },
-
- /**
- * Gets the most recent request
- * @private
- * @return {Object} The request. Null if there is no recent request
- */
- getLatest: function(){
- var id = this.latestId,
- request;
-
- if (id) {
- request = this.requests[id];
- }
- return request || null;
- },
- /**
- * Fires when the state of the xhr changes
- * @private
- * @param {Object} request The request
- */
- onStateChange : function(request) {
- if (request.xhr.readyState == 4) {
- this.clearTimeout(request);
- this.onComplete(request);
- this.cleanup(request);
- }
- },
- /**
- * Clears the timeout on the request
- * @private
- * @param {Object} The request
- */
- clearTimeout: function(request){
- clearTimeout(request.timeout);
- delete request.timeout;
- },
- /**
- * Cleans up any left over information from the request
- * @private
- * @param {Object} The request
- */
- cleanup: function(request){
- request.xhr = null;
- delete request.xhr;
- },
- /**
- * To be called when the request has come back from the server
- * @private
- * @param {Object} request
- * @return {Object} The response
- */
- onComplete : function(request) {
- var me = this,
- options = request.options,
- result,
- success,
- response;
- try {
- result = me.parseStatus(request.xhr.status);
- } catch (e) {
- // in some browsers we can't access the status if the readyState is not 4, so the request has failed
- result = {
- success : false,
- isException : false
- };
- }
- success = result.success;
- if (success) {
- response = me.createResponse(request);
- me.fireEvent('requestcomplete', me, response, options);
- Ext.callback(options.success, options.scope, [response, options]);
- } else {
- if (result.isException || request.aborted || request.timedout) {
- response = me.createException(request);
- } else {
- response = me.createResponse(request);
- }
- me.fireEvent('requestexception', me, response, options);
- Ext.callback(options.failure, options.scope, [response, options]);
- }
- Ext.callback(options.callback, options.scope, [options, success, response]);
- delete me.requests[request.id];
- return response;
- },
- /**
- * Checks if the response status was successful
- * @param {Number} status The status code
- * @return {Object} An object containing success/status state
- */
- parseStatus: function(status) {
- // see: https://prototype.lighthouseapp.com/projects/8886/tickets/129-ie-mangles-http-response-status-code-204-to-1223
- status = status == 1223 ? 204 : status;
- var success = (status >= 200 && status < 300) || status == 304,
- isException = false;
- if (!success) {
- switch (status) {
- case 12002:
- case 12029:
- case 12030:
- case 12031:
- case 12152:
- case 13030:
- isException = true;
- break;
- }
- }
- return {
- success: success,
- isException: isException
- };
- },
- /**
- * Creates the response object
- * @private
- * @param {Object} request
- */
- createResponse : function(request) {
- var xhr = request.xhr,
- headers = {},
- lines = xhr.getAllResponseHeaders().replace(/\r\n/g, '\n').split('\n'),
- count = lines.length,
- line, index, key, value, response;
- while (count--) {
- line = lines[count];
- index = line.indexOf(':');
- if(index >= 0) {
- key = line.substr(0, index).toLowerCase();
- if (line.charAt(index + 1) == ' ') {
- ++index;
- }
- headers[key] = line.substr(index + 1);
- }
- }
- request.xhr = null;
- delete request.xhr;
- response = {
- request: request,
- requestId : request.id,
- status : xhr.status,
- statusText : xhr.statusText,
- getResponseHeader : function(header){ return headers[header.toLowerCase()]; },
- getAllResponseHeaders : function(){ return headers; },
- responseText : xhr.responseText,
- responseXML : xhr.responseXML
- };
- // If we don't explicitly tear down the xhr reference, IE6/IE7 will hold this in the closure of the
- // functions created with getResponseHeader/getAllResponseHeaders
- xhr = null;
- return response;
- },
- /**
- * Creates the exception object
- * @private
- * @param {Object} request
- */
- createException : function(request) {
- return {
- request : request,
- requestId : request.id,
- status : request.aborted ? -1 : 0,
- statusText : request.aborted ? 'transaction aborted' : 'communication failure',
- aborted: request.aborted,
- timedout: request.timedout
- };
- }
- });
- /**
- * @class Ext.Ajax
- * @singleton
- * @markdown
- * @extends Ext.data.Connection
- A singleton instance of an {@link Ext.data.Connection}. This class
- is used to communicate with your server side code. It can be used as follows:
- Ext.Ajax.request({
- url: 'page.php',
- params: {
- id: 1
- },
- success: function(response){
- var text = response.responseText;
- // process server response here
- }
- });
- Default options for all requests can be set by changing a property on the Ext.Ajax class:
- Ext.Ajax.timeout = 60000; // 60 seconds
- Any options specified in the request method for the Ajax request will override any
- defaults set on the Ext.Ajax class. In the code sample below, the timeout for the
- request will be 60 seconds.
- Ext.Ajax.timeout = 120000; // 120 seconds
- Ext.Ajax.request({
- url: 'page.aspx',
- timeout: 60000
- });
- In general, this class will be used for all Ajax requests in your application.
- The main reason for creating a separate {@link Ext.data.Connection} is for a
- series of requests that share common settings that are different to all other
- requests in the application.
- */
- Ext.define('Ext.Ajax', {
- extend: 'Ext.data.Connection',
- singleton: true,
- /**
- * @cfg {String} url @hide
- */
- /**
- * @cfg {Object} extraParams @hide
- */
- /**
- * @cfg {Object} defaultHeaders @hide
- */
- /**
- * @cfg {String} method (Optional) @hide
- */
- /**
- * @cfg {Number} timeout (Optional) @hide
- */
- /**
- * @cfg {Boolean} autoAbort (Optional) @hide
- */
- /**
- * @cfg {Boolean} disableCaching (Optional) @hide
- */
- /**
- * @property {Boolean} disableCaching
- * True to add a unique cache-buster param to GET requests. Defaults to true.
- */
- /**
- * @property {String} url
- * The default URL to be used for requests to the server.
- * If the server receives all requests through one URL, setting this once is easier than
- * entering it on every request.
- */
- /**
- * @property {Object} extraParams
- * An object containing properties which are used as extra parameters to each request made
- * by this object. Session information and other data that you need
- * to pass with each request are commonly put here.
- */
- /**
- * @property {Object} defaultHeaders
- * An object containing request headers which are added to each request made by this object.
- */
- /**
- * @property {String} method
- * The default HTTP method to be used for requests. Note that this is case-sensitive and
- * should be all caps (if not set but params are present will use
- * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)
- */
- /**
- * @property {Number} timeout
- * The timeout in milliseconds to be used for requests. Defaults to 30000.
- */
- /**
- * @property {Boolean} autoAbort
- * Whether a new request should abort any pending requests.
- */
- autoAbort : false
- });
- /**
- * A class used to load remote content to an Element. Sample usage:
- *
- * Ext.get('el').load({
- * url: 'myPage.php',
- * scripts: true,
- * params: {
- * id: 1
- * }
- * });
- *
- * In general this class will not be instanced directly, rather the {@link Ext.Element#load} method
- * will be used.
- */
- Ext.define('Ext.ElementLoader', {
- /* Begin Definitions */
- mixins: {
- observable: 'Ext.util.Observable'
- },
- uses: [
- 'Ext.data.Connection',
- 'Ext.Ajax'
- ],
- statics: {
- Renderer: {
- Html: function(loader, response, active){
- loader.getTarget().update(response.responseText, active.scripts === true);
- return true;
- }
- }
- },
- /* End Definitions */
- /**
- * @cfg {String} url
- * The url to retrieve the content from.
- */
- url: null,
- /**
- * @cfg {Object} params
- * Any params to be attached to the Ajax request. These parameters will
- * be overridden by any params in the load options.
- */
- params: null,
- /**
- * @cfg {Object} baseParams Params that will be attached to every request. These parameters
- * will not be overridden by any params in the load options.
- */
- baseParams: null,
- /**
- * @cfg {Boolean/Object} autoLoad
- * True to have the loader make a request as soon as it is created.
- * This argument can also be a set of options that will be passed to {@link #load} is called.
- */
- autoLoad: false,
- /**
- * @cfg {HTMLElement/Ext.Element/String} target
- * The target element for the loader. It can be the DOM element, the id or an {@link Ext.Element}.
- */
- target: null,
- /**
- * @cfg {Boolean/String} loadMask
- * True or a string to show when the element is loading.
- */
- loadMask: false,
- /**
- * @cfg {Object} ajaxOptions
- * Any additional options to be passed to the request, for example timeout or headers.
- */
- ajaxOptions: null,
- /**
- * @cfg {Boolean} scripts
- * True to parse any inline script tags in the response.
- */
- scripts: false,
- /**
- * @cfg {Function} success
- * A function to be called when a load request is successful.
- * Will be called with the following config parameters:
- *
- * - this - The ElementLoader instance.
- * - response - The response object.
- * - options - Ajax options.
- */
- /**
- * @cfg {Function} failure A function to be called when a load request fails.
- * Will be called with the following config parameters:
- *
- * - this - The ElementLoader instance.
- * - response - The response object.
- * - options - Ajax options.
- */
- /**
- * @cfg {Function} callback A function to be called when a load request finishes.
- * Will be called with the following config parameters:
- *
- * - this - The ElementLoader instance.
- * - success - True if successful request.
- * - response - The response object.
- * - options - Ajax options.
- */
- /**
- * @cfg {Object} scope
- * The scope to execute the {@link #success} and {@link #failure} functions in.
- */
- /**
- * @cfg {Function} renderer
- * A custom function to render the content to the element. The passed parameters are:
- *
- * - The loader
- * - The response
- * - The active request
- */
- isLoader: true,
- constructor: function(config) {
- var me = this,
- autoLoad;
- config = config || {};
- Ext.apply(me, config);
- me.setTarget(me.target);
- me.addEvents(
- /**
- * @event beforeload
- * Fires before a load request is made to the server.
- * Returning false from an event listener can prevent the load
- * from occurring.
- * @param {Ext.ElementLoader} this
- * @param {Object} options The options passed to the request
- */
- 'beforeload',
- /**
- * @event exception
- * Fires after an unsuccessful load.
- * @param {Ext.ElementLoader} this
- * @param {Object} response The response from the server
- * @param {Object} options The options passed to the request
- */
- 'exception',
- /**
- * @event load
- * Fires after a successful load.
- * @param {Ext.ElementLoader} this
- * @param {Object} response The response from the server
- * @param {Object} options The options passed to the request
- */
- 'load'
- );
- // don't pass config because we have already applied it.
- me.mixins.observable.constructor.call(me);
- if (me.autoLoad) {
- autoLoad = me.autoLoad;
- if (autoLoad === true) {
- autoLoad = {};
- }
- me.load(autoLoad);
- }
- },
- /**
- * Sets an {@link Ext.Element} as the target of this loader.
- * Note that if the target is changed, any active requests will be aborted.
- * @param {String/HTMLElement/Ext.Element} target The element or its ID.
- */
- setTarget: function(target){
- var me = this;
- target = Ext.get(target);
- if (me.target && me.target != target) {
- me.abort();
- }
- me.target = target;
- },
- /**
- * Returns the target of this loader.
- * @return {Ext.Component} The target or null if none exists.
- */
- getTarget: function(){
- return this.target || null;
- },
- /**
- * Aborts the active load request
- */
- abort: function(){
- var active = this.active;
- if (active !== undefined) {
- Ext.Ajax.abort(active.request);
- if (active.mask) {
- this.removeMask();
- }
- delete this.active;
- }
- },
- /**
- * Removes the mask on the target
- * @private
- */
- removeMask: function(){
- this.target.unmask();
- },
- /**
- * Adds the mask on the target
- * @private
- * @param {Boolean/Object} mask The mask configuration
- */
- addMask: function(mask){
- this.target.mask(mask === true ? null : mask);
- },
- /**
- * Loads new data from the server.
- * @param {Object} options The options for the request. They can be any configuration option that can be specified for
- * the class, with the exception of the target option. Note that any options passed to the method will override any
- * class defaults.
- */
- load: function(options) {
- //<debug>
- if (!this.target) {
- Ext.Error.raise('A valid target is required when loading content');
- }
- //</debug>
- options = Ext.apply({}, options);
- var me = this,
- target = me.target,
- mask = Ext.isDefined(options.loadMask) ? options.loadMask : me.loadMask,
- params = Ext.apply({}, options.params),
- ajaxOptions = Ext.apply({}, options.ajaxOptions),
- callback = options.callback || me.callback,
- scope = options.scope || me.scope || me,
- request;
- Ext.applyIf(ajaxOptions, me.ajaxOptions);
- Ext.applyIf(options, ajaxOptions);
- Ext.applyIf(params, me.params);
- Ext.apply(params, me.baseParams);
- Ext.applyIf(options, {
- url: me.url
- });
- //<debug>
- if (!options.url) {
- Ext.Error.raise('You must specify the URL from which content should be loaded');
- }
- //</debug>
- Ext.apply(options, {
- scope: me,
- params: params,
- callback: me.onComplete
- });
- if (me.fireEvent('beforeload', me, options) === false) {
- return;
- }
- if (mask) {
- me.addMask(mask);
- }
- request = Ext.Ajax.request(options);
- me.active = {
- request: request,
- options: options,
- mask: mask,
- scope: scope,
- callback: callback,
- success: options.success || me.success,
- failure: options.failure || me.failure,
- renderer: options.renderer || me.renderer,
- scripts: Ext.isDefined(options.scripts) ? options.scripts : me.scripts
- };
- me.setOptions(me.active, options);
- },
- /**
- * Sets any additional options on the active request
- * @private
- * @param {Object} active The active request
- * @param {Object} options The initial options
- */
- setOptions: Ext.emptyFn,
- /**
- * Parses the response after the request completes
- * @private
- * @param {Object} options Ajax options
- * @param {Boolean} success Success status of the request
- * @param {Object} response The response object
- */
- onComplete: function(options, success, response) {
- var me = this,
- active = me.active,
- scope = active.scope,
- renderer = me.getRenderer(active.renderer);
- if (success) {
- success = renderer.call(me, me, response, active);
- }
- if (success) {
- Ext.callback(active.success, scope, [me, response, options]);
- me.fireEvent('load', me, response, options);
- } else {
- Ext.callback(active.failure, scope, [me, response, options]);
- me.fireEvent('exception', me, response, options);
- }
- Ext.callback(active.callback, scope, [me, success, response, options]);
- if (active.mask) {
- me.removeMask();
- }
- delete me.active;
- },
- /**
- * Gets the renderer to use
- * @private
- * @param {String/Function} renderer The renderer to use
- * @return {Function} A rendering function to use.
- */
- getRenderer: function(renderer){
- if (Ext.isFunction(renderer)) {
- return renderer;
- }
- return this.statics().Renderer.Html;
- },
- /**
- * Automatically refreshes the content over a specified period.
- * @param {Number} interval The interval to refresh in ms.
- * @param {Object} options (optional) The options to pass to the load method. See {@link #load}
- */
- startAutoRefresh: function(interval, options){
- var me = this;
- me.stopAutoRefresh();
- me.autoRefresh = setInterval(function(){
- me.load(options);
- }, interval);
- },
- /**
- * Clears any auto refresh. See {@link #startAutoRefresh}.
- */
- stopAutoRefresh: function(){
- clearInterval(this.autoRefresh);
- delete this.autoRefresh;
- },
- /**
- * Checks whether the loader is automatically refreshing. See {@link #startAutoRefresh}.
- * @return {Boolean} True if the loader is automatically refreshing
- */
- isAutoRefreshing: function(){
- return Ext.isDefined(this.autoRefresh);
- },
- /**
- * Destroys the loader. Any active requests will be aborted.
- */
- destroy: function(){
- var me = this;
- me.stopAutoRefresh();
- delete me.target;
- me.abort();
- me.clearListeners();
- }
- });
- /**
- * @class Ext.ComponentLoader
- * @extends Ext.ElementLoader
- *
- * This class is used to load content via Ajax into a {@link Ext.Component}. In general
- * this class will not be instanced directly, rather a loader configuration will be passed to the
- * constructor of the {@link Ext.Component}.
- *
- * ## HTML Renderer
- * By default, the content loaded will be processed as raw html. The response text
- * from the request is taken and added to the component. This can be used in
- * conjunction with the {@link #scripts} option to execute any inline scripts in
- * the resulting content. Using this renderer has the same effect as passing the
- * {@link Ext.Component#html} configuration option.
- *
- * ## Data Renderer
- * This renderer allows content to be added by using JSON data and a {@link Ext.XTemplate}.
- * The content received from the response is passed to the {@link Ext.Component#update} method.
- * This content is run through the attached {@link Ext.Component#tpl} and the data is added to
- * the Component. Using this renderer has the same effect as using the {@link Ext.Component#data}
- * configuration in conjunction with a {@link Ext.Component#tpl}.
- *
- * ## Component Renderer
- * This renderer can only be used with a {@link Ext.container.Container} and subclasses. It allows for
- * Components to be loaded remotely into a Container. The response is expected to be a single/series of
- * {@link Ext.Component} configuration objects. When the response is received, the data is decoded
- * and then passed to {@link Ext.container.Container#add}. Using this renderer has the same effect as specifying
- * the {@link Ext.container.Container#items} configuration on a Container.
- *
- * ## Custom Renderer
- * A custom function can be passed to handle any other special case, see the {@link #renderer} option.
- *
- * ## Example Usage
- * new Ext.Component({
- * tpl: '{firstName} - {lastName}',
- * loader: {
- * url: 'myPage.php',
- * renderer: 'data',
- * params: {
- * userId: 1
- * }
- * }
- * });
- */
- Ext.define('Ext.ComponentLoader', {
- /* Begin Definitions */
- extend: 'Ext.ElementLoader',
- statics: {
- Renderer: {
- Data: function(loader, response, active){
- var success = true;
- try {
- loader.getTarget().update(Ext.decode(response.responseText));
- } catch (e) {
- success = false;
- }
- return success;
- },
- Component: function(loader, response, active){
- var success = true,
- target = loader.getTarget(),
- items = [];
- //<debug>
- if (!target.isContainer) {
- Ext.Error.raise({
- target: target,
- msg: 'Components can only be loaded into a container'
- });
- }
- //</debug>
- try {
- items = Ext.decode(response.responseText);
- } catch (e) {
- success = false;
- }
- if (success) {
- if (active.removeAll) {
- target.removeAll();
- }
- target.add(items);
- }
- return success;
- }
- }
- },
- /* End Definitions */
- /**
- * @cfg {Ext.Component/String} target The target {@link Ext.Component} for the loader.
- * If a string is passed it will be looked up via the id.
- */
- target: null,
- /**
- * @cfg {Boolean/Object} loadMask True or a {@link Ext.LoadMask} configuration to enable masking during loading.
- */
- loadMask: false,
- /**
- * @cfg {Boolean} scripts True to parse any inline script tags in the response. This only used when using the html
- * {@link #renderer}.
- */
- /**
- * @cfg {String/Function} renderer
- The type of content that is to be loaded into, which can be one of 3 types:
- + **html** : Loads raw html content, see {@link Ext.Component#html}
- + **data** : Loads raw html content, see {@link Ext.Component#data}
- + **component** : Loads child {Ext.Component} instances. This option is only valid when used with a Container.
- Alternatively, you can pass a function which is called with the following parameters.
- + loader - Loader instance
- + response - The server response
- + active - The active request
- The function must return false is loading is not successful. Below is a sample of using a custom renderer:
- new Ext.Component({
- loader: {
- url: 'myPage.php',
- renderer: function(loader, response, active) {
- var text = response.responseText;
- loader.getTarget().update('The response is ' + text);
- return true;
- }
- }
- });
- */
- renderer: 'html',
- /**
- * Set a {Ext.Component} as the target of this loader. Note that if the target is changed,
- * any active requests will be aborted.
- * @param {String/Ext.Component} target The component to be the target of this loader. If a string is passed
- * it will be looked up via its id.
- */
- setTarget: function(target){
- var me = this;
- if (Ext.isString(target)) {
- target = Ext.getCmp(target);
- }
- if (me.target && me.target != target) {
- me.abort();
- }
- me.target = target;
- },
- // inherit docs
- removeMask: function(){
- this.target.setLoading(false);
- },
- /**
- * Add the mask on the target
- * @private
- * @param {Boolean/Object} mask The mask configuration
- */
- addMask: function(mask){
- this.target.setLoading(mask);
- },
- /**
- * Get the target of this loader.
- * @return {Ext.Component} target The target, null if none exists.
- */
- setOptions: function(active, options){
- active.removeAll = Ext.isDefined(options.removeAll) ? options.removeAll : this.removeAll;
- },
- /**
- * Gets the renderer to use
- * @private
- * @param {String/Function} renderer The renderer to use
- * @return {Function} A rendering function to use.
- */
- getRenderer: function(renderer){
- if (Ext.isFunction(renderer)) {
- return renderer;
- }
- var renderers = this.statics().Renderer;
- switch (renderer) {
- case 'component':
- return renderers.Component;
- case 'data':
- return renderers.Data;
- default:
- return Ext.ElementLoader.Renderer.Html;
- }
- }
- });
- /**
- * @author Ed Spencer
- *
- * Associations enable you to express relationships between different {@link Ext.data.Model Models}. Let's say we're
- * writing an ecommerce system where Users can make Orders - there's a relationship between these Models that we can
- * express like this:
- *
- * Ext.define('User', {
- * extend: 'Ext.data.Model',
- * fields: ['id', 'name', 'email'],
- *
- * hasMany: {model: 'Order', name: 'orders'}
- * });
- *
- * Ext.define('Order', {
- * extend: 'Ext.data.Model',
- * fields: ['id', 'user_id', 'status', 'price'],
- *
- * belongsTo: 'User'
- * });
- *
- * We've set up two models - User and Order - and told them about each other. You can set up as many associations on
- * each Model as you need using the two default types - {@link Ext.data.HasManyAssociation hasMany} and {@link
- * Ext.data.BelongsToAssociation belongsTo}. There's much more detail on the usage of each of those inside their
- * documentation pages. If you're not familiar with Models already, {@link Ext.data.Model there is plenty on those too}.
- *
- * **Further Reading**
- *
- * - {@link Ext.data.HasManyAssociation hasMany associations}
- * - {@link Ext.data.BelongsToAssociation belongsTo associations}
- * - {@link Ext.data.Model using Models}
- *
- * # Self association models
- *
- * We can also have models that create parent/child associations between the same type. Below is an example, where
- * groups can be nested inside other groups:
- *
- * // Server Data
- * {
- * "groups": {
- * "id": 10,
- * "parent_id": 100,
- * "name": "Main Group",
- * "parent_group": {
- * "id": 100,
- * "parent_id": null,
- * "name": "Parent Group"
- * },
- * "child_groups": [{
- * "id": 2,
- * "parent_id": 10,
- * "name": "Child Group 1"
- * },{
- * "id": 3,
- * "parent_id": 10,
- * "name": "Child Group 2"
- * },{
- * "id": 4,
- * "parent_id": 10,
- * "name": "Child Group 3"
- * }]
- * }
- * }
- *
- * // Client code
- * Ext.define('Group', {
- * extend: 'Ext.data.Model',
- * fields: ['id', 'parent_id', 'name'],
- * proxy: {
- * type: 'ajax',
- * url: 'data.json',
- * reader: {
- * type: 'json',
- * root: 'groups'
- * }
- * },
- * associations: [{
- * type: 'hasMany',
- * model: 'Group',
- * primaryKey: 'id',
- * foreignKey: 'parent_id',
- * autoLoad: true,
- * associationKey: 'child_groups' // read child data from child_groups
- * }, {
- * type: 'belongsTo',
- * model: 'Group',
- * primaryKey: 'id',
- * foreignKey: 'parent_id',
- * associationKey: 'parent_group' // read parent data from parent_group
- * }]
- * });
- *
- * Ext.onReady(function(){
- *
- * Group.load(10, {
- * success: function(group){
- * console.log(group.getGroup().get('name'));
- *
- * group.groups().each(function(rec){
- * console.log(rec.get('name'));
- * });
- * }
- * });
- *
- * });
- *
- */
- Ext.define('Ext.data.Association', {
- /**
- * @cfg {String} ownerModel (required)
- * The string name of the model that owns the association.
- */
- /**
- * @cfg {String} associatedModel (required)
- * The string name of the model that is being associated with.
- */
- /**
- * @cfg {String} primaryKey
- * The name of the primary key on the associated model. In general this will be the
- * {@link Ext.data.Model#idProperty} of the Model.
- */
- primaryKey: 'id',
- /**
- * @cfg {Ext.data.reader.Reader} reader
- * A special reader to read associated data
- */
-
- /**
- * @cfg {String} associationKey
- * The name of the property in the data to read the association from. Defaults to the name of the associated model.
- */
- defaultReaderType: 'json',
- statics: {
- create: function(association){
- if (!association.isAssociation) {
- if (Ext.isString(association)) {
- association = {
- type: association
- };
- }
- switch (association.type) {
- case 'belongsTo':
- return Ext.create('Ext.data.BelongsToAssociation', association);
- case 'hasMany':
- return Ext.create('Ext.data.HasManyAssociation', association);
- //TODO Add this back when it's fixed
- // case 'polymorphic':
- // return Ext.create('Ext.data.PolymorphicAssociation', association);
- default:
- //<debug>
- Ext.Error.raise('Unknown Association type: "' + association.type + '"');
- //</debug>
- }
- }
- return association;
- }
- },
- /**
- * Creates the Association object.
- * @param {Object} [config] Config object.
- */
- constructor: function(config) {
- Ext.apply(this, config);
- var types = Ext.ModelManager.types,
- ownerName = config.ownerModel,
- associatedName = config.associatedModel,
- ownerModel = types[ownerName],
- associatedModel = types[associatedName],
- ownerProto;
- //<debug>
- if (ownerModel === undefined) {
- Ext.Error.raise("The configured ownerModel was not valid (you tried " + ownerName + ")");
- }
- if (associatedModel === undefined) {
- Ext.Error.raise("The configured associatedModel was not valid (you tried " + associatedName + ")");
- }
- //</debug>
- this.ownerModel = ownerModel;
- this.associatedModel = associatedModel;
- /**
- * @property {String} ownerName
- * The name of the model that 'owns' the association
- */
- /**
- * @property {String} associatedName
- * The name of the model is on the other end of the association (e.g. if a User model hasMany Orders, this is
- * 'Order')
- */
- Ext.applyIf(this, {
- ownerName : ownerName,
- associatedName: associatedName
- });
- },
- /**
- * Get a specialized reader for reading associated data
- * @return {Ext.data.reader.Reader} The reader, null if not supplied
- */
- getReader: function(){
- var me = this,
- reader = me.reader,
- model = me.associatedModel;
- if (reader) {
- if (Ext.isString(reader)) {
- reader = {
- type: reader
- };
- }
- if (reader.isReader) {
- reader.setModel(model);
- } else {
- Ext.applyIf(reader, {
- model: model,
- type : me.defaultReaderType
- });
- }
- me.reader = Ext.createByAlias('reader.' + reader.type, reader);
- }
- return me.reader || null;
- }
- });
- /**
- * @author Ed Spencer
- * @class Ext.ModelManager
- * @extends Ext.AbstractManager
- The ModelManager keeps track of all {@link Ext.data.Model} types defined in your application.
- __Creating Model Instances__
- Model instances can be created by using the {@link Ext#create Ext.create} method. Ext.create replaces
- the deprecated {@link #create Ext.ModelManager.create} method. It is also possible to create a model instance
- this by using the Model type directly. The following 3 snippets are equivalent:
- Ext.define('User', {
- extend: 'Ext.data.Model',
- fields: ['first', 'last']
- });
- // method 1, create using Ext.create (recommended)
- Ext.create('User', {
- first: 'Ed',
- last: 'Spencer'
- });
- // method 2, create through the manager (deprecated)
- Ext.ModelManager.create({
- first: 'Ed',
- last: 'Spencer'
- }, 'User');
- // method 3, create on the type directly
- new User({
- first: 'Ed',
- last: 'Spencer'
- });
- __Accessing Model Types__
- A reference to a Model type can be obtained by using the {@link #getModel} function. Since models types
- are normal classes, you can access the type directly. The following snippets are equivalent:
- Ext.define('User', {
- extend: 'Ext.data.Model',
- fields: ['first', 'last']
- });
- // method 1, access model type through the manager
- var UserType = Ext.ModelManager.getModel('User');
- // method 2, reference the type directly
- var UserType = User;
- * @markdown
- * @singleton
- */
- Ext.define('Ext.ModelManager', {
- extend: 'Ext.AbstractManager',
- alternateClassName: 'Ext.ModelMgr',
- requires: ['Ext.data.Association'],
- singleton: true,
- typeName: 'mtype',
- /**
- * Private stack of associations that must be created once their associated model has been defined
- * @property {Ext.data.Association[]} associationStack
- */
- associationStack: [],
- /**
- * Registers a model definition. All model plugins marked with isDefault: true are bootstrapped
- * immediately, as are any addition plugins defined in the model config.
- * @private
- */
- registerType: function(name, config) {
- var proto = config.prototype,
- model;
- if (proto && proto.isModel) {
- // registering an already defined model
- model = config;
- } else {
- // passing in a configuration
- if (!config.extend) {
- config.extend = 'Ext.data.Model';
- }
- model = Ext.define(name, config);
- }
- this.types[name] = model;
- return model;
- },
- /**
- * @private
- * Private callback called whenever a model has just been defined. This sets up any associations
- * that were waiting for the given model to be defined
- * @param {Function} model The model that was just created
- */
- onModelDefined: function(model) {
- var stack = this.associationStack,
- length = stack.length,
- create = [],
- association, i, created;
- for (i = 0; i < length; i++) {
- association = stack[i];
- if (association.associatedModel == model.modelName) {
- create.push(association);
- }
- }
- for (i = 0, length = create.length; i < length; i++) {
- created = create[i];
- this.types[created.ownerModel].prototype.associations.add(Ext.data.Association.create(created));
- Ext.Array.remove(stack, created);
- }
- },
- /**
- * Registers an association where one of the models defined doesn't exist yet.
- * The ModelManager will check when new models are registered if it can link them
- * together
- * @private
- * @param {Ext.data.Association} association The association
- */
- registerDeferredAssociation: function(association){
- this.associationStack.push(association);
- },
- /**
- * Returns the {@link Ext.data.Model} for a given model name
- * @param {String/Object} id The id of the model or the model instance.
- * @return {Ext.data.Model} a model class.
- */
- getModel: function(id) {
- var model = id;
- if (typeof model == 'string') {
- model = this.types[model];
- }
- return model;
- },
- /**
- * Creates a new instance of a Model using the given data.
- *
- * This method is deprecated. Use {@link Ext#create Ext.create} instead. For example:
- *
- * Ext.create('User', {
- * first: 'Ed',
- * last: 'Spencer'
- * });
- *
- * @param {Object} data Data to initialize the Model's fields with
- * @param {String} name The name of the model to create
- * @param {Number} id (Optional) unique id of the Model instance (see {@link Ext.data.Model})
- */
- create: function(config, name, id) {
- var con = typeof name == 'function' ? name : this.types[name || config.name];
- return new con(config, id);
- }
- }, function() {
- /**
- * Old way for creating Model classes. Instead use:
- *
- * Ext.define("MyModel", {
- * extend: "Ext.data.Model",
- * fields: []
- * });
- *
- * @param {String} name Name of the Model class.
- * @param {Object} config A configuration object for the Model you wish to create.
- * @return {Ext.data.Model} The newly registered Model
- * @member Ext
- * @deprecated 4.0.0 Use {@link Ext#define} instead.
- */
- Ext.regModel = function() {
- //<debug>
- if (Ext.isDefined(Ext.global.console)) {
- Ext.global.console.warn('Ext.regModel has been deprecated. Models can now be created by extending Ext.data.Model: Ext.define("MyModel", {extend: "Ext.data.Model", fields: []});.');
- }
- //</debug>
- return this.ModelManager.registerType.apply(this.ModelManager, arguments);
- };
- });
- /**
- * @singleton
- *
- * Provides a registry of available Plugin classes indexed by a mnemonic code known as the Plugin's ptype.
- *
- * A plugin may be specified simply as a *config object* as long as the correct `ptype` is specified:
- *
- * {
- * ptype: 'gridviewdragdrop',
- * dragText: 'Drag and drop to reorganize'
- * }
- *
- * Or just use the ptype on its own:
- *
- * 'gridviewdragdrop'
- *
- * Alternatively you can instantiate the plugin with Ext.create:
- *
- * Ext.create('Ext.view.plugin.AutoComplete', {
- * ptype: 'gridviewdragdrop',
- * dragText: 'Drag and drop to reorganize'
- * })
- */
- Ext.define('Ext.PluginManager', {
- extend: 'Ext.AbstractManager',
- alternateClassName: 'Ext.PluginMgr',
- singleton: true,
- typeName: 'ptype',
- /**
- * Creates a new Plugin from the specified config object using the config object's ptype to determine the class to
- * instantiate.
- * @param {Object} config A configuration object for the Plugin you wish to create.
- * @param {Function} defaultType (optional) The constructor to provide the default Plugin type if the config object does not
- * contain a `ptype`. (Optional if the config contains a `ptype`).
- * @return {Ext.Component} The newly instantiated Plugin.
- */
- //create: function(plugin, defaultType) {
- // if (plugin instanceof this) {
- // return plugin;
- // } else {
- // var type, config = {};
- //
- // if (Ext.isString(plugin)) {
- // type = plugin;
- // }
- // else {
- // type = plugin[this.typeName] || defaultType;
- // config = plugin;
- // }
- //
- // return Ext.createByAlias('plugin.' + type, config);
- // }
- //},
- create : function(config, defaultType){
- if (config.init) {
- return config;
- } else {
- return Ext.createByAlias('plugin.' + (config.ptype || defaultType), config);
- }
- // Prior system supported Singleton plugins.
- //var PluginCls = this.types[config.ptype || defaultType];
- //if (PluginCls.init) {
- // return PluginCls;
- //} else {
- // return new PluginCls(config);
- //}
- },
- /**
- * Returns all plugins registered with the given type. Here, 'type' refers to the type of plugin, not its ptype.
- * @param {String} type The type to search for
- * @param {Boolean} defaultsOnly True to only return plugins of this type where the plugin's isDefault property is
- * truthy
- * @return {Ext.AbstractPlugin[]} All matching plugins
- */
- findByType: function(type, defaultsOnly) {
- var matches = [],
- types = this.types;
- for (var name in types) {
- if (!types.hasOwnProperty(name)) {
- continue;
- }
- var item = types[name];
- if (item.type == type && (!defaultsOnly || (defaultsOnly === true && item.isDefault))) {
- matches.push(item);
- }
- }
- return matches;
- }
- }, function() {
- /**
- * Shorthand for {@link Ext.PluginManager#registerType}
- * @param {String} ptype The ptype mnemonic string by which the Plugin class
- * may be looked up.
- * @param {Function} cls The new Plugin class.
- * @member Ext
- * @method preg
- */
- Ext.preg = function() {
- return Ext.PluginManager.registerType.apply(Ext.PluginManager, arguments);
- };
- });
- /**
- * Represents an HTML fragment template. Templates may be {@link #compile precompiled} for greater performance.
- *
- * An instance of this class may be created by passing to the constructor either a single argument, or multiple
- * arguments:
- *
- * # Single argument: String/Array
- *
- * The single argument may be either a String or an Array:
- *
- * - String:
- *
- * var t = new Ext.Template("<div>Hello {0}.</div>");
- * t.{@link #append}('some-element', ['foo']);
- *
- * - Array:
- *
- * An Array will be combined with `join('')`.
- *
- * var t = new Ext.Template([
- * '<div name="{id}">',
- * '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
- * '</div>',
- * ]);
- * t.{@link #compile}();
- * t.{@link #append}('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
- *
- * # Multiple arguments: String, Object, Array, ...
- *
- * Multiple arguments will be combined with `join('')`.
- *
- * var t = new Ext.Template(
- * '<div name="{id}">',
- * '<span class="{cls}">{name} {value}</span>',
- * '</div>',
- * // a configuration object:
- * {
- * compiled: true, // {@link #compile} immediately
- * }
- * );
- *
- * # Notes
- *
- * - For a list of available format functions, see {@link Ext.util.Format}.
- * - `disableFormats` reduces `{@link #apply}` time when no formatting is required.
- */
- Ext.define('Ext.Template', {
- /* Begin Definitions */
- requires: ['Ext.DomHelper', 'Ext.util.Format'],
- inheritableStatics: {
- /**
- * Creates a template from the passed element's value (_display:none_ textarea, preferred) or innerHTML.
- * @param {String/HTMLElement} el A DOM element or its id
- * @param {Object} config (optional) Config object
- * @return {Ext.Template} The created template
- * @static
- * @inheritable
- */
- from: function(el, config) {
- el = Ext.getDom(el);
- return new this(el.value || el.innerHTML, config || '');
- }
- },
- /* End Definitions */
- /**
- * Creates new template.
- *
- * @param {String...} html List of strings to be concatenated into template.
- * Alternatively an array of strings can be given, but then no config object may be passed.
- * @param {Object} config (optional) Config object
- */
- constructor: function(html) {
- var me = this,
- args = arguments,
- buffer = [],
- i = 0,
- length = args.length,
- value;
- me.initialConfig = {};
- if (length > 1) {
- for (; i < length; i++) {
- value = args[i];
- if (typeof value == 'object') {
- Ext.apply(me.initialConfig, value);
- Ext.apply(me, value);
- } else {
- buffer.push(value);
- }
- }
- html = buffer.join('');
- } else {
- if (Ext.isArray(html)) {
- buffer.push(html.join(''));
- } else {
- buffer.push(html);
- }
- }
- // @private
- me.html = buffer.join('');
- if (me.compiled) {
- me.compile();
- }
- },
- isTemplate: true,
- /**
- * @cfg {Boolean} compiled
- * True to immediately compile the template. Defaults to false.
- */
- /**
- * @cfg {Boolean} disableFormats
- * True to disable format functions in the template. If the template doesn't contain
- * format functions, setting disableFormats to true will reduce apply time. Defaults to false.
- */
- disableFormats: false,
- re: /\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
- /**
- * Returns an HTML fragment of this template with the specified values applied.
- *
- * @param {Object/Array} values The template values. Can be an array if your params are numeric:
- *
- * var tpl = new Ext.Template('Name: {0}, Age: {1}');
- * tpl.applyTemplate(['John', 25]);
- *
- * or an object:
- *
- * var tpl = new Ext.Template('Name: {name}, Age: {age}');
- * tpl.applyTemplate({name: 'John', age: 25});
- *
- * @return {String} The HTML fragment
- */
- applyTemplate: function(values) {
- var me = this,
- useFormat = me.disableFormats !== true,
- fm = Ext.util.Format,
- tpl = me;
- if (me.compiled) {
- return me.compiled(values);
- }
- function fn(m, name, format, args) {
- if (format && useFormat) {
- if (args) {
- args = [values[name]].concat(Ext.functionFactory('return ['+ args +'];')());
- } else {
- args = [values[name]];
- }
- if (format.substr(0, 5) == "this.") {
- return tpl[format.substr(5)].apply(tpl, args);
- }
- else {
- return fm[format].apply(fm, args);
- }
- }
- else {
- return values[name] !== undefined ? values[name] : "";
- }
- }
- return me.html.replace(me.re, fn);
- },
- /**
- * Sets the HTML used as the template and optionally compiles it.
- * @param {String} html
- * @param {Boolean} compile (optional) True to compile the template.
- * @return {Ext.Template} this
- */
- set: function(html, compile) {
- var me = this;
- me.html = html;
- me.compiled = null;
- return compile ? me.compile() : me;
- },
- compileARe: /\\/g,
- compileBRe: /(\r\n|\n)/g,
- compileCRe: /'/g,
- /**
- * Compiles the template into an internal function, eliminating the RegEx overhead.
- * @return {Ext.Template} this
- */
- compile: function() {
- var me = this,
- fm = Ext.util.Format,
- useFormat = me.disableFormats !== true,
- body, bodyReturn;
- function fn(m, name, format, args) {
- if (format && useFormat) {
- args = args ? ',' + args: "";
- if (format.substr(0, 5) != "this.") {
- format = "fm." + format + '(';
- }
- else {
- format = 'this.' + format.substr(5) + '(';
- }
- }
- else {
- args = '';
- format = "(values['" + name + "'] == undefined ? '' : ";
- }
- return "'," + format + "values['" + name + "']" + args + ") ,'";
- }
- bodyReturn = me.html.replace(me.compileARe, '\\\\').replace(me.compileBRe, '\\n').replace(me.compileCRe, "\\'").replace(me.re, fn);
- body = "this.compiled = function(values){ return ['" + bodyReturn + "'].join('');};";
- eval(body);
- return me;
- },
- /**
- * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
- *
- * @param {String/HTMLElement/Ext.Element} el The context element
- * @param {Object/Array} values The template values. See {@link #applyTemplate} for details.
- * @param {Boolean} returnElement (optional) true to return a Ext.Element.
- * @return {HTMLElement/Ext.Element} The new node or Element
- */
- insertFirst: function(el, values, returnElement) {
- return this.doInsert('afterBegin', el, values, returnElement);
- },
- /**
- * Applies the supplied values to the template and inserts the new node(s) before el.
- *
- * @param {String/HTMLElement/Ext.Element} el The context element
- * @param {Object/Array} values The template values. See {@link #applyTemplate} for details.
- * @param {Boolean} returnElement (optional) true to return a Ext.Element.
- * @return {HTMLElement/Ext.Element} The new node or Element
- */
- insertBefore: function(el, values, returnElement) {
- return this.doInsert('beforeBegin', el, values, returnElement);
- },
- /**
- * Applies the supplied values to the template and inserts the new node(s) after el.
- *
- * @param {String/HTMLElement/Ext.Element} el The context element
- * @param {Object/Array} values The template values. See {@link #applyTemplate} for details.
- * @param {Boolean} returnElement (optional) true to return a Ext.Element.
- * @return {HTMLElement/Ext.Element} The new node or Element
- */
- insertAfter: function(el, values, returnElement) {
- return this.doInsert('afterEnd', el, values, returnElement);
- },
- /**
- * Applies the supplied `values` to the template and appends the new node(s) to the specified `el`.
- *
- * For example usage see {@link Ext.Template Ext.Template class docs}.
- *
- * @param {String/HTMLElement/Ext.Element} el The context element
- * @param {Object/Array} values The template values. See {@link #applyTemplate} for details.
- * @param {Boolean} returnElement (optional) true to return an Ext.Element.
- * @return {HTMLElement/Ext.Element} The new node or Element
- */
- append: function(el, values, returnElement) {
- return this.doInsert('beforeEnd', el, values, returnElement);
- },
- doInsert: function(where, el, values, returnEl) {
- el = Ext.getDom(el);
- var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));
- return returnEl ? Ext.get(newNode, true) : newNode;
- },
- /**
- * Applies the supplied values to the template and overwrites the content of el with the new node(s).
- *
- * @param {String/HTMLElement/Ext.Element} el The context element
- * @param {Object/Array} values The template values. See {@link #applyTemplate} for details.
- * @param {Boolean} returnElement (optional) true to return a Ext.Element.
- * @return {HTMLElement/Ext.Element} The new node or Element
- */
- overwrite: function(el, values, returnElement) {
- el = Ext.getDom(el);
- el.innerHTML = this.applyTemplate(values);
- return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
- }
- }, function() {
- /**
- * @method apply
- * @member Ext.Template
- * Alias for {@link #applyTemplate}.
- * @alias Ext.Template#applyTemplate
- */
- this.createAlias('apply', 'applyTemplate');
- });
- /**
- * A template class that supports advanced functionality like:
- *
- * - Autofilling arrays using templates and sub-templates
- * - Conditional processing with basic comparison operators
- * - Basic math function support
- * - Execute arbitrary inline code with special built-in template variables
- * - Custom member functions
- * - Many special tags and built-in operators that aren't defined as part of the API, but are supported in the templates that can be created
- *
- * XTemplate provides the templating mechanism built into:
- *
- * - {@link Ext.view.View}
- *
- * The {@link Ext.Template} describes the acceptable parameters to pass to the constructor. The following examples
- * demonstrate all of the supported features.
- *
- * # Sample Data
- *
- * This is the data object used for reference in each code example:
- *
- * var data = {
- * name: 'Tommy Maintz',
- * title: 'Lead Developer',
- * company: 'Sencha Inc.',
- * email: 'tommy@sencha.com',
- * address: '5 Cups Drive',
- * city: 'Palo Alto',
- * state: 'CA',
- * zip: '44102',
- * drinks: ['Coffee', 'Soda', 'Water'],
- * kids: [
- * {
- * name: 'Joshua',
- * age:3
- * },
- * {
- * name: 'Matthew',
- * age:2
- * },
- * {
- * name: 'Solomon',
- * age:0
- * }
- * ]
- * };
- *
- * # Auto filling of arrays
- *
- * The **tpl** tag and the **for** operator are used to process the provided data object:
- *
- * - If the value specified in for is an array, it will auto-fill, repeating the template block inside the tpl
- * tag for each item in the array.
- * - If for="." is specified, the data object provided is examined.
- * - While processing an array, the special variable {#} will provide the current array index + 1 (starts at 1, not 0).
- *
- * Examples:
- *
- * <tpl for=".">...</tpl> // loop through array at root node
- * <tpl for="foo">...</tpl> // loop through array at foo node
- * <tpl for="foo.bar">...</tpl> // loop through array at foo.bar node
- *
- * Using the sample data above:
- *
- * var tpl = new Ext.XTemplate(
- * '<p>Kids: ',
- * '<tpl for=".">', // process the data.kids node
- * '<p>{#}. {name}</p>', // use current array index to autonumber
- * '</tpl></p>'
- * );
- * tpl.overwrite(panel.body, data.kids); // pass the kids property of the data object
- *
- * An example illustrating how the **for** property can be leveraged to access specified members of the provided data
- * object to populate the template:
- *
- * var tpl = new Ext.XTemplate(
- * '<p>Name: {name}</p>',
- * '<p>Title: {title}</p>',
- * '<p>Company: {company}</p>',
- * '<p>Kids: ',
- * '<tpl for="kids">', // interrogate the kids property within the data
- * '<p>{name}</p>',
- * '</tpl></p>'
- * );
- * tpl.overwrite(panel.body, data); // pass the root node of the data object
- *
- * Flat arrays that contain values (and not objects) can be auto-rendered using the special **`{.}`** variable inside a
- * loop. This variable will represent the value of the array at the current index:
- *
- * var tpl = new Ext.XTemplate(
- * '<p>{name}\'s favorite beverages:</p>',
- * '<tpl for="drinks">',
- * '<div> - {.}</div>',
- * '</tpl>'
- * );
- * tpl.overwrite(panel.body, data);
- *
- * When processing a sub-template, for example while looping through a child array, you can access the parent object's
- * members via the **parent** object:
- *
- * var tpl = new Ext.XTemplate(
- * '<p>Name: {name}</p>',
- * '<p>Kids: ',
- * '<tpl for="kids">',
- * '<tpl if="age > 1">',
- * '<p>{name}</p>',
- * '<p>Dad: {parent.name}</p>',
- * '</tpl>',
- * '</tpl></p>'
- * );
- * tpl.overwrite(panel.body, data);
- *
- * # Conditional processing with basic comparison operators
- *
- * The **tpl** tag and the **if** operator are used to provide conditional checks for deciding whether or not to render
- * specific parts of the template. Notes:
- *
- * - Double quotes must be encoded if used within the conditional
- * - There is no else operator -- if needed, two opposite if statements should be used.
- *
- * Examples:
- *
- * <tpl if="age > 1 && age < 10">Child</tpl>
- * <tpl if="age >= 10 && age < 18">Teenager</tpl>
- * <tpl if="this.isGirl(name)">...</tpl>
- * <tpl if="id==\'download\'">...</tpl>
- * <tpl if="needsIcon"><img src="{icon}" class="{iconCls}"/></tpl>
- * // no good:
- * <tpl if="name == "Tommy"">Hello</tpl>
- * // encode " if it is part of the condition, e.g.
- * <tpl if="name == "Tommy"">Hello</tpl>
- *
- * Using the sample data above:
- *
- * var tpl = new Ext.XTemplate(
- * '<p>Name: {name}</p>',
- * '<p>Kids: ',
- * '<tpl for="kids">',
- * '<tpl if="age > 1">',
- * '<p>{name}</p>',
- * '</tpl>',
- * '</tpl></p>'
- * );
- * tpl.overwrite(panel.body, data);
- *
- * # Basic math support
- *
- * The following basic math operators may be applied directly on numeric data values:
- *
- * + - * /
- *
- * For example:
- *
- * var tpl = new Ext.XTemplate(
- * '<p>Name: {name}</p>',
- * '<p>Kids: ',
- * '<tpl for="kids">',
- * '<tpl if="age > 1">', // <-- Note that the > is encoded
- * '<p>{#}: {name}</p>', // <-- Auto-number each item
- * '<p>In 5 Years: {age+5}</p>', // <-- Basic math
- * '<p>Dad: {parent.name}</p>',
- * '</tpl>',
- * '</tpl></p>'
- * );
- * tpl.overwrite(panel.body, data);
- *
- * # Execute arbitrary inline code with special built-in template variables
- *
- * Anything between `{[ ... ]}` is considered code to be executed in the scope of the template. There are some special
- * variables available in that code:
- *
- * - **values**: The values in the current scope. If you are using scope changing sub-templates,
- * you can change what values is.
- * - **parent**: The scope (values) of the ancestor template.
- * - **xindex**: If you are in a looping template, the index of the loop you are in (1-based).
- * - **xcount**: If you are in a looping template, the total length of the array you are looping.
- *
- * This example demonstrates basic row striping using an inline code block and the xindex variable:
- *
- * var tpl = new Ext.XTemplate(
- * '<p>Name: {name}</p>',
- * '<p>Company: {[values.company.toUpperCase() + ", " + values.title]}</p>',
- * '<p>Kids: ',
- * '<tpl for="kids">',
- * '<div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',
- * '{name}',
- * '</div>',
- * '</tpl></p>'
- * );
- * tpl.overwrite(panel.body, data);
- *
- * # Template member functions
- *
- * One or more member functions can be specified in a configuration object passed into the XTemplate constructor for
- * more complex processing:
- *
- * var tpl = new Ext.XTemplate(
- * '<p>Name: {name}</p>',
- * '<p>Kids: ',
- * '<tpl for="kids">',
- * '<tpl if="this.isGirl(name)">',
- * '<p>Girl: {name} - {age}</p>',
- * '</tpl>',
- * // use opposite if statement to simulate 'else' processing:
- * '<tpl if="this.isGirl(name) == false">',
- * '<p>Boy: {name} - {age}</p>',
- * '</tpl>',
- * '<tpl if="this.isBaby(age)">',
- * '<p>{name} is a baby!</p>',
- * '</tpl>',
- * '</tpl></p>',
- * {
- * // XTemplate configuration:
- * disableFormats: true,
- * // member functions:
- * isGirl: function(name){
- * return name == 'Sara Grace';
- * },
- * isBaby: function(age){
- * return age < 1;
- * }
- * }
- * );
- * tpl.overwrite(panel.body, data);
- */
- Ext.define('Ext.XTemplate', {
- /* Begin Definitions */
- extend: 'Ext.Template',
- /* End Definitions */
- argsRe: /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
- nameRe: /^<tpl\b[^>]*?for="(.*?)"/,
- ifRe: /^<tpl\b[^>]*?if="(.*?)"/,
- execRe: /^<tpl\b[^>]*?exec="(.*?)"/,
- constructor: function() {
- this.callParent(arguments);
- var me = this,
- html = me.html,
- argsRe = me.argsRe,
- nameRe = me.nameRe,
- ifRe = me.ifRe,
- execRe = me.execRe,
- id = 0,
- tpls = [],
- VALUES = 'values',
- PARENT = 'parent',
- XINDEX = 'xindex',
- XCOUNT = 'xcount',
- RETURN = 'return ',
- WITHVALUES = 'with(values){ ',
- m, matchName, matchIf, matchExec, exp, fn, exec, name, i;
- html = ['<tpl>', html, '</tpl>'].join('');
- while ((m = html.match(argsRe))) {
- exp = null;
- fn = null;
- exec = null;
- matchName = m[0].match(nameRe);
- matchIf = m[0].match(ifRe);
- matchExec = m[0].match(execRe);
- exp = matchIf ? matchIf[1] : null;
- if (exp) {
- fn = Ext.functionFactory(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + 'try{' + RETURN + Ext.String.htmlDecode(exp) + ';}catch(e){return;}}');
- }
- exp = matchExec ? matchExec[1] : null;
- if (exp) {
- exec = Ext.functionFactory(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + Ext.String.htmlDecode(exp) + ';}');
- }
- name = matchName ? matchName[1] : null;
- if (name) {
- if (name === '.') {
- name = VALUES;
- } else if (name === '..') {
- name = PARENT;
- }
- name = Ext.functionFactory(VALUES, PARENT, 'try{' + WITHVALUES + RETURN + name + ';}}catch(e){return;}');
- }
- tpls.push({
- id: id,
- target: name,
- exec: exec,
- test: fn,
- body: m[1] || ''
- });
- html = html.replace(m[0], '{xtpl' + id + '}');
- id = id + 1;
- }
- for (i = tpls.length - 1; i >= 0; --i) {
- me.compileTpl(tpls[i]);
- }
- me.master = tpls[tpls.length - 1];
- me.tpls = tpls;
- },
- // @private
- applySubTemplate: function(id, values, parent, xindex, xcount) {
- var me = this, t = me.tpls[id];
- return t.compiled.call(me, values, parent, xindex, xcount);
- },
- /**
- * @cfg {RegExp} codeRe
- * The regular expression used to match code variables. Default: matches {[expression]}.
- */
- codeRe: /\{\[((?:\\\]|.|\n)*?)\]\}/g,
- /**
- * @cfg {Boolean} compiled
- * Only applies to {@link Ext.Template}, XTemplates are compiled automatically.
- */
- re: /\{([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\/]\s?[\d\.\+\-\*\/\(\)]+)?\}/g,
- // @private
- compileTpl: function(tpl) {
- var fm = Ext.util.Format,
- me = this,
- useFormat = me.disableFormats !== true,
- body, bodyReturn, evaluatedFn;
- function fn(m, name, format, args, math) {
- var v;
- // name is what is inside the {}
- // Name begins with xtpl, use a Sub Template
- if (name.substr(0, 4) == 'xtpl') {
- return "',this.applySubTemplate(" + name.substr(4) + ", values, parent, xindex, xcount),'";
- }
- // name = "." - Just use the values object.
- if (name == '.') {
- // filter to not include arrays/objects/nulls
- v = 'Ext.Array.indexOf(["string", "number", "boolean"], typeof values) > -1 || Ext.isDate(values) ? values : ""';
- }
- // name = "#" - Use the xindex
- else if (name == '#') {
- v = 'xindex';
- }
- else if (name.substr(0, 7) == "parent.") {
- v = name;
- }
- // name has a . in it - Use object literal notation, starting from values
- else if (name.indexOf('.') != -1) {
- v = "values." + name;
- }
- // name is a property of values
- else {
- v = "values['" + name + "']";
- }
- if (math) {
- v = '(' + v + math + ')';
- }
- if (format && useFormat) {
- args = args ? ',' + args : "";
- if (format.substr(0, 5) != "this.") {
- format = "fm." + format + '(';
- }
- else {
- format = 'this.' + format.substr(5) + '(';
- }
- }
- else {
- args = '';
- format = "(" + v + " === undefined ? '' : ";
- }
- return "'," + format + v + args + "),'";
- }
- function codeFn(m, code) {
- // Single quotes get escaped when the template is compiled, however we want to undo this when running code.
- return "',(" + code.replace(me.compileARe, "'") + "),'";
- }
- bodyReturn = tpl.body.replace(me.compileBRe, '\\n').replace(me.compileCRe, "\\'").replace(me.re, fn).replace(me.codeRe, codeFn);
- body = "evaluatedFn = function(values, parent, xindex, xcount){return ['" + bodyReturn + "'].join('');};";
- eval(body);
- tpl.compiled = function(values, parent, xindex, xcount) {
- var vs,
- length,
- buffer,
- i;
- if (tpl.test && !tpl.test.call(me, values, parent, xindex, xcount)) {
- return '';
- }
- vs = tpl.target ? tpl.target.call(me, values, parent) : values;
- if (!vs) {
- return '';
- }
- parent = tpl.target ? values : parent;
- if (tpl.target && Ext.isArray(vs)) {
- buffer = [];
- length = vs.length;
- if (tpl.exec) {
- for (i = 0; i < length; i++) {
- buffer[buffer.length] = evaluatedFn.call(me, vs[i], parent, i + 1, length);
- tpl.exec.call(me, vs[i], parent, i + 1, length);
- }
- } else {
- for (i = 0; i < length; i++) {
- buffer[buffer.length] = evaluatedFn.call(me, vs[i], parent, i + 1, length);
- }
- }
- return buffer.join('');
- }
- if (tpl.exec) {
- tpl.exec.call(me, vs, parent, xindex, xcount);
- }
- return evaluatedFn.call(me, vs, parent, xindex, xcount);
- };
- return this;
- },
- // inherit docs from Ext.Template
- applyTemplate: function(values) {
- return this.master.compiled.call(this, values, {}, 1, 1);
- },
- /**
- * Does nothing. XTemplates are compiled automatically, so this function simply returns this.
- * @return {Ext.XTemplate} this
- */
- compile: function() {
- return this;
- }
- }, function() {
- // re-create the alias, inheriting it from Ext.Template doesn't work as intended.
- this.createAlias('apply', 'applyTemplate');
- });
- /**
- * @class Ext.app.Controller
- *
- * Controllers are the glue that binds an application together. All they really do is listen for events (usually from
- * views) and take some action. Here's how we might create a Controller to manage Users:
- *
- * Ext.define('MyApp.controller.Users', {
- * extend: 'Ext.app.Controller',
- *
- * init: function() {
- * console.log('Initialized Users! This happens before the Application launch function is called');
- * }
- * });
- *
- * The init function is a special method that is called when your application boots. It is called before the
- * {@link Ext.app.Application Application}'s launch function is executed so gives a hook point to run any code before
- * your Viewport is created.
- *
- * The init function is a great place to set up how your controller interacts with the view, and is usually used in
- * conjunction with another Controller function - {@link Ext.app.Controller#control control}. The control function
- * makes it easy to listen to events on your view classes and take some action with a handler function. Let's update
- * our Users controller to tell us when the panel is rendered:
- *
- * Ext.define('MyApp.controller.Users', {
- * extend: 'Ext.app.Controller',
- *
- * init: function() {
- * this.control({
- * 'viewport > panel': {
- * render: this.onPanelRendered
- * }
- * });
- * },
- *
- * onPanelRendered: function() {
- * console.log('The panel was rendered');
- * }
- * });
- *
- * We've updated the init function to use this.control to set up listeners on views in our application. The control
- * function uses the new ComponentQuery engine to quickly and easily get references to components on the page. If you
- * are not familiar with ComponentQuery yet, be sure to check out the {@link Ext.ComponentQuery documentation}. In brief though,
- * it allows us to pass a CSS-like selector that will find every matching component on the page.
- *
- * In our init function above we supplied 'viewport > panel', which translates to "find me every Panel that is a direct
- * child of a Viewport". We then supplied an object that maps event names (just 'render' in this case) to handler
- * functions. The overall effect is that whenever any component that matches our selector fires a 'render' event, our
- * onPanelRendered function is called.
- *
- * <u>Using refs</u>
- *
- * One of the most useful parts of Controllers is the new ref system. These use the new {@link Ext.ComponentQuery} to
- * make it really easy to get references to Views on your page. Let's look at an example of this now:
- *
- * Ext.define('MyApp.controller.Users', {
- * extend: 'Ext.app.Controller',
- *
- * refs: [
- * {
- * ref: 'list',
- * selector: 'grid'
- * }
- * ],
- *
- * init: function() {
- * this.control({
- * 'button': {
- * click: this.refreshGrid
- * }
- * });
- * },
- *
- * refreshGrid: function() {
- * this.getList().store.load();
- * }
- * });
- *
- * This example assumes the existence of a {@link Ext.grid.Panel Grid} on the page, which contains a single button to
- * refresh the Grid when clicked. In our refs array, we set up a reference to the grid. There are two parts to this -
- * the 'selector', which is a {@link Ext.ComponentQuery ComponentQuery} selector which finds any grid on the page and
- * assigns it to the reference 'list'.
- *
- * By giving the reference a name, we get a number of things for free. The first is the getList function that we use in
- * the refreshGrid method above. This is generated automatically by the Controller based on the name of our ref, which
- * was capitalized and prepended with get to go from 'list' to 'getList'.
- *
- * The way this works is that the first time getList is called by your code, the ComponentQuery selector is run and the
- * first component that matches the selector ('grid' in this case) will be returned. All future calls to getList will
- * use a cached reference to that grid. Usually it is advised to use a specific ComponentQuery selector that will only
- * match a single View in your application (in the case above our selector will match any grid on the page).
- *
- * Bringing it all together, our init function is called when the application boots, at which time we call this.control
- * to listen to any click on a {@link Ext.button.Button button} and call our refreshGrid function (again, this will
- * match any button on the page so we advise a more specific selector than just 'button', but have left it this way for
- * simplicity). When the button is clicked we use out getList function to refresh the grid.
- *
- * You can create any number of refs and control any number of components this way, simply adding more functions to
- * your Controller as you go. For an example of real-world usage of Controllers see the Feed Viewer example in the
- * examples/app/feed-viewer folder in the SDK download.
- *
- * <u>Generated getter methods</u>
- *
- * Refs aren't the only thing that generate convenient getter methods. Controllers often have to deal with Models and
- * Stores so the framework offers a couple of easy ways to get access to those too. Let's look at another example:
- *
- * Ext.define('MyApp.controller.Users', {
- * extend: 'Ext.app.Controller',
- *
- * models: ['User'],
- * stores: ['AllUsers', 'AdminUsers'],
- *
- * init: function() {
- * var User = this.getUserModel(),
- * allUsers = this.getAllUsersStore();
- *
- * var ed = new User({name: 'Ed'});
- * allUsers.add(ed);
- * }
- * });
- *
- * By specifying Models and Stores that the Controller cares about, it again dynamically loads them from the appropriate
- * locations (app/model/User.js, app/store/AllUsers.js and app/store/AdminUsers.js in this case) and creates getter
- * functions for them all. The example above will create a new User model instance and add it to the AllUsers Store.
- * Of course, you could do anything in this function but in this case we just did something simple to demonstrate the
- * functionality.
- *
- * <u>Further Reading</u>
- *
- * For more information about writing Ext JS 4 applications, please see the
- * [application architecture guide](#/guide/application_architecture). Also see the {@link Ext.app.Application} documentation.
- *
- * @docauthor Ed Spencer
- */
- Ext.define('Ext.app.Controller', {
- mixins: {
- observable: 'Ext.util.Observable'
- },
- /**
- * @cfg {String} id The id of this controller. You can use this id when dispatching.
- */
-
- /**
- * @cfg {String[]} models
- * Array of models to require from AppName.model namespace. For example:
- *
- * Ext.define("MyApp.controller.Foo", {
- * extend: "Ext.app.Controller",
- * models: ['User', 'Vehicle']
- * });
- *
- * This is equivalent of:
- *
- * Ext.define("MyApp.controller.Foo", {
- * extend: "Ext.app.Controller",
- * requires: ['MyApp.model.User', 'MyApp.model.Vehicle']
- * });
- *
- */
- /**
- * @cfg {String[]} views
- * Array of views to require from AppName.view namespace. For example:
- *
- * Ext.define("MyApp.controller.Foo", {
- * extend: "Ext.app.Controller",
- * views: ['List', 'Detail']
- * });
- *
- * This is equivalent of:
- *
- * Ext.define("MyApp.controller.Foo", {
- * extend: "Ext.app.Controller",
- * requires: ['MyApp.view.List', 'MyApp.view.Detail']
- * });
- *
- */
- /**
- * @cfg {String[]} stores
- * Array of stores to require from AppName.store namespace. For example:
- *
- * Ext.define("MyApp.controller.Foo", {
- * extend: "Ext.app.Controller",
- * stores: ['Users', 'Vehicles']
- * });
- *
- * This is equivalent of:
- *
- * Ext.define("MyApp.controller.Foo", {
- * extend: "Ext.app.Controller",
- * requires: ['MyApp.store.Users', 'MyApp.store.Vehicles']
- * });
- *
- */
- onClassExtended: function(cls, data) {
- var className = Ext.getClassName(cls),
- match = className.match(/^(.*)\.controller\./);
- if (match !== null) {
- var namespace = Ext.Loader.getPrefix(className) || match[1],
- onBeforeClassCreated = data.onBeforeClassCreated,
- requires = [],
- modules = ['model', 'view', 'store'],
- prefix;
- data.onBeforeClassCreated = function(cls, data) {
- var i, ln, module,
- items, j, subLn, item;
- for (i = 0,ln = modules.length; i < ln; i++) {
- module = modules[i];
- items = Ext.Array.from(data[module + 's']);
- for (j = 0,subLn = items.length; j < subLn; j++) {
- item = items[j];
- prefix = Ext.Loader.getPrefix(item);
- if (prefix === '' || prefix === item) {
- requires.push(namespace + '.' + module + '.' + item);
- }
- else {
- requires.push(item);
- }
- }
- }
- Ext.require(requires, Ext.Function.pass(onBeforeClassCreated, arguments, this));
- };
- }
- },
- /**
- * Creates new Controller.
- * @param {Object} config (optional) Config object.
- */
- constructor: function(config) {
- this.mixins.observable.constructor.call(this, config);
- Ext.apply(this, config || {});
- this.createGetters('model', this.models);
- this.createGetters('store', this.stores);
- this.createGetters('view', this.views);
- if (this.refs) {
- this.ref(this.refs);
- }
- },
- /**
- * A template method that is called when your application boots. It is called before the
- * {@link Ext.app.Application Application}'s launch function is executed so gives a hook point to run any code before
- * your Viewport is created.
- *
- * @param {Ext.app.Application} application
- * @template
- */
- init: function(application) {},
- /**
- * A template method like {@link #init}, but called after the viewport is created.
- * This is called after the {@link Ext.app.Application#launch launch} method of Application is executed.
- *
- * @param {Ext.app.Application} application
- * @template
- */
- onLaunch: function(application) {},
- createGetters: function(type, refs) {
- type = Ext.String.capitalize(type);
- Ext.Array.each(refs, function(ref) {
- var fn = 'get',
- parts = ref.split('.');
- // Handle namespaced class names. E.g. feed.Add becomes getFeedAddView etc.
- Ext.Array.each(parts, function(part) {
- fn += Ext.String.capitalize(part);
- });
- fn += type;
- if (!this[fn]) {
- this[fn] = Ext.Function.pass(this['get' + type], [ref], this);
- }
- // Execute it right away
- this[fn](ref);
- },
- this);
- },
- ref: function(refs) {
- var me = this;
- refs = Ext.Array.from(refs);
- Ext.Array.each(refs, function(info) {
- var ref = info.ref,
- fn = 'get' + Ext.String.capitalize(ref);
- if (!me[fn]) {
- me[fn] = Ext.Function.pass(me.getRef, [ref, info], me);
- }
- });
- },
- getRef: function(ref, info, config) {
- this.refCache = this.refCache || {};
- info = info || {};
- config = config || {};
- Ext.apply(info, config);
- if (info.forceCreate) {
- return Ext.ComponentManager.create(info, 'component');
- }
- var me = this,
- selector = info.selector,
- cached = me.refCache[ref];
- if (!cached) {
- me.refCache[ref] = cached = Ext.ComponentQuery.query(info.selector)[0];
- if (!cached && info.autoCreate) {
- me.refCache[ref] = cached = Ext.ComponentManager.create(info, 'component');
- }
- if (cached) {
- cached.on('beforedestroy', function() {
- me.refCache[ref] = null;
- });
- }
- }
- return cached;
- },
- /**
- * Adds listeners to components selected via {@link Ext.ComponentQuery}. Accepts an
- * object containing component paths mapped to a hash of listener functions.
- *
- * In the following example the `updateUser` function is mapped to to the `click`
- * event on a button component, which is a child of the `useredit` component.
- *
- * Ext.define('AM.controller.Users', {
- * init: function() {
- * this.control({
- * 'useredit button[action=save]': {
- * click: this.updateUser
- * }
- * });
- * },
- *
- * updateUser: function(button) {
- * console.log('clicked the Save button');
- * }
- * });
- *
- * See {@link Ext.ComponentQuery} for more information on component selectors.
- *
- * @param {String/Object} selectors If a String, the second argument is used as the
- * listeners, otherwise an object of selectors -> listeners is assumed
- * @param {Object} listeners
- */
- control: function(selectors, listeners) {
- this.application.control(selectors, listeners, this);
- },
- /**
- * Returns instance of a {@link Ext.app.Controller controller} with the given name.
- * When controller doesn't exist yet, it's created.
- * @param {String} name
- * @return {Ext.app.Controller} a controller instance.
- */
- getController: function(name) {
- return this.application.getController(name);
- },
- /**
- * Returns instance of a {@link Ext.data.Store Store} with the given name.
- * When store doesn't exist yet, it's created.
- * @param {String} name
- * @return {Ext.data.Store} a store instance.
- */
- getStore: function(name) {
- return this.application.getStore(name);
- },
- /**
- * Returns a {@link Ext.data.Model Model} class with the given name.
- * A shorthand for using {@link Ext.ModelManager#getModel}.
- * @param {String} name
- * @return {Ext.data.Model} a model class.
- */
- getModel: function(model) {
- return this.application.getModel(model);
- },
- /**
- * Returns a View class with the given name. To create an instance of the view,
- * you can use it like it's used by Application to create the Viewport:
- *
- * this.getView('Viewport').create();
- *
- * @param {String} name
- * @return {Ext.Base} a view class.
- */
- getView: function(view) {
- return this.application.getView(view);
- }
- });
- /**
- * @author Don Griffin
- *
- * This class is a base for all id generators. It also provides lookup of id generators by
- * their id.
- *
- * Generally, id generators are used to generate a primary key for new model instances. There
- * are different approaches to solving this problem, so this mechanism has both simple use
- * cases and is open to custom implementations. A {@link Ext.data.Model} requests id generation
- * using the {@link Ext.data.Model#idgen} property.
- *
- * # Identity, Type and Shared IdGenerators
- *
- * It is often desirable to share IdGenerators to ensure uniqueness or common configuration.
- * This is done by giving IdGenerator instances an id property by which they can be looked
- * up using the {@link #get} method. To configure two {@link Ext.data.Model Model} classes
- * to share one {@link Ext.data.SequentialIdGenerator sequential} id generator, you simply
- * assign them the same id:
- *
- * Ext.define('MyApp.data.MyModelA', {
- * extend: 'Ext.data.Model',
- * idgen: {
- * type: 'sequential',
- * id: 'foo'
- * }
- * });
- *
- * Ext.define('MyApp.data.MyModelB', {
- * extend: 'Ext.data.Model',
- * idgen: {
- * type: 'sequential',
- * id: 'foo'
- * }
- * });
- *
- * To make this as simple as possible for generator types that are shared by many (or all)
- * Models, the IdGenerator types (such as 'sequential' or 'uuid') are also reserved as
- * generator id's. This is used by the {@link Ext.data.UuidGenerator} which has an id equal
- * to its type ('uuid'). In other words, the following Models share the same generator:
- *
- * Ext.define('MyApp.data.MyModelX', {
- * extend: 'Ext.data.Model',
- * idgen: 'uuid'
- * });
- *
- * Ext.define('MyApp.data.MyModelY', {
- * extend: 'Ext.data.Model',
- * idgen: 'uuid'
- * });
- *
- * This can be overridden (by specifying the id explicitly), but there is no particularly
- * good reason to do so for this generator type.
- *
- * # Creating Custom Generators
- *
- * An id generator should derive from this class and implement the {@link #generate} method.
- * The constructor will apply config properties on new instances, so a constructor is often
- * not necessary.
- *
- * To register an id generator type, a derived class should provide an `alias` like so:
- *
- * Ext.define('MyApp.data.CustomIdGenerator', {
- * extend: 'Ext.data.IdGenerator',
- * alias: 'idgen.custom',
- *
- * configProp: 42, // some config property w/default value
- *
- * generate: function () {
- * return ... // a new id
- * }
- * });
- *
- * Using the custom id generator is then straightforward:
- *
- * Ext.define('MyApp.data.MyModel', {
- * extend: 'Ext.data.Model',
- * idgen: 'custom'
- * });
- * // or...
- *
- * Ext.define('MyApp.data.MyModel', {
- * extend: 'Ext.data.Model',
- * idgen: {
- * type: 'custom',
- * configProp: value
- * }
- * });
- *
- * It is not recommended to mix shared generators with generator configuration. This leads
- * to unpredictable results unless all configurations match (which is also redundant). In
- * such cases, a custom generator with a default id is the best approach.
- *
- * Ext.define('MyApp.data.CustomIdGenerator', {
- * extend: 'Ext.data.SequentialIdGenerator',
- * alias: 'idgen.custom',
- *
- * id: 'custom', // shared by default
- *
- * prefix: 'ID_',
- * seed: 1000
- * });
- *
- * Ext.define('MyApp.data.MyModelX', {
- * extend: 'Ext.data.Model',
- * idgen: 'custom'
- * });
- *
- * Ext.define('MyApp.data.MyModelY', {
- * extend: 'Ext.data.Model',
- * idgen: 'custom'
- * });
- *
- * // the above models share a generator that produces ID_1000, ID_1001, etc..
- *
- */
- Ext.define('Ext.data.IdGenerator', {
- isGenerator: true,
- /**
- * Initializes a new instance.
- * @param {Object} config (optional) Configuration object to be applied to the new instance.
- */
- constructor: function(config) {
- var me = this;
- Ext.apply(me, config);
- if (me.id) {
- Ext.data.IdGenerator.all[me.id] = me;
- }
- },
- /**
- * @cfg {String} id
- * The id by which to register a new instance. This instance can be found using the
- * {@link Ext.data.IdGenerator#get} static method.
- */
- getRecId: function (rec) {
- return rec.modelName + '-' + rec.internalId;
- },
- /**
- * Generates and returns the next id. This method must be implemented by the derived
- * class.
- *
- * @return {String} The next id.
- * @method generate
- * @abstract
- */
- statics: {
- /**
- * @property {Object} all
- * This object is keyed by id to lookup instances.
- * @private
- * @static
- */
- all: {},
- /**
- * Returns the IdGenerator given its config description.
- * @param {String/Object} config If this parameter is an IdGenerator instance, it is
- * simply returned. If this is a string, it is first used as an id for lookup and
- * then, if there is no match, as a type to create a new instance. This parameter
- * can also be a config object that contains a `type` property (among others) that
- * are used to create and configure the instance.
- * @static
- */
- get: function (config) {
- var generator,
- id,
- type;
- if (typeof config == 'string') {
- id = type = config;
- config = null;
- } else if (config.isGenerator) {
- return config;
- } else {
- id = config.id || config.type;
- type = config.type;
- }
- generator = this.all[id];
- if (!generator) {
- generator = Ext.create('idgen.' + type, config);
- }
- return generator;
- }
- }
- });
- /**
- * @class Ext.data.SortTypes
- * This class defines a series of static methods that are used on a
- * {@link Ext.data.Field} for performing sorting. The methods cast the
- * underlying values into a data type that is appropriate for sorting on
- * that particular field. If a {@link Ext.data.Field#type} is specified,
- * the sortType will be set to a sane default if the sortType is not
- * explicitly defined on the field. The sortType will make any necessary
- * modifications to the value and return it.
- * <ul>
- * <li><b>asText</b> - Removes any tags and converts the value to a string</li>
- * <li><b>asUCText</b> - Removes any tags and converts the value to an uppercase string</li>
- * <li><b>asUCText</b> - Converts the value to an uppercase string</li>
- * <li><b>asDate</b> - Converts the value into Unix epoch time</li>
- * <li><b>asFloat</b> - Converts the value to a floating point number</li>
- * <li><b>asInt</b> - Converts the value to an integer number</li>
- * </ul>
- * <p>
- * It is also possible to create a custom sortType that can be used throughout
- * an application.
- * <pre><code>
- Ext.apply(Ext.data.SortTypes, {
- asPerson: function(person){
- // expects an object with a first and last name property
- return person.lastName.toUpperCase() + person.firstName.toLowerCase();
- }
- });
- Ext.define('Employee', {
- extend: 'Ext.data.Model',
- fields: [{
- name: 'person',
- sortType: 'asPerson'
- }, {
- name: 'salary',
- type: 'float' // sortType set to asFloat
- }]
- });
- * </code></pre>
- * </p>
- * @singleton
- * @docauthor Evan Trimboli <evan@sencha.com>
- */
- Ext.define('Ext.data.SortTypes', {
-
- singleton: true,
-
- /**
- * Default sort that does nothing
- * @param {Object} s The value being converted
- * @return {Object} The comparison value
- */
- none : function(s) {
- return s;
- },
- /**
- * The regular expression used to strip tags
- * @type {RegExp}
- * @property
- */
- stripTagsRE : /<\/?[^>]+>/gi,
- /**
- * Strips all HTML tags to sort on text only
- * @param {Object} s The value being converted
- * @return {String} The comparison value
- */
- asText : function(s) {
- return String(s).replace(this.stripTagsRE, "");
- },
- /**
- * Strips all HTML tags to sort on text only - Case insensitive
- * @param {Object} s The value being converted
- * @return {String} The comparison value
- */
- asUCText : function(s) {
- return String(s).toUpperCase().replace(this.stripTagsRE, "");
- },
- /**
- * Case insensitive string
- * @param {Object} s The value being converted
- * @return {String} The comparison value
- */
- asUCString : function(s) {
- return String(s).toUpperCase();
- },
- /**
- * Date sorting
- * @param {Object} s The value being converted
- * @return {Number} The comparison value
- */
- asDate : function(s) {
- if(!s){
- return 0;
- }
- if(Ext.isDate(s)){
- return s.getTime();
- }
- return Date.parse(String(s));
- },
- /**
- * Float sorting
- * @param {Object} s The value being converted
- * @return {Number} The comparison value
- */
- asFloat : function(s) {
- var val = parseFloat(String(s).replace(/,/g, ""));
- return isNaN(val) ? 0 : val;
- },
- /**
- * Integer sorting
- * @param {Object} s The value being converted
- * @return {Number} The comparison value
- */
- asInt : function(s) {
- var val = parseInt(String(s).replace(/,/g, ""), 10);
- return isNaN(val) ? 0 : val;
- }
- });
- /**
- * Represents a filter that can be applied to a {@link Ext.util.MixedCollection MixedCollection}. Can either simply
- * filter on a property/value pair or pass in a filter function with custom logic. Filters are always used in the
- * context of MixedCollections, though {@link Ext.data.Store Store}s frequently create them when filtering and searching
- * on their records. Example usage:
- *
- * //set up a fictional MixedCollection containing a few people to filter on
- * var allNames = new Ext.util.MixedCollection();
- * allNames.addAll([
- * {id: 1, name: 'Ed', age: 25},
- * {id: 2, name: 'Jamie', age: 37},
- * {id: 3, name: 'Abe', age: 32},
- * {id: 4, name: 'Aaron', age: 26},
- * {id: 5, name: 'David', age: 32}
- * ]);
- *
- * var ageFilter = new Ext.util.Filter({
- * property: 'age',
- * value : 32
- * });
- *
- * var longNameFilter = new Ext.util.Filter({
- * filterFn: function(item) {
- * return item.name.length > 4;
- * }
- * });
- *
- * //a new MixedCollection with the 3 names longer than 4 characters
- * var longNames = allNames.filter(longNameFilter);
- *
- * //a new MixedCollection with the 2 people of age 24:
- * var youngFolk = allNames.filter(ageFilter);
- *
- */
- Ext.define('Ext.util.Filter', {
- /* Begin Definitions */
- /* End Definitions */
- /**
- * @cfg {String} property
- * The property to filter on. Required unless a {@link #filterFn} is passed
- */
-
- /**
- * @cfg {Function} filterFn
- * A custom filter function which is passed each item in the {@link Ext.util.MixedCollection} in turn. Should return
- * true to accept each item or false to reject it
- */
-
- /**
- * @cfg {Boolean} anyMatch
- * True to allow any match - no regex start/end line anchors will be added.
- */
- anyMatch: false,
-
- /**
- * @cfg {Boolean} exactMatch
- * True to force exact match (^ and $ characters added to the regex). Ignored if anyMatch is true.
- */
- exactMatch: false,
-
- /**
- * @cfg {Boolean} caseSensitive
- * True to make the regex case sensitive (adds 'i' switch to regex).
- */
- caseSensitive: false,
-
- /**
- * @cfg {String} root
- * Optional root property. This is mostly useful when filtering a Store, in which case we set the root to 'data' to
- * make the filter pull the {@link #property} out of the data object of each item
- */
- /**
- * Creates new Filter.
- * @param {Object} [config] Config object
- */
- constructor: function(config) {
- var me = this;
- Ext.apply(me, config);
-
- //we're aliasing filter to filterFn mostly for API cleanliness reasons, despite the fact it dirties the code here.
- //Ext.util.Sorter takes a sorterFn property but allows .sort to be called - we do the same here
- me.filter = me.filter || me.filterFn;
-
- if (me.filter === undefined) {
- if (me.property === undefined || me.value === undefined) {
- // Commented this out temporarily because it stops us using string ids in models. TODO: Remove this once
- // Model has been updated to allow string ids
-
- // Ext.Error.raise("A Filter requires either a property or a filterFn to be set");
- } else {
- me.filter = me.createFilterFn();
- }
-
- me.filterFn = me.filter;
- }
- },
-
- /**
- * @private
- * Creates a filter function for the configured property/value/anyMatch/caseSensitive options for this Filter
- */
- createFilterFn: function() {
- var me = this,
- matcher = me.createValueMatcher(),
- property = me.property;
-
- return function(item) {
- var value = me.getRoot.call(me, item)[property];
- return matcher === null ? value === null : matcher.test(value);
- };
- },
-
- /**
- * @private
- * Returns the root property of the given item, based on the configured {@link #root} property
- * @param {Object} item The item
- * @return {Object} The root property of the object
- */
- getRoot: function(item) {
- var root = this.root;
- return root === undefined ? item : item[root];
- },
-
- /**
- * @private
- * Returns a regular expression based on the given value and matching options
- */
- createValueMatcher : function() {
- var me = this,
- value = me.value,
- anyMatch = me.anyMatch,
- exactMatch = me.exactMatch,
- caseSensitive = me.caseSensitive,
- escapeRe = Ext.String.escapeRegex;
-
- if (value === null) {
- return value;
- }
-
- if (!value.exec) { // not a regex
- value = String(value);
- if (anyMatch === true) {
- value = escapeRe(value);
- } else {
- value = '^' + escapeRe(value);
- if (exactMatch === true) {
- value += '$';
- }
- }
- value = new RegExp(value, caseSensitive ? '' : 'i');
- }
-
- return value;
- }
- });
- /**
- * Represents a single sorter that can be applied to a Store. The sorter is used
- * to compare two values against each other for the purpose of ordering them. Ordering
- * is achieved by specifying either:
- *
- * - {@link #property A sorting property}
- * - {@link #sorterFn A sorting function}
- *
- * As a contrived example, we can specify a custom sorter that sorts by rank:
- *
- * Ext.define('Person', {
- * extend: 'Ext.data.Model',
- * fields: ['name', 'rank']
- * });
- *
- * Ext.create('Ext.data.Store', {
- * model: 'Person',
- * proxy: 'memory',
- * sorters: [{
- * sorterFn: function(o1, o2){
- * var getRank = function(o){
- * var name = o.get('rank');
- * if (name === 'first') {
- * return 1;
- * } else if (name === 'second') {
- * return 2;
- * } else {
- * return 3;
- * }
- * },
- * rank1 = getRank(o1),
- * rank2 = getRank(o2);
- *
- * if (rank1 === rank2) {
- * return 0;
- * }
- *
- * return rank1 < rank2 ? -1 : 1;
- * }
- * }],
- * data: [{
- * name: 'Person1',
- * rank: 'second'
- * }, {
- * name: 'Person2',
- * rank: 'third'
- * }, {
- * name: 'Person3',
- * rank: 'first'
- * }]
- * });
- */
- Ext.define('Ext.util.Sorter', {
- /**
- * @cfg {String} property
- * The property to sort by. Required unless {@link #sorterFn} is provided. The property is extracted from the object
- * directly and compared for sorting using the built in comparison operators.
- */
-
- /**
- * @cfg {Function} sorterFn
- * A specific sorter function to execute. Can be passed instead of {@link #property}. This sorter function allows
- * for any kind of custom/complex comparisons. The sorterFn receives two arguments, the objects being compared. The
- * function should return:
- *
- * - -1 if o1 is "less than" o2
- * - 0 if o1 is "equal" to o2
- * - 1 if o1 is "greater than" o2
- */
-
- /**
- * @cfg {String} root
- * Optional root property. This is mostly useful when sorting a Store, in which case we set the root to 'data' to
- * make the filter pull the {@link #property} out of the data object of each item
- */
-
- /**
- * @cfg {Function} transform
- * A function that will be run on each value before it is compared in the sorter. The function will receive a single
- * argument, the value.
- */
-
- /**
- * @cfg {String} direction
- * The direction to sort by.
- */
- direction: "ASC",
-
- constructor: function(config) {
- var me = this;
-
- Ext.apply(me, config);
-
- //<debug>
- if (me.property === undefined && me.sorterFn === undefined) {
- Ext.Error.raise("A Sorter requires either a property or a sorter function");
- }
- //</debug>
-
- me.updateSortFunction();
- },
-
- /**
- * @private
- * Creates and returns a function which sorts an array by the given property and direction
- * @return {Function} A function which sorts by the property/direction combination provided
- */
- createSortFunction: function(sorterFn) {
- var me = this,
- property = me.property,
- direction = me.direction || "ASC",
- modifier = direction.toUpperCase() == "DESC" ? -1 : 1;
-
- //create a comparison function. Takes 2 objects, returns 1 if object 1 is greater,
- //-1 if object 2 is greater or 0 if they are equal
- return function(o1, o2) {
- return modifier * sorterFn.call(me, o1, o2);
- };
- },
-
- /**
- * @private
- * Basic default sorter function that just compares the defined property of each object
- */
- defaultSorterFn: function(o1, o2) {
- var me = this,
- transform = me.transform,
- v1 = me.getRoot(o1)[me.property],
- v2 = me.getRoot(o2)[me.property];
-
- if (transform) {
- v1 = transform(v1);
- v2 = transform(v2);
- }
- return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
- },
-
- /**
- * @private
- * Returns the root property of the given item, based on the configured {@link #root} property
- * @param {Object} item The item
- * @return {Object} The root property of the object
- */
- getRoot: function(item) {
- return this.root === undefined ? item : item[this.root];
- },
-
- /**
- * Set the sorting direction for this sorter.
- * @param {String} direction The direction to sort in. Should be either 'ASC' or 'DESC'.
- */
- setDirection: function(direction) {
- var me = this;
- me.direction = direction;
- me.updateSortFunction();
- },
-
- /**
- * Toggles the sorting direction for this sorter.
- */
- toggle: function() {
- var me = this;
- me.direction = Ext.String.toggle(me.direction, "ASC", "DESC");
- me.updateSortFunction();
- },
-
- /**
- * Update the sort function for this sorter.
- * @param {Function} [fn] A new sorter function for this sorter. If not specified it will use the default
- * sorting function.
- */
- updateSortFunction: function(fn) {
- var me = this;
- fn = fn || me.sorterFn || me.defaultSorterFn;
- me.sort = me.createSortFunction(fn);
- }
- });
- /**
- * @author Ed Spencer
- *
- * Represents a single read or write operation performed by a {@link Ext.data.proxy.Proxy Proxy}. Operation objects are
- * used to enable communication between Stores and Proxies. Application developers should rarely need to interact with
- * Operation objects directly.
- *
- * Several Operations can be batched together in a {@link Ext.data.Batch batch}.
- */
- Ext.define('Ext.data.Operation', {
- /**
- * @cfg {Boolean} synchronous
- * True if this Operation is to be executed synchronously. This property is inspected by a
- * {@link Ext.data.Batch Batch} to see if a series of Operations can be executed in parallel or not.
- */
- synchronous: true,
- /**
- * @cfg {String} action
- * The action being performed by this Operation. Should be one of 'create', 'read', 'update' or 'destroy'.
- */
- action: undefined,
- /**
- * @cfg {Ext.util.Filter[]} filters
- * Optional array of filter objects. Only applies to 'read' actions.
- */
- filters: undefined,
- /**
- * @cfg {Ext.util.Sorter[]} sorters
- * Optional array of sorter objects. Only applies to 'read' actions.
- */
- sorters: undefined,
- /**
- * @cfg {Ext.util.Grouper} group
- * Optional grouping configuration. Only applies to 'read' actions where grouping is desired.
- */
- group: undefined,
- /**
- * @cfg {Number} start
- * The start index (offset), used in paging when running a 'read' action.
- */
- start: undefined,
- /**
- * @cfg {Number} limit
- * The number of records to load. Used on 'read' actions when paging is being used.
- */
- limit: undefined,
- /**
- * @cfg {Ext.data.Batch} batch
- * The batch that this Operation is a part of.
- */
- batch: undefined,
- /**
- * @cfg {Function} callback
- * Function to execute when operation completed. Will be called with the following parameters:
- *
- * - records : Array of Ext.data.Model objects.
- * - operation : The Ext.data.Operation itself.
- * - success : True when operation completed successfully.
- */
- callback: undefined,
- /**
- * @cfg {Object} scope
- * Scope for the {@link #callback} function.
- */
- scope: undefined,
- /**
- * @property {Boolean} started
- * Read-only property tracking the start status of this Operation. Use {@link #isStarted}.
- * @private
- */
- started: false,
- /**
- * @property {Boolean} running
- * Read-only property tracking the run status of this Operation. Use {@link #isRunning}.
- * @private
- */
- running: false,
- /**
- * @property {Boolean} complete
- * Read-only property tracking the completion status of this Operation. Use {@link #isComplete}.
- * @private
- */
- complete: false,
- /**
- * @property {Boolean} success
- * Read-only property tracking whether the Operation was successful or not. This starts as undefined and is set to true
- * or false by the Proxy that is executing the Operation. It is also set to false by {@link #setException}. Use
- * {@link #wasSuccessful} to query success status.
- * @private
- */
- success: undefined,
- /**
- * @property {Boolean} exception
- * Read-only property tracking the exception status of this Operation. Use {@link #hasException} and see {@link #getError}.
- * @private
- */
- exception: false,
- /**
- * @property {String/Object} error
- * The error object passed when {@link #setException} was called. This could be any object or primitive.
- * @private
- */
- error: undefined,
- /**
- * @property {RegExp} actionCommitRecordsRe
- * The RegExp used to categorize actions that require record commits.
- */
- actionCommitRecordsRe: /^(?:create|update)$/i,
- /**
- * @property {RegExp} actionSkipSyncRe
- * The RegExp used to categorize actions that skip local record synchronization. This defaults
- * to match 'destroy'.
- */
- actionSkipSyncRe: /^destroy$/i,
- /**
- * Creates new Operation object.
- * @param {Object} config (optional) Config object.
- */
- constructor: function(config) {
- Ext.apply(this, config || {});
- },
- /**
- * This method is called to commit data to this instance's records given the records in
- * the server response. This is followed by calling {@link Ext.data.Model#commit} on all
- * those records (for 'create' and 'update' actions).
- *
- * If this {@link #action} is 'destroy', any server records are ignored and the
- * {@link Ext.data.Model#commit} method is not called.
- *
- * @param {Ext.data.Model[]} serverRecords An array of {@link Ext.data.Model} objects returned by
- * the server.
- * @markdown
- */
- commitRecords: function (serverRecords) {
- var me = this,
- mc, index, clientRecords, serverRec, clientRec;
- if (!me.actionSkipSyncRe.test(me.action)) {
- clientRecords = me.records;
- if (clientRecords && clientRecords.length) {
- mc = Ext.create('Ext.util.MixedCollection', true, function(r) {return r.getId();});
- mc.addAll(clientRecords);
- for (index = serverRecords ? serverRecords.length : 0; index--; ) {
- serverRec = serverRecords[index];
- clientRec = mc.get(serverRec.getId());
- if (clientRec) {
- clientRec.beginEdit();
- clientRec.set(serverRec.data);
- clientRec.endEdit(true);
- }
- }
- if (me.actionCommitRecordsRe.test(me.action)) {
- for (index = clientRecords.length; index--; ) {
- clientRecords[index].commit();
- }
- }
- }
- }
- },
- /**
- * Marks the Operation as started.
- */
- setStarted: function() {
- this.started = true;
- this.running = true;
- },
- /**
- * Marks the Operation as completed.
- */
- setCompleted: function() {
- this.complete = true;
- this.running = false;
- },
- /**
- * Marks the Operation as successful.
- */
- setSuccessful: function() {
- this.success = true;
- },
- /**
- * Marks the Operation as having experienced an exception. Can be supplied with an option error message/object.
- * @param {String/Object} error (optional) error string/object
- */
- setException: function(error) {
- this.exception = true;
- this.success = false;
- this.running = false;
- this.error = error;
- },
- /**
- * Returns true if this Operation encountered an exception (see also {@link #getError})
- * @return {Boolean} True if there was an exception
- */
- hasException: function() {
- return this.exception === true;
- },
- /**
- * Returns the error string or object that was set using {@link #setException}
- * @return {String/Object} The error object
- */
- getError: function() {
- return this.error;
- },
- /**
- * Returns an array of Ext.data.Model instances as set by the Proxy.
- * @return {Ext.data.Model[]} Any loaded Records
- */
- getRecords: function() {
- var resultSet = this.getResultSet();
- return (resultSet === undefined ? this.records : resultSet.records);
- },
- /**
- * Returns the ResultSet object (if set by the Proxy). This object will contain the {@link Ext.data.Model model}
- * instances as well as meta data such as number of instances fetched, number available etc
- * @return {Ext.data.ResultSet} The ResultSet object
- */
- getResultSet: function() {
- return this.resultSet;
- },
- /**
- * Returns true if the Operation has been started. Note that the Operation may have started AND completed, see
- * {@link #isRunning} to test if the Operation is currently running.
- * @return {Boolean} True if the Operation has started
- */
- isStarted: function() {
- return this.started === true;
- },
- /**
- * Returns true if the Operation has been started but has not yet completed.
- * @return {Boolean} True if the Operation is currently running
- */
- isRunning: function() {
- return this.running === true;
- },
- /**
- * Returns true if the Operation has been completed
- * @return {Boolean} True if the Operation is complete
- */
- isComplete: function() {
- return this.complete === true;
- },
- /**
- * Returns true if the Operation has completed and was successful
- * @return {Boolean} True if successful
- */
- wasSuccessful: function() {
- return this.isComplete() && this.success === true;
- },
- /**
- * @private
- * Associates this Operation with a Batch
- * @param {Ext.data.Batch} batch The batch
- */
- setBatch: function(batch) {
- this.batch = batch;
- },
- /**
- * Checks whether this operation should cause writing to occur.
- * @return {Boolean} Whether the operation should cause a write to occur.
- */
- allowWrite: function() {
- return this.action != 'read';
- }
- });
- /**
- * @author Ed Spencer
- *
- * This singleton contains a set of validation functions that can be used to validate any type of data. They are most
- * often used in {@link Ext.data.Model Models}, where they are automatically set up and executed.
- */
- Ext.define('Ext.data.validations', {
- singleton: true,
-
- /**
- * @property {String} presenceMessage
- * The default error message used when a presence validation fails.
- */
- presenceMessage: 'must be present',
-
- /**
- * @property {String} lengthMessage
- * The default error message used when a length validation fails.
- */
- lengthMessage: 'is the wrong length',
-
- /**
- * @property {Boolean} formatMessage
- * The default error message used when a format validation fails.
- */
- formatMessage: 'is the wrong format',
-
- /**
- * @property {String} inclusionMessage
- * The default error message used when an inclusion validation fails.
- */
- inclusionMessage: 'is not included in the list of acceptable values',
-
- /**
- * @property {String} exclusionMessage
- * The default error message used when an exclusion validation fails.
- */
- exclusionMessage: 'is not an acceptable value',
-
- /**
- * @property {String} emailMessage
- * The default error message used when an email validation fails
- */
- emailMessage: 'is not a valid email address',
-
- /**
- * @property {RegExp} emailRe
- * The regular expression used to validate email addresses
- */
- emailRe: /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,
-
- /**
- * Validates that the given value is present.
- * For example:
- *
- * validations: [{type: 'presence', field: 'age'}]
- *
- * @param {Object} config Config object
- * @param {Object} value The value to validate
- * @return {Boolean} True if validation passed
- */
- presence: function(config, value) {
- if (value === undefined) {
- value = config;
- }
-
- //we need an additional check for zero here because zero is an acceptable form of present data
- return !!value || value === 0;
- },
-
- /**
- * Returns true if the given value is between the configured min and max values.
- * For example:
- *
- * validations: [{type: 'length', field: 'name', min: 2}]
- *
- * @param {Object} config Config object
- * @param {String} value The value to validate
- * @return {Boolean} True if the value passes validation
- */
- length: function(config, value) {
- if (value === undefined || value === null) {
- return false;
- }
-
- var length = value.length,
- min = config.min,
- max = config.max;
-
- if ((min && length < min) || (max && length > max)) {
- return false;
- } else {
- return true;
- }
- },
-
- /**
- * Validates that an email string is in the correct format
- * @param {Object} config Config object
- * @param {String} email The email address
- * @return {Boolean} True if the value passes validation
- */
- email: function(config, email) {
- return Ext.data.validations.emailRe.test(email);
- },
-
- /**
- * Returns true if the given value passes validation against the configured `matcher` regex.
- * For example:
- *
- * validations: [{type: 'format', field: 'username', matcher: /([a-z]+)[0-9]{2,3}/}]
- *
- * @param {Object} config Config object
- * @param {String} value The value to validate
- * @return {Boolean} True if the value passes the format validation
- */
- format: function(config, value) {
- return !!(config.matcher && config.matcher.test(value));
- },
-
- /**
- * Validates that the given value is present in the configured `list`.
- * For example:
- *
- * validations: [{type: 'inclusion', field: 'gender', list: ['Male', 'Female']}]
- *
- * @param {Object} config Config object
- * @param {String} value The value to validate
- * @return {Boolean} True if the value is present in the list
- */
- inclusion: function(config, value) {
- return config.list && Ext.Array.indexOf(config.list,value) != -1;
- },
-
- /**
- * Validates that the given value is present in the configured `list`.
- * For example:
- *
- * validations: [{type: 'exclusion', field: 'username', list: ['Admin', 'Operator']}]
- *
- * @param {Object} config Config object
- * @param {String} value The value to validate
- * @return {Boolean} True if the value is not present in the list
- */
- exclusion: function(config, value) {
- return config.list && Ext.Array.indexOf(config.list,value) == -1;
- }
- });
- /**
- * @author Ed Spencer
- *
- * Simple wrapper class that represents a set of records returned by a Proxy.
- */
- Ext.define('Ext.data.ResultSet', {
- /**
- * @cfg {Boolean} loaded
- * True if the records have already been loaded. This is only meaningful when dealing with
- * SQL-backed proxies.
- */
- loaded: true,
- /**
- * @cfg {Number} count
- * The number of records in this ResultSet. Note that total may differ from this number.
- */
- count: 0,
- /**
- * @cfg {Number} total
- * The total number of records reported by the data source. This ResultSet may form a subset of
- * those records (see {@link #count}).
- */
- total: 0,
- /**
- * @cfg {Boolean} success
- * True if the ResultSet loaded successfully, false if any errors were encountered.
- */
- success: false,
- /**
- * @cfg {Ext.data.Model[]} records (required)
- * The array of record instances.
- */
- /**
- * Creates the resultSet
- * @param {Object} [config] Config object.
- */
- constructor: function(config) {
- Ext.apply(this, config);
- /**
- * @property {Number} totalRecords
- * Copy of this.total.
- * @deprecated Will be removed in Ext JS 5.0. Use {@link #total} instead.
- */
- this.totalRecords = this.total;
- if (config.count === undefined) {
- this.count = this.records.length;
- }
- }
- });
- /**
- * @author Ed Spencer
- *
- * Base Writer class used by most subclasses of {@link Ext.data.proxy.Server}. This class is responsible for taking a
- * set of {@link Ext.data.Operation} objects and a {@link Ext.data.Request} object and modifying that request based on
- * the Operations.
- *
- * For example a Ext.data.writer.Json would format the Operations and their {@link Ext.data.Model} instances based on
- * the config options passed to the JsonWriter's constructor.
- *
- * Writers are not needed for any kind of local storage - whether via a {@link Ext.data.proxy.WebStorage Web Storage
- * proxy} (see {@link Ext.data.proxy.LocalStorage localStorage} and {@link Ext.data.proxy.SessionStorage
- * sessionStorage}) or just in memory via a {@link Ext.data.proxy.Memory MemoryProxy}.
- */
- Ext.define('Ext.data.writer.Writer', {
- alias: 'writer.base',
- alternateClassName: ['Ext.data.DataWriter', 'Ext.data.Writer'],
-
- /**
- * @cfg {Boolean} writeAllFields
- * True to write all fields from the record to the server. If set to false it will only send the fields that were
- * modified. Note that any fields that have {@link Ext.data.Field#persist} set to false will still be ignored.
- */
- writeAllFields: true,
-
- /**
- * @cfg {String} nameProperty
- * This property is used to read the key for each value that will be sent to the server. For example:
- *
- * Ext.define('Person', {
- * extend: 'Ext.data.Model',
- * fields: [{
- * name: 'first',
- * mapping: 'firstName'
- * }, {
- * name: 'last',
- * mapping: 'lastName'
- * }, {
- * name: 'age'
- * }]
- * });
- * new Ext.data.writer.Writer({
- * writeAllFields: true,
- * nameProperty: 'mapping'
- * });
- *
- * // This will be sent to the server
- * {
- * firstName: 'first name value',
- * lastName: 'last name value',
- * age: 1
- * }
- *
- * If the value is not present, the field name will always be used.
- */
- nameProperty: 'name',
- /**
- * Creates new Writer.
- * @param {Object} [config] Config object.
- */
- constructor: function(config) {
- Ext.apply(this, config);
- },
- /**
- * Prepares a Proxy's Ext.data.Request object
- * @param {Ext.data.Request} request The request object
- * @return {Ext.data.Request} The modified request object
- */
- write: function(request) {
- var operation = request.operation,
- records = operation.records || [],
- len = records.length,
- i = 0,
- data = [];
- for (; i < len; i++) {
- data.push(this.getRecordData(records[i]));
- }
- return this.writeRecords(request, data);
- },
- /**
- * Formats the data for each record before sending it to the server. This method should be overridden to format the
- * data in a way that differs from the default.
- * @param {Object} record The record that we are writing to the server.
- * @return {Object} An object literal of name/value keys to be written to the server. By default this method returns
- * the data property on the record.
- */
- getRecordData: function(record) {
- var isPhantom = record.phantom === true,
- writeAll = this.writeAllFields || isPhantom,
- nameProperty = this.nameProperty,
- fields = record.fields,
- data = {},
- changes,
- name,
- field,
- key;
-
- if (writeAll) {
- fields.each(function(field){
- if (field.persist) {
- name = field[nameProperty] || field.name;
- data[name] = record.get(field.name);
- }
- });
- } else {
- // Only write the changes
- changes = record.getChanges();
- for (key in changes) {
- if (changes.hasOwnProperty(key)) {
- field = fields.get(key);
- name = field[nameProperty] || field.name;
- data[name] = changes[key];
- }
- }
- if (!isPhantom) {
- // always include the id for non phantoms
- data[record.idProperty] = record.getId();
- }
- }
- return data;
- }
- });
- /**
- * A mixin to add floating capability to a Component.
- */
- Ext.define('Ext.util.Floating', {
- uses: ['Ext.Layer', 'Ext.window.Window'],
- /**
- * @cfg {Boolean} focusOnToFront
- * Specifies whether the floated component should be automatically {@link Ext.Component#focus focused} when
- * it is {@link #toFront brought to the front}.
- */
- focusOnToFront: true,
- /**
- * @cfg {String/Boolean} shadow
- * Specifies whether the floating component should be given a shadow. Set to true to automatically create an {@link
- * Ext.Shadow}, or a string indicating the shadow's display {@link Ext.Shadow#mode}. Set to false to disable the
- * shadow.
- */
- shadow: 'sides',
- constructor: function(config) {
- var me = this;
-
- me.floating = true;
- me.el = Ext.create('Ext.Layer', Ext.apply({}, config, {
- hideMode: me.hideMode,
- hidden: me.hidden,
- shadow: Ext.isDefined(me.shadow) ? me.shadow : 'sides',
- shadowOffset: me.shadowOffset,
- constrain: false,
- shim: me.shim === false ? false : undefined
- }), me.el);
- },
- onFloatRender: function() {
- var me = this;
- me.zIndexParent = me.getZIndexParent();
- me.setFloatParent(me.ownerCt);
- delete me.ownerCt;
- if (me.zIndexParent) {
- me.zIndexParent.registerFloatingItem(me);
- } else {
- Ext.WindowManager.register(me);
- }
- },
- setFloatParent: function(floatParent) {
- var me = this;
- // Remove listeners from previous floatParent
- if (me.floatParent) {
- me.mun(me.floatParent, {
- hide: me.onFloatParentHide,
- show: me.onFloatParentShow,
- scope: me
- });
- }
- me.floatParent = floatParent;
- // Floating Components as children of Containers must hide when their parent hides.
- if (floatParent) {
- me.mon(me.floatParent, {
- hide: me.onFloatParentHide,
- show: me.onFloatParentShow,
- scope: me
- });
- }
- // If a floating Component is configured to be constrained, but has no configured
- // constrainTo setting, set its constrainTo to be it's ownerCt before rendering.
- if ((me.constrain || me.constrainHeader) && !me.constrainTo) {
- me.constrainTo = floatParent ? floatParent.getTargetEl() : me.container;
- }
- },
- onFloatParentHide: function() {
- var me = this;
-
- if (me.hideOnParentHide !== false) {
- me.showOnParentShow = me.isVisible();
- me.hide();
- }
- },
- onFloatParentShow: function() {
- if (this.showOnParentShow) {
- delete this.showOnParentShow;
- this.show();
- }
- },
- /**
- * @private
- * Finds the ancestor Container responsible for allocating zIndexes for the passed Component.
- *
- * That will be the outermost floating Container (a Container which has no ownerCt and has floating:true).
- *
- * If we have no ancestors, or we walk all the way up to the document body, there's no zIndexParent,
- * and the global Ext.WindowManager will be used.
- */
- getZIndexParent: function() {
- var p = this.ownerCt,
- c;
- if (p) {
- while (p) {
- c = p;
- p = p.ownerCt;
- }
- if (c.floating) {
- return c;
- }
- }
- },
- // private
- // z-index is managed by the zIndexManager and may be overwritten at any time.
- // Returns the next z-index to be used.
- // If this is a Container, then it will have rebased any managed floating Components,
- // and so the next available z-index will be approximately 10000 above that.
- setZIndex: function(index) {
- var me = this;
- me.el.setZIndex(index);
- // Next item goes 10 above;
- index += 10;
- // When a Container with floating items has its z-index set, it rebases any floating items it is managing.
- // The returned value is a round number approximately 10000 above the last z-index used.
- if (me.floatingItems) {
- index = Math.floor(me.floatingItems.setBase(index) / 100) * 100 + 10000;
- }
- return index;
- },
- /**
- * Moves this floating Component into a constrain region.
- *
- * By default, this Component is constrained to be within the container it was added to, or the element it was
- * rendered to.
- *
- * An alternative constraint may be passed.
- * @param {String/HTMLElement/Ext.Element/Ext.util.Region} constrainTo (Optional) The Element or {@link Ext.util.Region Region} into which this Component is
- * to be constrained. Defaults to the element into which this floating Component was rendered.
- */
- doConstrain: function(constrainTo) {
- var me = this,
- vector = me.getConstrainVector(constrainTo || me.el.getScopeParent()),
- xy;
- if (vector) {
- xy = me.getPosition();
- xy[0] += vector[0];
- xy[1] += vector[1];
- me.setPosition(xy);
- }
- },
- /**
- * Gets the x/y offsets to constrain this float
- * @private
- * @param {String/HTMLElement/Ext.Element/Ext.util.Region} constrainTo (Optional) The Element or {@link Ext.util.Region Region} into which this Component is to be constrained.
- * @return {Number[]} The x/y constraints
- */
- getConstrainVector: function(constrainTo){
- var me = this,
- el;
- if (me.constrain || me.constrainHeader) {
- el = me.constrainHeader ? me.header.el : me.el;
- constrainTo = constrainTo || (me.floatParent && me.floatParent.getTargetEl()) || me.container;
- return el.getConstrainVector(constrainTo);
- }
- },
- /**
- * Aligns this floating Component to the specified element
- *
- * @param {Ext.Component/Ext.Element/HTMLElement/String} element
- * The element or {@link Ext.Component} to align to. If passing a component, it must be a
- * omponent instance. If a string id is passed, it will be used as an element id.
- * @param {String} [position="tl-bl?"] The position to align to (see {@link
- * Ext.Element#alignTo} for more details).
- * @param {Number[]} [offsets] Offset the positioning by [x, y]
- * @return {Ext.Component} this
- */
- alignTo: function(element, position, offsets) {
- if (element.isComponent) {
- element = element.getEl();
- }
- var xy = this.el.getAlignToXY(element, position, offsets);
- this.setPagePosition(xy);
- return this;
- },
- /**
- * Brings this floating Component to the front of any other visible, floating Components managed by the same {@link
- * Ext.ZIndexManager ZIndexManager}
- *
- * If this Component is modal, inserts the modal mask just below this Component in the z-index stack.
- *
- * @param {Boolean} [preventFocus=false] Specify `true` to prevent the Component from being focused.
- * @return {Ext.Component} this
- */
- toFront: function(preventFocus) {
- var me = this;
- // Find the floating Component which provides the base for this Component's zIndexing.
- // That must move to front to then be able to rebase its zIndex stack and move this to the front
- if (me.zIndexParent) {
- me.zIndexParent.toFront(true);
- }
- if (me.zIndexManager.bringToFront(me)) {
- if (!Ext.isDefined(preventFocus)) {
- preventFocus = !me.focusOnToFront;
- }
- if (!preventFocus) {
- // Kick off a delayed focus request.
- // If another floating Component is toFronted before the delay expires
- // this will not receive focus.
- me.focus(false, true);
- }
- }
- return me;
- },
- /**
- * This method is called internally by {@link Ext.ZIndexManager} to signal that a floating Component has either been
- * moved to the top of its zIndex stack, or pushed from the top of its zIndex stack.
- *
- * If a _Window_ is superceded by another Window, deactivating it hides its shadow.
- *
- * This method also fires the {@link Ext.Component#activate activate} or
- * {@link Ext.Component#deactivate deactivate} event depending on which action occurred.
- *
- * @param {Boolean} [active=false] True to activate the Component, false to deactivate it.
- * @param {Ext.Component} [newActive] The newly active Component which is taking over topmost zIndex position.
- */
- setActive: function(active, newActive) {
- var me = this;
-
- if (active) {
- if (me.el.shadow && !me.maximized) {
- me.el.enableShadow(true);
- }
- me.fireEvent('activate', me);
- } else {
- // Only the *Windows* in a zIndex stack share a shadow. All other types of floaters
- // can keep their shadows all the time
- if ((me instanceof Ext.window.Window) && (newActive instanceof Ext.window.Window)) {
- me.el.disableShadow();
- }
- me.fireEvent('deactivate', me);
- }
- },
- /**
- * Sends this Component to the back of (lower z-index than) any other visible windows
- * @return {Ext.Component} this
- */
- toBack: function() {
- this.zIndexManager.sendToBack(this);
- return this;
- },
- /**
- * Center this Component in its container.
- * @return {Ext.Component} this
- */
- center: function() {
- var me = this,
- xy = me.el.getAlignToXY(me.container, 'c-c');
- me.setPagePosition(xy);
- return me;
- },
- // private
- syncShadow : function(){
- if (this.floating) {
- this.el.sync(true);
- }
- },
- // private
- fitContainer: function() {
- var parent = this.floatParent,
- container = parent ? parent.getTargetEl() : this.container,
- size = container.getViewSize(false);
- this.setSize(size);
- }
- });
- /**
- * Base Layout class - extended by ComponentLayout and ContainerLayout
- */
- Ext.define('Ext.layout.Layout', {
- /* Begin Definitions */
- /* End Definitions */
- isLayout: true,
- initialized: false,
- statics: {
- create: function(layout, defaultType) {
- var type;
- if (layout instanceof Ext.layout.Layout) {
- return Ext.createByAlias('layout.' + layout);
- } else {
- if (!layout || typeof layout === 'string') {
- type = layout || defaultType;
- layout = {};
- }
- else {
- type = layout.type || defaultType;
- }
- return Ext.createByAlias('layout.' + type, layout || {});
- }
- }
- },
- constructor : function(config) {
- this.id = Ext.id(null, this.type + '-');
- Ext.apply(this, config);
- },
- /**
- * @private
- */
- layout : function() {
- var me = this;
- me.layoutBusy = true;
- me.initLayout();
- if (me.beforeLayout.apply(me, arguments) !== false) {
- me.layoutCancelled = false;
- me.onLayout.apply(me, arguments);
- me.childrenChanged = false;
- me.owner.needsLayout = false;
- me.layoutBusy = false;
- me.afterLayout.apply(me, arguments);
- }
- else {
- me.layoutCancelled = true;
- }
- me.layoutBusy = false;
- me.doOwnerCtLayouts();
- },
- beforeLayout : function() {
- this.renderChildren();
- return true;
- },
- renderChildren: function () {
- this.renderItems(this.getLayoutItems(), this.getRenderTarget());
- },
- /**
- * @private
- * Iterates over all passed items, ensuring they are rendered. If the items are already rendered,
- * also determines if the items are in the proper place dom.
- */
- renderItems : function(items, target) {
- var me = this,
- ln = items.length,
- i = 0,
- item;
- for (; i < ln; i++) {
- item = items[i];
- if (item && !item.rendered) {
- me.renderItem(item, target, i);
- } else if (!me.isValidParent(item, target, i)) {
- me.moveItem(item, target, i);
- } else {
- // still need to configure the item, it may have moved in the container.
- me.configureItem(item);
- }
- }
- },
- // @private - Validates item is in the proper place in the dom.
- isValidParent : function(item, target, position) {
- var dom = item.el ? item.el.dom : Ext.getDom(item);
- if (dom && target && target.dom) {
- if (Ext.isNumber(position) && dom !== target.dom.childNodes[position]) {
- return false;
- }
- return (dom.parentNode == (target.dom || target));
- }
- return false;
- },
- /**
- * @private
- * Renders the given Component into the target Element.
- * @param {Ext.Component} item The Component to render
- * @param {Ext.Element} target The target Element
- * @param {Number} position The position within the target to render the item to
- */
- renderItem : function(item, target, position) {
- var me = this;
- if (!item.rendered) {
- if (me.itemCls) {
- item.addCls(me.itemCls);
- }
- if (me.owner.itemCls) {
- item.addCls(me.owner.itemCls);
- }
- item.render(target, position);
- me.configureItem(item);
- me.childrenChanged = true;
- }
- },
- /**
- * @private
- * Moved Component to the provided target instead.
- */
- moveItem : function(item, target, position) {
- // Make sure target is a dom element
- target = target.dom || target;
- if (typeof position == 'number') {
- position = target.childNodes[position];
- }
- target.insertBefore(item.el.dom, position || null);
- item.container = Ext.get(target);
- this.configureItem(item);
- this.childrenChanged = true;
- },
- /**
- * @private
- * Adds the layout's targetCls if necessary and sets
- * initialized flag when complete.
- */
- initLayout : function() {
- var me = this,
- targetCls = me.targetCls;
-
- if (!me.initialized && !Ext.isEmpty(targetCls)) {
- me.getTarget().addCls(targetCls);
- }
- me.initialized = true;
- },
- // @private Sets the layout owner
- setOwner : function(owner) {
- this.owner = owner;
- },
- // @private - Returns empty array
- getLayoutItems : function() {
- return [];
- },
- /**
- * @private
- * Applies itemCls
- * Empty template method
- */
- configureItem: Ext.emptyFn,
-
- // Placeholder empty functions for subclasses to extend
- onLayout : Ext.emptyFn,
- afterLayout : Ext.emptyFn,
- onRemove : Ext.emptyFn,
- onDestroy : Ext.emptyFn,
- doOwnerCtLayouts : Ext.emptyFn,
- /**
- * @private
- * Removes itemCls
- */
- afterRemove : function(item) {
- var el = item.el,
- owner = this.owner,
- itemCls = this.itemCls,
- ownerCls = owner.itemCls;
-
- // Clear managed dimensions flag when removed from the layout.
- if (item.rendered && !item.isDestroyed) {
- if (itemCls) {
- el.removeCls(itemCls);
- }
- if (ownerCls) {
- el.removeCls(ownerCls);
- }
- }
- // These flags are set at the time a child item is added to a layout.
- // The layout must decide if it is managing the item's width, or its height, or both.
- // See AbstractComponent for docs on these properties.
- delete item.layoutManagedWidth;
- delete item.layoutManagedHeight;
- },
- /**
- * Destroys this layout. This is a template method that is empty by default, but should be implemented
- * by subclasses that require explicit destruction to purge event handlers or remove DOM nodes.
- * @template
- */
- destroy : function() {
- var targetCls = this.targetCls,
- target;
-
- if (!Ext.isEmpty(targetCls)) {
- target = this.getTarget();
- if (target) {
- target.removeCls(targetCls);
- }
- }
- this.onDestroy();
- }
- });
- /**
- * @class Ext.ZIndexManager
- * <p>A class that manages a group of {@link Ext.Component#floating} Components and provides z-order management,
- * and Component activation behavior, including masking below the active (topmost) Component.</p>
- * <p>{@link Ext.Component#floating Floating} Components which are rendered directly into the document (such as {@link Ext.window.Window Window}s) which are
- * {@link Ext.Component#show show}n are managed by a {@link Ext.WindowManager global instance}.</p>
- * <p>{@link Ext.Component#floating Floating} Components which are descendants of {@link Ext.Component#floating floating} <i>Containers</i>
- * (for example a {@link Ext.view.BoundList BoundList} within an {@link Ext.window.Window Window}, or a {@link Ext.menu.Menu Menu}),
- * are managed by a ZIndexManager owned by that floating Container. Therefore ComboBox dropdowns within Windows will have managed z-indices
- * guaranteed to be correct, relative to the Window.</p>
- */
- Ext.define('Ext.ZIndexManager', {
- alternateClassName: 'Ext.WindowGroup',
- statics: {
- zBase : 9000
- },
- constructor: function(container) {
- var me = this;
- me.list = {};
- me.zIndexStack = [];
- me.front = null;
- if (container) {
- // This is the ZIndexManager for an Ext.container.Container, base its zseed on the zIndex of the Container's element
- if (container.isContainer) {
- container.on('resize', me._onContainerResize, me);
- me.zseed = Ext.Number.from(container.getEl().getStyle('zIndex'), me.getNextZSeed());
- // The containing element we will be dealing with (eg masking) is the content target
- me.targetEl = container.getTargetEl();
- me.container = container;
- }
- // This is the ZIndexManager for a DOM element
- else {
- Ext.EventManager.onWindowResize(me._onContainerResize, me);
- me.zseed = me.getNextZSeed();
- me.targetEl = Ext.get(container);
- }
- }
- // No container passed means we are the global WindowManager. Our target is the doc body.
- // DOM must be ready to collect that ref.
- else {
- Ext.EventManager.onWindowResize(me._onContainerResize, me);
- me.zseed = me.getNextZSeed();
- Ext.onDocumentReady(function() {
- me.targetEl = Ext.getBody();
- });
- }
- },
- getNextZSeed: function() {
- return (Ext.ZIndexManager.zBase += 10000);
- },
- setBase: function(baseZIndex) {
- this.zseed = baseZIndex;
- return this.assignZIndices();
- },
- // private
- assignZIndices: function() {
- var a = this.zIndexStack,
- len = a.length,
- i = 0,
- zIndex = this.zseed,
- comp;
- for (; i < len; i++) {
- comp = a[i];
- if (comp && !comp.hidden) {
- // Setting the zIndex of a Component returns the topmost zIndex consumed by
- // that Component.
- // If it's just a plain floating Component such as a BoundList, then the
- // return value is the passed value plus 10, ready for the next item.
- // If a floating *Container* has its zIndex set, it re-orders its managed
- // floating children, starting from that new base, and returns a value 10000 above
- // the highest zIndex which it allocates.
- zIndex = comp.setZIndex(zIndex);
- }
- }
- this._activateLast();
- return zIndex;
- },
- // private
- _setActiveChild: function(comp) {
- if (comp !== this.front) {
- if (this.front) {
- this.front.setActive(false, comp);
- }
- this.front = comp;
- if (comp) {
- comp.setActive(true);
- if (comp.modal) {
- this._showModalMask(comp);
- }
- }
- }
- },
- // private
- _activateLast: function(justHidden) {
- var comp,
- lastActivated = false,
- i;
- // Go down through the z-index stack.
- // Activate the next visible one down.
- // Keep going down to find the next visible modal one to shift the modal mask down under
- for (i = this.zIndexStack.length-1; i >= 0; --i) {
- comp = this.zIndexStack[i];
- if (!comp.hidden) {
- if (!lastActivated) {
- this._setActiveChild(comp);
- lastActivated = true;
- }
- // Move any modal mask down to just under the next modal floater down the stack
- if (comp.modal) {
- this._showModalMask(comp);
- return;
- }
- }
- }
- // none to activate, so there must be no modal mask.
- // And clear the currently active property
- this._hideModalMask();
- if (!lastActivated) {
- this._setActiveChild(null);
- }
- },
- _showModalMask: function(comp) {
- var zIndex = comp.el.getStyle('zIndex') - 4,
- maskTarget = comp.floatParent ? comp.floatParent.getTargetEl() : Ext.get(comp.getEl().dom.parentNode),
- parentBox;
-
- if (!maskTarget) {
- //<debug>
- Ext.global.console && Ext.global.console.warn && Ext.global.console.warn('mask target could not be found. Mask cannot be shown');
- //</debug>
- return;
- }
-
- parentBox = maskTarget.getBox();
- if (!this.mask) {
- this.mask = Ext.getBody().createChild({
- cls: Ext.baseCSSPrefix + 'mask'
- });
- this.mask.setVisibilityMode(Ext.Element.DISPLAY);
- this.mask.on('click', this._onMaskClick, this);
- }
- if (maskTarget.dom === document.body) {
- parentBox.height = Ext.Element.getViewHeight();
- }
- maskTarget.addCls(Ext.baseCSSPrefix + 'body-masked');
- this.mask.setBox(parentBox);
- this.mask.setStyle('zIndex', zIndex);
- this.mask.show();
- },
- _hideModalMask: function() {
- if (this.mask && this.mask.dom.parentNode) {
- Ext.get(this.mask.dom.parentNode).removeCls(Ext.baseCSSPrefix + 'body-masked');
- this.mask.hide();
- }
- },
- _onMaskClick: function() {
- if (this.front) {
- this.front.focus();
- }
- },
- _onContainerResize: function() {
- if (this.mask && this.mask.isVisible()) {
- this.mask.setSize(Ext.get(this.mask.dom.parentNode).getViewSize(true));
- }
- },
- /**
- * <p>Registers a floating {@link Ext.Component} with this ZIndexManager. This should not
- * need to be called under normal circumstances. Floating Components (such as Windows, BoundLists and Menus) are automatically registered
- * with a {@link Ext.Component#zIndexManager zIndexManager} at render time.</p>
- * <p>Where this may be useful is moving Windows between two ZIndexManagers. For example,
- * to bring the Ext.MessageBox dialog under the same manager as the Desktop's
- * ZIndexManager in the desktop sample app:</p><code><pre>
- MyDesktop.getDesktop().getManager().register(Ext.MessageBox);
- </pre></code>
- * @param {Ext.Component} comp The Component to register.
- */
- register : function(comp) {
- if (comp.zIndexManager) {
- comp.zIndexManager.unregister(comp);
- }
- comp.zIndexManager = this;
- this.list[comp.id] = comp;
- this.zIndexStack.push(comp);
- comp.on('hide', this._activateLast, this);
- },
- /**
- * <p>Unregisters a {@link Ext.Component} from this ZIndexManager. This should not
- * need to be called. Components are automatically unregistered upon destruction.
- * See {@link #register}.</p>
- * @param {Ext.Component} comp The Component to unregister.
- */
- unregister : function(comp) {
- delete comp.zIndexManager;
- if (this.list && this.list[comp.id]) {
- delete this.list[comp.id];
- comp.un('hide', this._activateLast);
- Ext.Array.remove(this.zIndexStack, comp);
- // Destruction requires that the topmost visible floater be activated. Same as hiding.
- this._activateLast(comp);
- }
- },
- /**
- * Gets a registered Component by id.
- * @param {String/Object} id The id of the Component or a {@link Ext.Component} instance
- * @return {Ext.Component}
- */
- get : function(id) {
- return typeof id == "object" ? id : this.list[id];
- },
- /**
- * Brings the specified Component to the front of any other active Components in this ZIndexManager.
- * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
- * @return {Boolean} True if the dialog was brought to the front, else false
- * if it was already in front
- */
- bringToFront : function(comp) {
- comp = this.get(comp);
- if (comp !== this.front) {
- Ext.Array.remove(this.zIndexStack, comp);
- this.zIndexStack.push(comp);
- this.assignZIndices();
- return true;
- }
- if (comp.modal) {
- this._showModalMask(comp);
- }
- return false;
- },
- /**
- * Sends the specified Component to the back of other active Components in this ZIndexManager.
- * @param {String/Object} comp The id of the Component or a {@link Ext.Component} instance
- * @return {Ext.Component} The Component
- */
- sendToBack : function(comp) {
- comp = this.get(comp);
- Ext.Array.remove(this.zIndexStack, comp);
- this.zIndexStack.unshift(comp);
- this.assignZIndices();
- return comp;
- },
- /**
- * Hides all Components managed by this ZIndexManager.
- */
- hideAll : function() {
- for (var id in this.list) {
- if (this.list[id].isComponent && this.list[id].isVisible()) {
- this.list[id].hide();
- }
- }
- },
- /**
- * @private
- * Temporarily hides all currently visible managed Components. This is for when
- * dragging a Window which may manage a set of floating descendants in its ZIndexManager;
- * they should all be hidden just for the duration of the drag.
- */
- hide: function() {
- var i = 0,
- ln = this.zIndexStack.length,
- comp;
- this.tempHidden = [];
- for (; i < ln; i++) {
- comp = this.zIndexStack[i];
- if (comp.isVisible()) {
- this.tempHidden.push(comp);
- comp.hide();
- }
- }
- },
- /**
- * @private
- * Restores temporarily hidden managed Components to visibility.
- */
- show: function() {
- var i = 0,
- ln = this.tempHidden.length,
- comp,
- x,
- y;
- for (; i < ln; i++) {
- comp = this.tempHidden[i];
- x = comp.x;
- y = comp.y;
- comp.show();
- comp.setPosition(x, y);
- }
- delete this.tempHidden;
- },
- /**
- * Gets the currently-active Component in this ZIndexManager.
- * @return {Ext.Component} The active Component
- */
- getActive : function() {
- return this.front;
- },
- /**
- * Returns zero or more Components in this ZIndexManager using the custom search function passed to this method.
- * The function should accept a single {@link Ext.Component} reference as its only argument and should
- * return true if the Component matches the search criteria, otherwise it should return false.
- * @param {Function} fn The search function
- * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Component being tested.
- * that gets passed to the function if not specified)
- * @return {Array} An array of zero or more matching windows
- */
- getBy : function(fn, scope) {
- var r = [],
- i = 0,
- len = this.zIndexStack.length,
- comp;
- for (; i < len; i++) {
- comp = this.zIndexStack[i];
- if (fn.call(scope||comp, comp) !== false) {
- r.push(comp);
- }
- }
- return r;
- },
- /**
- * Executes the specified function once for every Component in this ZIndexManager, passing each
- * Component as the only parameter. Returning false from the function will stop the iteration.
- * @param {Function} fn The function to execute for each item
- * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Component in the iteration.
- */
- each : function(fn, scope) {
- var comp;
- for (var id in this.list) {
- comp = this.list[id];
- if (comp.isComponent && fn.call(scope || comp, comp) === false) {
- return;
- }
- }
- },
- /**
- * Executes the specified function once for every Component in this ZIndexManager, passing each
- * Component as the only parameter. Returning false from the function will stop the iteration.
- * The components are passed to the function starting at the bottom and proceeding to the top.
- * @param {Function} fn The function to execute for each item
- * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function
- * is executed. Defaults to the current Component in the iteration.
- */
- eachBottomUp: function (fn, scope) {
- var comp,
- stack = this.zIndexStack,
- i, n;
- for (i = 0, n = stack.length ; i < n; i++) {
- comp = stack[i];
- if (comp.isComponent && fn.call(scope || comp, comp) === false) {
- return;
- }
- }
- },
- /**
- * Executes the specified function once for every Component in this ZIndexManager, passing each
- * Component as the only parameter. Returning false from the function will stop the iteration.
- * The components are passed to the function starting at the top and proceeding to the bottom.
- * @param {Function} fn The function to execute for each item
- * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function
- * is executed. Defaults to the current Component in the iteration.
- */
- eachTopDown: function (fn, scope) {
- var comp,
- stack = this.zIndexStack,
- i;
- for (i = stack.length ; i-- > 0; ) {
- comp = stack[i];
- if (comp.isComponent && fn.call(scope || comp, comp) === false) {
- return;
- }
- }
- },
- destroy: function() {
- this.each(function(c) {
- c.destroy();
- });
- delete this.zIndexStack;
- delete this.list;
- delete this.container;
- delete this.targetEl;
- }
- }, function() {
- /**
- * @class Ext.WindowManager
- * @extends Ext.ZIndexManager
- * <p>The default global floating Component group that is available automatically.</p>
- * <p>This manages instances of floating Components which were rendered programatically without
- * being added to a {@link Ext.container.Container Container}, and for floating Components which were added into non-floating Containers.</p>
- * <p><i>Floating</i> Containers create their own instance of ZIndexManager, and floating Components added at any depth below
- * there are managed by that ZIndexManager.</p>
- * @singleton
- */
- Ext.WindowManager = Ext.WindowMgr = new this();
- });
- /**
- * @private
- * Base class for Box Layout overflow handlers. These specialized classes are invoked when a Box Layout
- * (either an HBox or a VBox) has child items that are either too wide (for HBox) or too tall (for VBox)
- * for its container.
- */
- Ext.define('Ext.layout.container.boxOverflow.None', {
-
- alternateClassName: 'Ext.layout.boxOverflow.None',
-
- constructor: function(layout, config) {
- this.layout = layout;
- Ext.apply(this, config || {});
- },
- handleOverflow: Ext.emptyFn,
- clearOverflow: Ext.emptyFn,
-
- onRemove: Ext.emptyFn,
- /**
- * @private
- * Normalizes an item reference, string id or numerical index into a reference to the item
- * @param {Ext.Component/String/Number} item The item reference, id or index
- * @return {Ext.Component} The item
- */
- getItem: function(item) {
- return this.layout.owner.getComponent(item);
- },
-
- onRemove: Ext.emptyFn
- });
- /**
- * @class Ext.util.KeyMap
- * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
- * The constructor accepts the same config object as defined by {@link #addBinding}.
- * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
- * combination it will call the function with this signature (if the match is a multi-key
- * combination the callback will still be called only once): (String key, Ext.EventObject e)
- * A KeyMap can also handle a string representation of keys. By default KeyMap starts enabled.<br />
- * Usage:
- <pre><code>
- // map one key by key code
- var map = new Ext.util.KeyMap("my-element", {
- key: 13, // or Ext.EventObject.ENTER
- fn: myHandler,
- scope: myObject
- });
- // map multiple keys to one action by string
- var map = new Ext.util.KeyMap("my-element", {
- key: "a\r\n\t",
- fn: myHandler,
- scope: myObject
- });
- // map multiple keys to multiple actions by strings and array of codes
- var map = new Ext.util.KeyMap("my-element", [
- {
- key: [10,13],
- fn: function(){ alert("Return was pressed"); }
- }, {
- key: "abc",
- fn: function(){ alert('a, b or c was pressed'); }
- }, {
- key: "\t",
- ctrl:true,
- shift:true,
- fn: function(){ alert('Control + shift + tab was pressed.'); }
- }
- ]);
- </code></pre>
- */
- Ext.define('Ext.util.KeyMap', {
- alternateClassName: 'Ext.KeyMap',
- /**
- * Creates new KeyMap.
- * @param {String/HTMLElement/Ext.Element} el The element or its ID to bind to
- * @param {Object} binding The binding (see {@link #addBinding})
- * @param {String} [eventName="keydown"] The event to bind to
- */
- constructor: function(el, binding, eventName){
- var me = this;
- Ext.apply(me, {
- el: Ext.get(el),
- eventName: eventName || me.eventName,
- bindings: []
- });
- if (binding) {
- me.addBinding(binding);
- }
- me.enable();
- },
- eventName: 'keydown',
- /**
- * Add a new binding to this KeyMap. The following config object properties are supported:
- * <pre>
- Property Type Description
- ---------- --------------- ----------------------------------------------------------------------
- key String/Array A single keycode or an array of keycodes to handle
- shift Boolean True to handle key only when shift is pressed, False to handle the key only when shift is not pressed (defaults to undefined)
- ctrl Boolean True to handle key only when ctrl is pressed, False to handle the key only when ctrl is not pressed (defaults to undefined)
- alt Boolean True to handle key only when alt is pressed, False to handle the key only when alt is not pressed (defaults to undefined)
- handler Function The function to call when KeyMap finds the expected key combination
- fn Function Alias of handler (for backwards-compatibility)
- scope Object The scope of the callback function
- defaultEventAction String A default action to apply to the event. Possible values are: stopEvent, stopPropagation, preventDefault. If no value is set no action is performed.
- </pre>
- *
- * Usage:
- * <pre><code>
- // Create a KeyMap
- var map = new Ext.util.KeyMap(document, {
- key: Ext.EventObject.ENTER,
- fn: handleKey,
- scope: this
- });
- //Add a new binding to the existing KeyMap later
- map.addBinding({
- key: 'abc',
- shift: true,
- fn: handleKey,
- scope: this
- });
- </code></pre>
- * @param {Object/Object[]} binding A single KeyMap config or an array of configs
- */
- addBinding : function(binding){
- if (Ext.isArray(binding)) {
- Ext.each(binding, this.addBinding, this);
- return;
- }
- var keyCode = binding.key,
- processed = false,
- key,
- keys,
- keyString,
- i,
- len;
- if (Ext.isString(keyCode)) {
- keys = [];
- keyString = keyCode.toUpperCase();
- for (i = 0, len = keyString.length; i < len; ++i){
- keys.push(keyString.charCodeAt(i));
- }
- keyCode = keys;
- processed = true;
- }
- if (!Ext.isArray(keyCode)) {
- keyCode = [keyCode];
- }
- if (!processed) {
- for (i = 0, len = keyCode.length; i < len; ++i) {
- key = keyCode[i];
- if (Ext.isString(key)) {
- keyCode[i] = key.toUpperCase().charCodeAt(0);
- }
- }
- }
- this.bindings.push(Ext.apply({
- keyCode: keyCode
- }, binding));
- },
- /**
- * Process any keydown events on the element
- * @private
- * @param {Ext.EventObject} event
- */
- handleKeyDown: function(event) {
- if (this.enabled) { //just in case
- var bindings = this.bindings,
- i = 0,
- len = bindings.length;
- event = this.processEvent(event);
- for(; i < len; ++i){
- this.processBinding(bindings[i], event);
- }
- }
- },
- /**
- * Ugly hack to allow this class to be tested. Currently WebKit gives
- * no way to raise a key event properly with both
- * a) A keycode
- * b) The alt/ctrl/shift modifiers
- * So we have to simulate them here. Yuk!
- * This is a stub method intended to be overridden by tests.
- * More info: https://bugs.webkit.org/show_bug.cgi?id=16735
- * @private
- */
- processEvent: function(event){
- return event;
- },
- /**
- * Process a particular binding and fire the handler if necessary.
- * @private
- * @param {Object} binding The binding information
- * @param {Ext.EventObject} event
- */
- processBinding: function(binding, event){
- if (this.checkModifiers(binding, event)) {
- var key = event.getKey(),
- handler = binding.fn || binding.handler,
- scope = binding.scope || this,
- keyCode = binding.keyCode,
- defaultEventAction = binding.defaultEventAction,
- i,
- len,
- keydownEvent = new Ext.EventObjectImpl(event);
- for (i = 0, len = keyCode.length; i < len; ++i) {
- if (key === keyCode[i]) {
- if (handler.call(scope, key, event) !== true && defaultEventAction) {
- keydownEvent[defaultEventAction]();
- }
- break;
- }
- }
- }
- },
- /**
- * Check if the modifiers on the event match those on the binding
- * @private
- * @param {Object} binding
- * @param {Ext.EventObject} event
- * @return {Boolean} True if the event matches the binding
- */
- checkModifiers: function(binding, e){
- var keys = ['shift', 'ctrl', 'alt'],
- i = 0,
- len = keys.length,
- val, key;
- for (; i < len; ++i){
- key = keys[i];
- val = binding[key];
- if (!(val === undefined || (val === e[key + 'Key']))) {
- return false;
- }
- }
- return true;
- },
- /**
- * Shorthand for adding a single key listener
- * @param {Number/Number[]/Object} key Either the numeric key code, array of key codes or an object with the
- * following options:
- * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
- * @param {Function} fn The function to call
- * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
- */
- on: function(key, fn, scope) {
- var keyCode, shift, ctrl, alt;
- if (Ext.isObject(key) && !Ext.isArray(key)) {
- keyCode = key.key;
- shift = key.shift;
- ctrl = key.ctrl;
- alt = key.alt;
- } else {
- keyCode = key;
- }
- this.addBinding({
- key: keyCode,
- shift: shift,
- ctrl: ctrl,
- alt: alt,
- fn: fn,
- scope: scope
- });
- },
- /**
- * Returns true if this KeyMap is enabled
- * @return {Boolean}
- */
- isEnabled : function(){
- return this.enabled;
- },
- /**
- * Enables this KeyMap
- */
- enable: function(){
- var me = this;
-
- if (!me.enabled) {
- me.el.on(me.eventName, me.handleKeyDown, me);
- me.enabled = true;
- }
- },
- /**
- * Disable this KeyMap
- */
- disable: function(){
- var me = this;
-
- if (me.enabled) {
- me.el.removeListener(me.eventName, me.handleKeyDown, me);
- me.enabled = false;
- }
- },
- /**
- * Convenience function for setting disabled/enabled by boolean.
- * @param {Boolean} disabled
- */
- setDisabled : function(disabled){
- if (disabled) {
- this.disable();
- } else {
- this.enable();
- }
- },
- /**
- * Destroys the KeyMap instance and removes all handlers.
- * @param {Boolean} removeEl True to also remove the attached element
- */
- destroy: function(removeEl){
- var me = this;
- me.bindings = [];
- me.disable();
- if (removeEl === true) {
- me.el.remove();
- }
- delete me.el;
- }
- });
- /**
- * @class Ext.util.ClickRepeater
- * @extends Ext.util.Observable
- *
- * A wrapper class which can be applied to any element. Fires a "click" event while the
- * mouse is pressed. The interval between firings may be specified in the config but
- * defaults to 20 milliseconds.
- *
- * Optionally, a CSS class may be applied to the element during the time it is pressed.
- *
- */
- Ext.define('Ext.util.ClickRepeater', {
- extend: 'Ext.util.Observable',
- /**
- * Creates new ClickRepeater.
- * @param {String/HTMLElement/Ext.Element} el The element or its ID to listen on
- * @param {Object} config (optional) Config object.
- */
- constructor : function(el, config){
- this.el = Ext.get(el);
- this.el.unselectable();
- Ext.apply(this, config);
- this.addEvents(
- /**
- * @event mousedown
- * Fires when the mouse button is depressed.
- * @param {Ext.util.ClickRepeater} this
- * @param {Ext.EventObject} e
- */
- "mousedown",
- /**
- * @event click
- * Fires on a specified interval during the time the element is pressed.
- * @param {Ext.util.ClickRepeater} this
- * @param {Ext.EventObject} e
- */
- "click",
- /**
- * @event mouseup
- * Fires when the mouse key is released.
- * @param {Ext.util.ClickRepeater} this
- * @param {Ext.EventObject} e
- */
- "mouseup"
- );
- if(!this.disabled){
- this.disabled = true;
- this.enable();
- }
- // allow inline handler
- if(this.handler){
- this.on("click", this.handler, this.scope || this);
- }
- this.callParent();
- },
- /**
- * @cfg {String/HTMLElement/Ext.Element} el The element to act as a button.
- */
- /**
- * @cfg {String} pressedCls A CSS class name to be applied to the element while pressed.
- */
- /**
- * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
- * "interval" and "delay" are ignored.
- */
- /**
- * @cfg {Number} interval The interval between firings of the "click" event. Default 20 ms.
- */
- interval : 20,
- /**
- * @cfg {Number} delay The initial delay before the repeating event begins firing.
- * Similar to an autorepeat key delay.
- */
- delay: 250,
- /**
- * @cfg {Boolean} preventDefault True to prevent the default click event
- */
- preventDefault : true,
- /**
- * @cfg {Boolean} stopDefault True to stop the default click event
- */
- stopDefault : false,
- timer : 0,
- /**
- * Enables the repeater and allows events to fire.
- */
- enable: function(){
- if(this.disabled){
- this.el.on('mousedown', this.handleMouseDown, this);
- if (Ext.isIE){
- this.el.on('dblclick', this.handleDblClick, this);
- }
- if(this.preventDefault || this.stopDefault){
- this.el.on('click', this.eventOptions, this);
- }
- }
- this.disabled = false;
- },
- /**
- * Disables the repeater and stops events from firing.
- */
- disable: function(/* private */ force){
- if(force || !this.disabled){
- clearTimeout(this.timer);
- if(this.pressedCls){
- this.el.removeCls(this.pressedCls);
- }
- Ext.getDoc().un('mouseup', this.handleMouseUp, this);
- this.el.removeAllListeners();
- }
- this.disabled = true;
- },
- /**
- * Convenience function for setting disabled/enabled by boolean.
- * @param {Boolean} disabled
- */
- setDisabled: function(disabled){
- this[disabled ? 'disable' : 'enable']();
- },
- eventOptions: function(e){
- if(this.preventDefault){
- e.preventDefault();
- }
- if(this.stopDefault){
- e.stopEvent();
- }
- },
- // private
- destroy : function() {
- this.disable(true);
- Ext.destroy(this.el);
- this.clearListeners();
- },
- handleDblClick : function(e){
- clearTimeout(this.timer);
- this.el.blur();
- this.fireEvent("mousedown", this, e);
- this.fireEvent("click", this, e);
- },
- // private
- handleMouseDown : function(e){
- clearTimeout(this.timer);
- this.el.blur();
- if(this.pressedCls){
- this.el.addCls(this.pressedCls);
- }
- this.mousedownTime = new Date();
- Ext.getDoc().on("mouseup", this.handleMouseUp, this);
- this.el.on("mouseout", this.handleMouseOut, this);
- this.fireEvent("mousedown", this, e);
- this.fireEvent("click", this, e);
- // Do not honor delay or interval if acceleration wanted.
- if (this.accelerate) {
- this.delay = 400;
- }
- // Re-wrap the event object in a non-shared object, so it doesn't lose its context if
- // the global shared EventObject gets a new Event put into it before the timer fires.
- e = new Ext.EventObjectImpl(e);
- this.timer = Ext.defer(this.click, this.delay || this.interval, this, [e]);
- },
- // private
- click : function(e){
- this.fireEvent("click", this, e);
- this.timer = Ext.defer(this.click, this.accelerate ?
- this.easeOutExpo(Ext.Date.getElapsed(this.mousedownTime),
- 400,
- -390,
- 12000) :
- this.interval, this, [e]);
- },
- easeOutExpo : function (t, b, c, d) {
- return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
- },
- // private
- handleMouseOut : function(){
- clearTimeout(this.timer);
- if(this.pressedCls){
- this.el.removeCls(this.pressedCls);
- }
- this.el.on("mouseover", this.handleMouseReturn, this);
- },
- // private
- handleMouseReturn : function(){
- this.el.un("mouseover", this.handleMouseReturn, this);
- if(this.pressedCls){
- this.el.addCls(this.pressedCls);
- }
- this.click();
- },
- // private
- handleMouseUp : function(e){
- clearTimeout(this.timer);
- this.el.un("mouseover", this.handleMouseReturn, this);
- this.el.un("mouseout", this.handleMouseOut, this);
- Ext.getDoc().un("mouseup", this.handleMouseUp, this);
- if(this.pressedCls){
- this.el.removeCls(this.pressedCls);
- }
- this.fireEvent("mouseup", this, e);
- }
- });
- /**
- * @class Ext.layout.component.Component
- * @extends Ext.layout.Layout
- *
- * This class is intended to be extended or created via the {@link Ext.Component#componentLayout layout}
- * configuration property. See {@link Ext.Component#componentLayout} for additional details.
- *
- * @private
- */
- Ext.define('Ext.layout.component.Component', {
- /* Begin Definitions */
- extend: 'Ext.layout.Layout',
- /* End Definitions */
- type: 'component',
- monitorChildren: true,
- initLayout : function() {
- var me = this,
- owner = me.owner,
- ownerEl = owner.el;
- if (!me.initialized) {
- if (owner.frameSize) {
- me.frameSize = owner.frameSize;
- }
- else {
- owner.frameSize = me.frameSize = {
- top: 0,
- left: 0,
- bottom: 0,
- right: 0
- };
- }
- }
- me.callParent(arguments);
- },
- beforeLayout : function(width, height, isSetSize, callingContainer) {
- this.callParent(arguments);
- var me = this,
- owner = me.owner,
- ownerCt = owner.ownerCt,
- layout = owner.layout,
- isVisible = owner.isVisible(true),
- ownerElChild = owner.el.child,
- layoutCollection;
- // Cache the size we began with so we can see if there has been any effect.
- me.previousComponentSize = me.lastComponentSize;
- // Do not allow autoing of any dimensions which are fixed
- if (!isSetSize
- && ((!Ext.isNumber(width) && owner.isFixedWidth()) ||
- (!Ext.isNumber(height) && owner.isFixedHeight()))
- // unless we are being told to do so by the ownerCt's layout
- && callingContainer && callingContainer !== ownerCt) {
-
- me.doContainerLayout();
- return false;
- }
- // If an ownerCt is hidden, add my reference onto the layoutOnShow stack. Set the needsLayout flag.
- // If the owner itself is a directly hidden floater, set the needsLayout object on that for when it is shown.
- if (!isVisible && (owner.hiddenAncestor || owner.floating)) {
- if (owner.hiddenAncestor) {
- layoutCollection = owner.hiddenAncestor.layoutOnShow;
- layoutCollection.remove(owner);
- layoutCollection.add(owner);
- }
- owner.needsLayout = {
- width: width,
- height: height,
- isSetSize: false
- };
- }
- if (isVisible && this.needsLayout(width, height)) {
- return owner.beforeComponentLayout(width, height, isSetSize, callingContainer);
- }
- else {
- return false;
- }
- },
- /**
- * Check if the new size is different from the current size and only
- * trigger a layout if it is necessary.
- * @param {Number} width The new width to set.
- * @param {Number} height The new height to set.
- */
- needsLayout : function(width, height) {
- var me = this,
- widthBeingChanged,
- heightBeingChanged;
- me.lastComponentSize = me.lastComponentSize || {
- width: -Infinity,
- height: -Infinity
- };
- // If autoWidthing, or an explicitly different width is passed, then the width is being changed.
- widthBeingChanged = !Ext.isDefined(width) || me.lastComponentSize.width !== width;
- // If autoHeighting, or an explicitly different height is passed, then the height is being changed.
- heightBeingChanged = !Ext.isDefined(height) || me.lastComponentSize.height !== height;
- // isSizing flag added to prevent redundant layouts when going up the layout chain
- return !me.isSizing && (me.childrenChanged || widthBeingChanged || heightBeingChanged);
- },
- /**
- * Set the size of any element supporting undefined, null, and values.
- * @param {Number} width The new width to set.
- * @param {Number} height The new height to set.
- */
- setElementSize: function(el, width, height) {
- if (width !== undefined && height !== undefined) {
- el.setSize(width, height);
- }
- else if (height !== undefined) {
- el.setHeight(height);
- }
- else if (width !== undefined) {
- el.setWidth(width);
- }
- },
- /**
- * Returns the owner component's resize element.
- * @return {Ext.Element}
- */
- getTarget : function() {
- return this.owner.el;
- },
- /**
- * <p>Returns the element into which rendering must take place. Defaults to the owner Component's encapsulating element.</p>
- * May be overridden in Component layout managers which implement an inner element.
- * @return {Ext.Element}
- */
- getRenderTarget : function() {
- return this.owner.el;
- },
- /**
- * Set the size of the target element.
- * @param {Number} width The new width to set.
- * @param {Number} height The new height to set.
- */
- setTargetSize : function(width, height) {
- var me = this;
- me.setElementSize(me.owner.el, width, height);
- if (me.owner.frameBody) {
- var targetInfo = me.getTargetInfo(),
- padding = targetInfo.padding,
- border = targetInfo.border,
- frameSize = me.frameSize;
- me.setElementSize(me.owner.frameBody,
- Ext.isNumber(width) ? (width - frameSize.left - frameSize.right - padding.left - padding.right - border.left - border.right) : width,
- Ext.isNumber(height) ? (height - frameSize.top - frameSize.bottom - padding.top - padding.bottom - border.top - border.bottom) : height
- );
- }
- me.autoSized = {
- width: !Ext.isNumber(width),
- height: !Ext.isNumber(height)
- };
- me.lastComponentSize = {
- width: width,
- height: height
- };
- },
- getTargetInfo : function() {
- if (!this.targetInfo) {
- var target = this.getTarget(),
- body = this.owner.getTargetEl();
- this.targetInfo = {
- padding: {
- top: target.getPadding('t'),
- right: target.getPadding('r'),
- bottom: target.getPadding('b'),
- left: target.getPadding('l')
- },
- border: {
- top: target.getBorderWidth('t'),
- right: target.getBorderWidth('r'),
- bottom: target.getBorderWidth('b'),
- left: target.getBorderWidth('l')
- },
- bodyMargin: {
- top: body.getMargin('t'),
- right: body.getMargin('r'),
- bottom: body.getMargin('b'),
- left: body.getMargin('l')
- }
- };
- }
- return this.targetInfo;
- },
- // Start laying out UP the ownerCt's layout when flagged to do so.
- doOwnerCtLayouts: function() {
- var owner = this.owner,
- ownerCt = owner.ownerCt,
- ownerCtComponentLayout, ownerCtContainerLayout,
- curSize = this.lastComponentSize,
- prevSize = this.previousComponentSize,
- widthChange = (prevSize && curSize && Ext.isNumber(curSize.width )) ? curSize.width !== prevSize.width : true,
- heightChange = (prevSize && curSize && Ext.isNumber(curSize.height)) ? curSize.height !== prevSize.height : true;
- // If size has not changed, do not inform upstream layouts
- if (!ownerCt || (!widthChange && !heightChange)) {
- return;
- }
- ownerCtComponentLayout = ownerCt.componentLayout;
- ownerCtContainerLayout = ownerCt.layout;
- if (!owner.floating && ownerCtComponentLayout && ownerCtComponentLayout.monitorChildren && !ownerCtComponentLayout.layoutBusy) {
- if (!ownerCt.suspendLayout && ownerCtContainerLayout && !ownerCtContainerLayout.layoutBusy) {
- // If the owning Container may be adjusted in any of the the dimension which have changed, perform its Component layout
- if (((widthChange && !ownerCt.isFixedWidth()) || (heightChange && !ownerCt.isFixedHeight()))) {
- // Set the isSizing flag so that the upstream Container layout (called after a Component layout) can omit this component from sizing operations
- this.isSizing = true;
- ownerCt.doComponentLayout();
- this.isSizing = false;
- }
- // Execute upstream Container layout
- else if (ownerCtContainerLayout.bindToOwnerCtContainer === true) {
- ownerCtContainerLayout.layout();
- }
- }
- }
- },
- doContainerLayout: function() {
- var me = this,
- owner = me.owner,
- ownerCt = owner.ownerCt,
- layout = owner.layout,
- ownerCtComponentLayout;
- // Run the container layout if it exists (layout for child items)
- // **Unless automatic laying out is suspended, or the layout is currently running**
- if (!owner.suspendLayout && layout && layout.isLayout && !layout.layoutBusy && !layout.isAutoDock) {
- layout.layout();
- }
- // Tell the ownerCt that it's child has changed and can be re-layed by ignoring the lastComponentSize cache.
- if (ownerCt && ownerCt.componentLayout) {
- ownerCtComponentLayout = ownerCt.componentLayout;
- if (!owner.floating && ownerCtComponentLayout.monitorChildren && !ownerCtComponentLayout.layoutBusy) {
- ownerCtComponentLayout.childrenChanged = true;
- }
- }
- },
- afterLayout : function(width, height, isSetSize, layoutOwner) {
- this.doContainerLayout();
- this.owner.afterComponentLayout(width, height, isSetSize, layoutOwner);
- }
- });
- /**
- * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
- * wide, in pixels, a given block of text will be. Note that when measuring text, it should be plain text and
- * should not contain any HTML, otherwise it may not be measured correctly.
- *
- * The measurement works by copying the relevant CSS styles that can affect the font related display,
- * then checking the size of an element that is auto-sized. Note that if the text is multi-lined, you must
- * provide a **fixed width** when doing the measurement.
- *
- * If multiple measurements are being done on the same element, you create a new instance to initialize
- * to avoid the overhead of copying the styles to the element repeatedly.
- */
- Ext.define('Ext.util.TextMetrics', {
- statics: {
- shared: null,
- /**
- * Measures the size of the specified text
- * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
- * that can affect the size of the rendered text
- * @param {String} text The text to measure
- * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
- * in order to accurately measure the text height
- * @return {Object} An object containing the text's size `{width: (width), height: (height)}`
- */
- measure: function(el, text, fixedWidth){
- var me = this,
- shared = me.shared;
-
- if(!shared){
- shared = me.shared = new me(el, fixedWidth);
- }
- shared.bind(el);
- shared.setFixedWidth(fixedWidth || 'auto');
- return shared.getSize(text);
- },
-
- /**
- * Destroy the TextMetrics instance created by {@link #measure}.
- */
- destroy: function(){
- var me = this;
- Ext.destroy(me.shared);
- me.shared = null;
- }
- },
-
- /**
- * Creates new TextMetrics.
- * @param {String/HTMLElement/Ext.Element} bindTo The element or its ID to bind to.
- * @param {Number} fixedWidth (optional) A fixed width to apply to the measuring element.
- */
- constructor: function(bindTo, fixedWidth){
- var measure = this.measure = Ext.getBody().createChild({
- cls: 'x-textmetrics'
- });
- this.el = Ext.get(bindTo);
-
- measure.position('absolute');
- measure.setLeftTop(-1000, -1000);
- measure.hide();
- if (fixedWidth) {
- measure.setWidth(fixedWidth);
- }
- },
-
- /**
- * Returns the size of the specified text based on the internal element's style and width properties
- * @param {String} text The text to measure
- * @return {Object} An object containing the text's size `{width: (width), height: (height)}`
- */
- getSize: function(text){
- var measure = this.measure,
- size;
-
- measure.update(text);
- size = measure.getSize();
- measure.update('');
- return size;
- },
-
- /**
- * Binds this TextMetrics instance to a new element
- * @param {String/HTMLElement/Ext.Element} el The element or its ID.
- */
- bind: function(el){
- var me = this;
-
- me.el = Ext.get(el);
- me.measure.setStyle(
- me.el.getStyles('font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing')
- );
- },
-
- /**
- * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
- * to set a fixed width in order to accurately measure the text height.
- * @param {Number} width The width to set on the element
- */
- setFixedWidth : function(width){
- this.measure.setWidth(width);
- },
-
- /**
- * Returns the measured width of the specified text
- * @param {String} text The text to measure
- * @return {Number} width The width in pixels
- */
- getWidth : function(text){
- this.measure.dom.style.width = 'auto';
- return this.getSize(text).width;
- },
-
- /**
- * Returns the measured height of the specified text
- * @param {String} text The text to measure
- * @return {Number} height The height in pixels
- */
- getHeight : function(text){
- return this.getSize(text).height;
- },
-
- /**
- * Destroy this instance
- */
- destroy: function(){
- var me = this;
- me.measure.remove();
- delete me.el;
- delete me.measure;
- }
- }, function(){
- Ext.Element.addMethods({
- /**
- * Returns the width in pixels of the passed text, or the width of the text in this Element.
- * @param {String} text The text to measure. Defaults to the innerHTML of the element.
- * @param {Number} min (optional) The minumum value to return.
- * @param {Number} max (optional) The maximum value to return.
- * @return {Number} The text width in pixels.
- * @member Ext.Element
- */
- getTextWidth : function(text, min, max){
- return Ext.Number.constrain(Ext.util.TextMetrics.measure(this.dom, Ext.value(text, this.dom.innerHTML, true)).width, min || 0, max || 1000000);
- }
- });
- });
- /**
- * @class Ext.layout.container.boxOverflow.Scroller
- * @extends Ext.layout.container.boxOverflow.None
- * @private
- */
- Ext.define('Ext.layout.container.boxOverflow.Scroller', {
- /* Begin Definitions */
- extend: 'Ext.layout.container.boxOverflow.None',
- requires: ['Ext.util.ClickRepeater', 'Ext.Element'],
- alternateClassName: 'Ext.layout.boxOverflow.Scroller',
- mixins: {
- observable: 'Ext.util.Observable'
- },
-
- /* End Definitions */
- /**
- * @cfg {Boolean} animateScroll
- * True to animate the scrolling of items within the layout (ignored if enableScroll is false)
- */
- animateScroll: false,
- /**
- * @cfg {Number} scrollIncrement
- * The number of pixels to scroll by on scroller click
- */
- scrollIncrement: 20,
- /**
- * @cfg {Number} wheelIncrement
- * The number of pixels to increment on mouse wheel scrolling.
- */
- wheelIncrement: 10,
- /**
- * @cfg {Number} scrollRepeatInterval
- * Number of milliseconds between each scroll while a scroller button is held down
- */
- scrollRepeatInterval: 60,
- /**
- * @cfg {Number} scrollDuration
- * Number of milliseconds that each scroll animation lasts
- */
- scrollDuration: 400,
- /**
- * @cfg {String} beforeCtCls
- * CSS class added to the beforeCt element. This is the element that holds any special items such as scrollers,
- * which must always be present at the leftmost edge of the Container
- */
- /**
- * @cfg {String} afterCtCls
- * CSS class added to the afterCt element. This is the element that holds any special items such as scrollers,
- * which must always be present at the rightmost edge of the Container
- */
- /**
- * @cfg {String} [scrollerCls='x-box-scroller']
- * CSS class added to both scroller elements if enableScroll is used
- */
- scrollerCls: Ext.baseCSSPrefix + 'box-scroller',
- /**
- * @cfg {String} beforeScrollerCls
- * CSS class added to the left scroller element if enableScroll is used
- */
- /**
- * @cfg {String} afterScrollerCls
- * CSS class added to the right scroller element if enableScroll is used
- */
-
- constructor: function(layout, config) {
- this.layout = layout;
- Ext.apply(this, config || {});
-
- this.addEvents(
- /**
- * @event scroll
- * @param {Ext.layout.container.boxOverflow.Scroller} scroller The layout scroller
- * @param {Number} newPosition The new position of the scroller
- * @param {Boolean/Object} animate If animating or not. If true, it will be a animation configuration, else it will be false
- */
- 'scroll'
- );
- },
-
- initCSSClasses: function() {
- var me = this,
- layout = me.layout;
- if (!me.CSSinitialized) {
- me.beforeCtCls = me.beforeCtCls || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelBefore;
- me.afterCtCls = me.afterCtCls || Ext.baseCSSPrefix + 'box-scroller-' + layout.parallelAfter;
- me.beforeScrollerCls = me.beforeScrollerCls || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelBefore;
- me.afterScrollerCls = me.afterScrollerCls || Ext.baseCSSPrefix + layout.owner.getXType() + '-scroll-' + layout.parallelAfter;
- me.CSSinitializes = true;
- }
- },
- handleOverflow: function(calculations, targetSize) {
- var me = this,
- layout = me.layout,
- methodName = 'get' + layout.parallelPrefixCap,
- newSize = {};
- me.initCSSClasses();
- me.callParent(arguments);
- this.createInnerElements();
- this.showScrollers();
- newSize[layout.perpendicularPrefix] = targetSize[layout.perpendicularPrefix];
- newSize[layout.parallelPrefix] = targetSize[layout.parallelPrefix] - (me.beforeCt[methodName]() + me.afterCt[methodName]());
- return { targetSize: newSize };
- },
- /**
- * @private
- * Creates the beforeCt and afterCt elements if they have not already been created
- */
- createInnerElements: function() {
- var me = this,
- target = me.layout.getRenderTarget();
- //normal items will be rendered to the innerCt. beforeCt and afterCt allow for fixed positioning of
- //special items such as scrollers or dropdown menu triggers
- if (!me.beforeCt) {
- target.addCls(Ext.baseCSSPrefix + me.layout.direction + '-box-overflow-body');
- me.beforeCt = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.beforeCtCls}, 'before');
- me.afterCt = target.insertSibling({cls: Ext.layout.container.Box.prototype.innerCls + ' ' + me.afterCtCls}, 'after');
- me.createWheelListener();
- }
- },
- /**
- * @private
- * Sets up an listener to scroll on the layout's innerCt mousewheel event
- */
- createWheelListener: function() {
- this.layout.innerCt.on({
- scope : this,
- mousewheel: function(e) {
- e.stopEvent();
- this.scrollBy(e.getWheelDelta() * this.wheelIncrement * -1, false);
- }
- });
- },
- /**
- * @private
- */
- clearOverflow: function() {
- this.hideScrollers();
- },
- /**
- * @private
- * Shows the scroller elements in the beforeCt and afterCt. Creates the scrollers first if they are not already
- * present.
- */
- showScrollers: function() {
- this.createScrollers();
- this.beforeScroller.show();
- this.afterScroller.show();
- this.updateScrollButtons();
-
- this.layout.owner.addClsWithUI('scroller');
- },
- /**
- * @private
- * Hides the scroller elements in the beforeCt and afterCt
- */
- hideScrollers: function() {
- if (this.beforeScroller != undefined) {
- this.beforeScroller.hide();
- this.afterScroller.hide();
-
- this.layout.owner.removeClsWithUI('scroller');
- }
- },
- /**
- * @private
- * Creates the clickable scroller elements and places them into the beforeCt and afterCt
- */
- createScrollers: function() {
- if (!this.beforeScroller && !this.afterScroller) {
- var before = this.beforeCt.createChild({
- cls: Ext.String.format("{0} {1} ", this.scrollerCls, this.beforeScrollerCls)
- });
- var after = this.afterCt.createChild({
- cls: Ext.String.format("{0} {1}", this.scrollerCls, this.afterScrollerCls)
- });
- before.addClsOnOver(this.beforeScrollerCls + '-hover');
- after.addClsOnOver(this.afterScrollerCls + '-hover');
- before.setVisibilityMode(Ext.Element.DISPLAY);
- after.setVisibilityMode(Ext.Element.DISPLAY);
- this.beforeRepeater = Ext.create('Ext.util.ClickRepeater', before, {
- interval: this.scrollRepeatInterval,
- handler : this.scrollLeft,
- scope : this
- });
- this.afterRepeater = Ext.create('Ext.util.ClickRepeater', after, {
- interval: this.scrollRepeatInterval,
- handler : this.scrollRight,
- scope : this
- });
- /**
- * @property beforeScroller
- * @type Ext.Element
- * The left scroller element. Only created when needed.
- */
- this.beforeScroller = before;
- /**
- * @property afterScroller
- * @type Ext.Element
- * The left scroller element. Only created when needed.
- */
- this.afterScroller = after;
- }
- },
- /**
- * @private
- */
- destroy: function() {
- Ext.destroy(this.beforeRepeater, this.afterRepeater, this.beforeScroller, this.afterScroller, this.beforeCt, this.afterCt);
- },
- /**
- * @private
- * Scrolls left or right by the number of pixels specified
- * @param {Number} delta Number of pixels to scroll to the right by. Use a negative number to scroll left
- */
- scrollBy: function(delta, animate) {
- this.scrollTo(this.getScrollPosition() + delta, animate);
- },
- /**
- * @private
- * @return {Object} Object passed to scrollTo when scrolling
- */
- getScrollAnim: function() {
- return {
- duration: this.scrollDuration,
- callback: this.updateScrollButtons,
- scope : this
- };
- },
- /**
- * @private
- * Enables or disables each scroller button based on the current scroll position
- */
- updateScrollButtons: function() {
- if (this.beforeScroller == undefined || this.afterScroller == undefined) {
- return;
- }
- var beforeMeth = this.atExtremeBefore() ? 'addCls' : 'removeCls',
- afterMeth = this.atExtremeAfter() ? 'addCls' : 'removeCls',
- beforeCls = this.beforeScrollerCls + '-disabled',
- afterCls = this.afterScrollerCls + '-disabled';
-
- this.beforeScroller[beforeMeth](beforeCls);
- this.afterScroller[afterMeth](afterCls);
- this.scrolling = false;
- },
- /**
- * @private
- * Returns true if the innerCt scroll is already at its left-most point
- * @return {Boolean} True if already at furthest left point
- */
- atExtremeBefore: function() {
- return this.getScrollPosition() === 0;
- },
- /**
- * @private
- * Scrolls to the left by the configured amount
- */
- scrollLeft: function() {
- this.scrollBy(-this.scrollIncrement, false);
- },
- /**
- * @private
- * Scrolls to the right by the configured amount
- */
- scrollRight: function() {
- this.scrollBy(this.scrollIncrement, false);
- },
- /**
- * Returns the current scroll position of the innerCt element
- * @return {Number} The current scroll position
- */
- getScrollPosition: function(){
- var layout = this.layout;
- return parseInt(layout.innerCt.dom['scroll' + layout.parallelBeforeCap], 10) || 0;
- },
- /**
- * @private
- * Returns the maximum value we can scrollTo
- * @return {Number} The max scroll value
- */
- getMaxScrollPosition: function() {
- var layout = this.layout;
- return layout.innerCt.dom['scroll' + layout.parallelPrefixCap] - this.layout.innerCt['get' + layout.parallelPrefixCap]();
- },
- /**
- * @private
- * Returns true if the innerCt scroll is already at its right-most point
- * @return {Boolean} True if already at furthest right point
- */
- atExtremeAfter: function() {
- return this.getScrollPosition() >= this.getMaxScrollPosition();
- },
- /**
- * @private
- * Scrolls to the given position. Performs bounds checking.
- * @param {Number} position The position to scroll to. This is constrained.
- * @param {Boolean} animate True to animate. If undefined, falls back to value of this.animateScroll
- */
- scrollTo: function(position, animate) {
- var me = this,
- layout = me.layout,
- oldPosition = me.getScrollPosition(),
- newPosition = Ext.Number.constrain(position, 0, me.getMaxScrollPosition());
- if (newPosition != oldPosition && !me.scrolling) {
- if (animate == undefined) {
- animate = me.animateScroll;
- }
- layout.innerCt.scrollTo(layout.parallelBefore, newPosition, animate ? me.getScrollAnim() : false);
- if (animate) {
- me.scrolling = true;
- } else {
- me.scrolling = false;
- me.updateScrollButtons();
- }
-
- me.fireEvent('scroll', me, newPosition, animate ? me.getScrollAnim() : false);
- }
- },
- /**
- * Scrolls to the given component.
- * @param {String/Number/Ext.Component} item The item to scroll to. Can be a numerical index, component id
- * or a reference to the component itself.
- * @param {Boolean} animate True to animate the scrolling
- */
- scrollToItem: function(item, animate) {
- var me = this,
- layout = me.layout,
- visibility,
- box,
- newPos;
- item = me.getItem(item);
- if (item != undefined) {
- visibility = this.getItemVisibility(item);
- if (!visibility.fullyVisible) {
- box = item.getBox(true, true);
- newPos = box[layout.parallelPosition];
- if (visibility.hiddenEnd) {
- newPos -= (this.layout.innerCt['get' + layout.parallelPrefixCap]() - box[layout.parallelPrefix]);
- }
- this.scrollTo(newPos, animate);
- }
- }
- },
- /**
- * @private
- * For a given item in the container, return an object with information on whether the item is visible
- * with the current innerCt scroll value.
- * @param {Ext.Component} item The item
- * @return {Object} Values for fullyVisible, hiddenStart and hiddenEnd
- */
- getItemVisibility: function(item) {
- var me = this,
- box = me.getItem(item).getBox(true, true),
- layout = me.layout,
- itemStart = box[layout.parallelPosition],
- itemEnd = itemStart + box[layout.parallelPrefix],
- scrollStart = me.getScrollPosition(),
- scrollEnd = scrollStart + layout.innerCt['get' + layout.parallelPrefixCap]();
- return {
- hiddenStart : itemStart < scrollStart,
- hiddenEnd : itemEnd > scrollEnd,
- fullyVisible: itemStart > scrollStart && itemEnd < scrollEnd
- };
- }
- });
- /**
- * @class Ext.util.Offset
- * @ignore
- */
- Ext.define('Ext.util.Offset', {
- /* Begin Definitions */
- statics: {
- fromObject: function(obj) {
- return new this(obj.x, obj.y);
- }
- },
- /* End Definitions */
- constructor: function(x, y) {
- this.x = (x != null && !isNaN(x)) ? x : 0;
- this.y = (y != null && !isNaN(y)) ? y : 0;
- return this;
- },
- copy: function() {
- return new Ext.util.Offset(this.x, this.y);
- },
- copyFrom: function(p) {
- this.x = p.x;
- this.y = p.y;
- },
- toString: function() {
- return "Offset[" + this.x + "," + this.y + "]";
- },
- equals: function(offset) {
- //<debug>
- if(!(offset instanceof this.statics())) {
- Ext.Error.raise('Offset must be an instance of Ext.util.Offset');
- }
- //</debug>
- return (this.x == offset.x && this.y == offset.y);
- },
- round: function(to) {
- if (!isNaN(to)) {
- var factor = Math.pow(10, to);
- this.x = Math.round(this.x * factor) / factor;
- this.y = Math.round(this.y * factor) / factor;
- } else {
- this.x = Math.round(this.x);
- this.y = Math.round(this.y);
- }
- },
- isZero: function() {
- return this.x == 0 && this.y == 0;
- }
- });
- /**
- * @class Ext.util.KeyNav
- * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
- * navigation keys to function calls that will get called when the keys are pressed, providing an easy
- * way to implement custom navigation schemes for any UI component.</p>
- * <p>The following are all of the possible keys that can be implemented: enter, space, left, right, up, down, tab, esc,
- * pageUp, pageDown, del, backspace, home, end. Usage:</p>
- <pre><code>
- var nav = new Ext.util.KeyNav("my-element", {
- "left" : function(e){
- this.moveLeft(e.ctrlKey);
- },
- "right" : function(e){
- this.moveRight(e.ctrlKey);
- },
- "enter" : function(e){
- this.save();
- },
- scope : this
- });
- </code></pre>
- */
- Ext.define('Ext.util.KeyNav', {
-
- alternateClassName: 'Ext.KeyNav',
-
- requires: ['Ext.util.KeyMap'],
-
- statics: {
- keyOptions: {
- left: 37,
- right: 39,
- up: 38,
- down: 40,
- space: 32,
- pageUp: 33,
- pageDown: 34,
- del: 46,
- backspace: 8,
- home: 36,
- end: 35,
- enter: 13,
- esc: 27,
- tab: 9
- }
- },
- /**
- * Creates new KeyNav.
- * @param {String/HTMLElement/Ext.Element} el The element or its ID to bind to
- * @param {Object} config The config
- */
- constructor: function(el, config){
- this.setConfig(el, config || {});
- },
-
- /**
- * Sets up a configuration for the KeyNav.
- * @private
- * @param {String/HTMLElement/Ext.Element} el The element or its ID to bind to
- * @param {Object} config A configuration object as specified in the constructor.
- */
- setConfig: function(el, config) {
- if (this.map) {
- this.map.destroy();
- }
-
- var map = Ext.create('Ext.util.KeyMap', el, null, this.getKeyEvent('forceKeyDown' in config ? config.forceKeyDown : this.forceKeyDown)),
- keys = Ext.util.KeyNav.keyOptions,
- scope = config.scope || this,
- key;
-
- this.map = map;
- for (key in keys) {
- if (keys.hasOwnProperty(key)) {
- if (config[key]) {
- map.addBinding({
- scope: scope,
- key: keys[key],
- handler: Ext.Function.bind(this.handleEvent, scope, [config[key]], true),
- defaultEventAction: config.defaultEventAction || this.defaultEventAction
- });
- }
- }
- }
-
- map.disable();
- if (!config.disabled) {
- map.enable();
- }
- },
-
- /**
- * Method for filtering out the map argument
- * @private
- * @param {Ext.util.KeyMap} map
- * @param {Ext.EventObject} event
- * @param {Object} options Contains the handler to call
- */
- handleEvent: function(map, event, handler){
- return handler.call(this, event);
- },
-
- /**
- * @cfg {Boolean} disabled
- * True to disable this KeyNav instance.
- */
- disabled: false,
-
- /**
- * @cfg {String} defaultEventAction
- * The method to call on the {@link Ext.EventObject} after this KeyNav intercepts a key. Valid values are
- * {@link Ext.EventObject#stopEvent}, {@link Ext.EventObject#preventDefault} and
- * {@link Ext.EventObject#stopPropagation}.
- */
- defaultEventAction: "stopEvent",
-
- /**
- * @cfg {Boolean} forceKeyDown
- * Handle the keydown event instead of keypress. KeyNav automatically does this for IE since
- * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
- * handle keydown instead of keypress.
- */
- forceKeyDown: false,
-
- /**
- * Destroy this KeyNav (this is the same as calling disable).
- * @param {Boolean} removeEl True to remove the element associated with this KeyNav.
- */
- destroy: function(removeEl){
- this.map.destroy(removeEl);
- delete this.map;
- },
- /**
- * Enable this KeyNav
- */
- enable: function() {
- this.map.enable();
- this.disabled = false;
- },
- /**
- * Disable this KeyNav
- */
- disable: function() {
- this.map.disable();
- this.disabled = true;
- },
-
- /**
- * Convenience function for setting disabled/enabled by boolean.
- * @param {Boolean} disabled
- */
- setDisabled : function(disabled){
- this.map.setDisabled(disabled);
- this.disabled = disabled;
- },
-
- /**
- * Determines the event to bind to listen for keys. Depends on the {@link #forceKeyDown} setting,
- * as well as the useKeyDown option on the EventManager.
- * @return {String} The type of event to listen for.
- */
- getKeyEvent: function(forceKeyDown){
- return (forceKeyDown || Ext.EventManager.useKeyDown) ? 'keydown' : 'keypress';
- }
- });
- /**
- * @class Ext.fx.Queue
- * Animation Queue mixin to handle chaining and queueing by target.
- * @private
- */
- Ext.define('Ext.fx.Queue', {
- requires: ['Ext.util.HashMap'],
- constructor: function() {
- this.targets = Ext.create('Ext.util.HashMap');
- this.fxQueue = {};
- },
- // @private
- getFxDefaults: function(targetId) {
- var target = this.targets.get(targetId);
- if (target) {
- return target.fxDefaults;
- }
- return {};
- },
- // @private
- setFxDefaults: function(targetId, obj) {
- var target = this.targets.get(targetId);
- if (target) {
- target.fxDefaults = Ext.apply(target.fxDefaults || {}, obj);
- }
- },
- // @private
- stopAnimation: function(targetId) {
- var me = this,
- queue = me.getFxQueue(targetId),
- ln = queue.length;
- while (ln) {
- queue[ln - 1].end();
- ln--;
- }
- },
- /**
- * @private
- * Returns current animation object if the element has any effects actively running or queued, else returns false.
- */
- getActiveAnimation: function(targetId) {
- var queue = this.getFxQueue(targetId);
- return (queue && !!queue.length) ? queue[0] : false;
- },
- // @private
- hasFxBlock: function(targetId) {
- var queue = this.getFxQueue(targetId);
- return queue && queue[0] && queue[0].block;
- },
- // @private get fx queue for passed target, create if needed.
- getFxQueue: function(targetId) {
- if (!targetId) {
- return false;
- }
- var me = this,
- queue = me.fxQueue[targetId],
- target = me.targets.get(targetId);
- if (!target) {
- return false;
- }
- if (!queue) {
- me.fxQueue[targetId] = [];
- // GarbageCollector will need to clean up Elements since they aren't currently observable
- if (target.type != 'element') {
- target.target.on('destroy', function() {
- me.fxQueue[targetId] = [];
- });
- }
- }
- return me.fxQueue[targetId];
- },
- // @private
- queueFx: function(anim) {
- var me = this,
- target = anim.target,
- queue, ln;
- if (!target) {
- return;
- }
- queue = me.getFxQueue(target.getId());
- ln = queue.length;
- if (ln) {
- if (anim.concurrent) {
- anim.paused = false;
- }
- else {
- queue[ln - 1].on('afteranimate', function() {
- anim.paused = false;
- });
- }
- }
- else {
- anim.paused = false;
- }
- anim.on('afteranimate', function() {
- Ext.Array.remove(queue, anim);
- if (anim.remove) {
- if (target.type == 'element') {
- var el = Ext.get(target.id);
- if (el) {
- el.remove();
- }
- }
- }
- }, this);
- queue.push(anim);
- }
- });
- /**
- * @class Ext.fx.target.Target
- This class specifies a generic target for an animation. It provides a wrapper around a
- series of different types of objects to allow for a generic animation API.
- A target can be a single object or a Composite object containing other objects that are
- to be animated. This class and it's subclasses are generally not created directly, the
- underlying animation will create the appropriate Ext.fx.target.Target object by passing
- the instance to be animated.
- The following types of objects can be animated:
- - {@link Ext.fx.target.Component Components}
- - {@link Ext.fx.target.Element Elements}
- - {@link Ext.fx.target.Sprite Sprites}
- * @markdown
- * @abstract
- */
- Ext.define('Ext.fx.target.Target', {
- isAnimTarget: true,
- /**
- * Creates new Target.
- * @param {Ext.Component/Ext.Element/Ext.draw.Sprite} target The object to be animated
- */
- constructor: function(target) {
- this.target = target;
- this.id = this.getId();
- },
-
- getId: function() {
- return this.target.id;
- }
- });
- /**
- * @class Ext.fx.target.Sprite
- * @extends Ext.fx.target.Target
- This class represents a animation target for a {@link Ext.draw.Sprite}. In general this class will not be
- created directly, the {@link Ext.draw.Sprite} will be passed to the animation and
- and the appropriate target will be created.
- * @markdown
- */
- Ext.define('Ext.fx.target.Sprite', {
- /* Begin Definitions */
- extend: 'Ext.fx.target.Target',
- /* End Definitions */
- type: 'draw',
- getFromPrim: function(sprite, attr) {
- var o;
- if (attr == 'translate') {
- o = {
- x: sprite.attr.translation.x || 0,
- y: sprite.attr.translation.y || 0
- };
- }
- else if (attr == 'rotate') {
- o = {
- degrees: sprite.attr.rotation.degrees || 0,
- x: sprite.attr.rotation.x,
- y: sprite.attr.rotation.y
- };
- }
- else {
- o = sprite.attr[attr];
- }
- return o;
- },
- getAttr: function(attr, val) {
- return [[this.target, val != undefined ? val : this.getFromPrim(this.target, attr)]];
- },
- setAttr: function(targetData) {
- var ln = targetData.length,
- spriteArr = [],
- attrs, attr, attrArr, attPtr, spritePtr, idx, value, i, j, x, y, ln2;
- for (i = 0; i < ln; i++) {
- attrs = targetData[i].attrs;
- for (attr in attrs) {
- attrArr = attrs[attr];
- ln2 = attrArr.length;
- for (j = 0; j < ln2; j++) {
- spritePtr = attrArr[j][0];
- attPtr = attrArr[j][1];
- if (attr === 'translate') {
- value = {
- x: attPtr.x,
- y: attPtr.y
- };
- }
- else if (attr === 'rotate') {
- x = attPtr.x;
- if (isNaN(x)) {
- x = null;
- }
- y = attPtr.y;
- if (isNaN(y)) {
- y = null;
- }
- value = {
- degrees: attPtr.degrees,
- x: x,
- y: y
- };
- }
- else if (attr === 'width' || attr === 'height' || attr === 'x' || attr === 'y') {
- value = parseFloat(attPtr);
- }
- else {
- value = attPtr;
- }
- idx = Ext.Array.indexOf(spriteArr, spritePtr);
- if (idx == -1) {
- spriteArr.push([spritePtr, {}]);
- idx = spriteArr.length - 1;
- }
- spriteArr[idx][1][attr] = value;
- }
- }
- }
- ln = spriteArr.length;
- for (i = 0; i < ln; i++) {
- spritePtr = spriteArr[i];
- spritePtr[0].setAttributes(spritePtr[1]);
- }
- this.target.redraw();
- }
- });
- /**
- * @class Ext.fx.target.CompositeSprite
- * @extends Ext.fx.target.Sprite
- This class represents a animation target for a {@link Ext.draw.CompositeSprite}. It allows
- each {@link Ext.draw.Sprite} in the group to be animated as a whole. In general this class will not be
- created directly, the {@link Ext.draw.CompositeSprite} will be passed to the animation and
- and the appropriate target will be created.
- * @markdown
- */
- Ext.define('Ext.fx.target.CompositeSprite', {
- /* Begin Definitions */
- extend: 'Ext.fx.target.Sprite',
- /* End Definitions */
- getAttr: function(attr, val) {
- var out = [],
- target = this.target;
- target.each(function(sprite) {
- out.push([sprite, val != undefined ? val : this.getFromPrim(sprite, attr)]);
- }, this);
- return out;
- }
- });
- /**
- * @class Ext.fx.target.Component
- * @extends Ext.fx.target.Target
- *
- * This class represents a animation target for a {@link Ext.Component}. In general this class will not be
- * created directly, the {@link Ext.Component} will be passed to the animation and
- * and the appropriate target will be created.
- */
- Ext.define('Ext.fx.target.Component', {
- /* Begin Definitions */
-
- extend: 'Ext.fx.target.Target',
-
- /* End Definitions */
- type: 'component',
- // Methods to call to retrieve unspecified "from" values from a target Component
- getPropMethod: {
- top: function() {
- return this.getPosition(true)[1];
- },
- left: function() {
- return this.getPosition(true)[0];
- },
- x: function() {
- return this.getPosition()[0];
- },
- y: function() {
- return this.getPosition()[1];
- },
- height: function() {
- return this.getHeight();
- },
- width: function() {
- return this.getWidth();
- },
- opacity: function() {
- return this.el.getStyle('opacity');
- }
- },
- compMethod: {
- top: 'setPosition',
- left: 'setPosition',
- x: 'setPagePosition',
- y: 'setPagePosition',
- height: 'setSize',
- width: 'setSize',
- opacity: 'setOpacity'
- },
- // Read the named attribute from the target Component. Use the defined getter for the attribute
- getAttr: function(attr, val) {
- return [[this.target, val !== undefined ? val : this.getPropMethod[attr].call(this.target)]];
- },
- setAttr: function(targetData, isFirstFrame, isLastFrame) {
- var me = this,
- target = me.target,
- ln = targetData.length,
- attrs, attr, o, i, j, meth, targets, left, top, w, h;
- for (i = 0; i < ln; i++) {
- attrs = targetData[i].attrs;
- for (attr in attrs) {
- targets = attrs[attr].length;
- meth = {
- setPosition: {},
- setPagePosition: {},
- setSize: {},
- setOpacity: {}
- };
- for (j = 0; j < targets; j++) {
- o = attrs[attr][j];
- // We REALLY want a single function call, so push these down to merge them: eg
- // meth.setPagePosition.target = <targetComponent>
- // meth.setPagePosition['x'] = 100
- // meth.setPagePosition['y'] = 100
- meth[me.compMethod[attr]].target = o[0];
- meth[me.compMethod[attr]][attr] = o[1];
- }
- if (meth.setPosition.target) {
- o = meth.setPosition;
- left = (o.left === undefined) ? undefined : parseInt(o.left, 10);
- top = (o.top === undefined) ? undefined : parseInt(o.top, 10);
- o.target.setPosition(left, top);
- }
- if (meth.setPagePosition.target) {
- o = meth.setPagePosition;
- o.target.setPagePosition(o.x, o.y);
- }
- if (meth.setSize.target && meth.setSize.target.el) {
- o = meth.setSize;
- // Dimensions not being animated MUST NOT be autosized. They must remain at current value.
- w = (o.width === undefined) ? o.target.getWidth() : parseInt(o.width, 10);
- h = (o.height === undefined) ? o.target.getHeight() : parseInt(o.height, 10);
- // Only set the size of the Component on the last frame, or if the animation was
- // configured with dynamic: true.
- // In other cases, we just set the target element size.
- // This will result in either clipping if animating a reduction in size, or the revealing of
- // the inner elements of the Component if animating an increase in size.
- // Component's animate function initially resizes to the larger size before resizing the
- // outer element to clip the contents.
- if (isLastFrame || me.dynamic) {
- o.target.componentLayout.childrenChanged = true;
- // Flag if we are being called by an animating layout: use setCalculatedSize
- if (me.layoutAnimation) {
- o.target.setCalculatedSize(w, h);
- } else {
- o.target.setSize(w, h);
- }
- }
- else {
- o.target.el.setSize(w, h);
- }
- }
- if (meth.setOpacity.target) {
- o = meth.setOpacity;
- o.target.el.setStyle('opacity', o.opacity);
- }
- }
- }
- }
- });
- /**
- * @class Ext.fx.CubicBezier
- * @ignore
- */
- Ext.define('Ext.fx.CubicBezier', {
- /* Begin Definitions */
- singleton: true,
- /* End Definitions */
- cubicBezierAtTime: function(t, p1x, p1y, p2x, p2y, duration) {
- var cx = 3 * p1x,
- bx = 3 * (p2x - p1x) - cx,
- ax = 1 - cx - bx,
- cy = 3 * p1y,
- by = 3 * (p2y - p1y) - cy,
- ay = 1 - cy - by;
- function sampleCurveX(t) {
- return ((ax * t + bx) * t + cx) * t;
- }
- function solve(x, epsilon) {
- var t = solveCurveX(x, epsilon);
- return ((ay * t + by) * t + cy) * t;
- }
- function solveCurveX(x, epsilon) {
- var t0, t1, t2, x2, d2, i;
- for (t2 = x, i = 0; i < 8; i++) {
- x2 = sampleCurveX(t2) - x;
- if (Math.abs(x2) < epsilon) {
- return t2;
- }
- d2 = (3 * ax * t2 + 2 * bx) * t2 + cx;
- if (Math.abs(d2) < 1e-6) {
- break;
- }
- t2 = t2 - x2 / d2;
- }
- t0 = 0;
- t1 = 1;
- t2 = x;
- if (t2 < t0) {
- return t0;
- }
- if (t2 > t1) {
- return t1;
- }
- while (t0 < t1) {
- x2 = sampleCurveX(t2);
- if (Math.abs(x2 - x) < epsilon) {
- return t2;
- }
- if (x > x2) {
- t0 = t2;
- } else {
- t1 = t2;
- }
- t2 = (t1 - t0) / 2 + t0;
- }
- return t2;
- }
- return solve(t, 1 / (200 * duration));
- },
- cubicBezier: function(x1, y1, x2, y2) {
- var fn = function(pos) {
- return Ext.fx.CubicBezier.cubicBezierAtTime(pos, x1, y1, x2, y2, 1);
- };
- fn.toCSS3 = function() {
- return 'cubic-bezier(' + [x1, y1, x2, y2].join(',') + ')';
- };
- fn.reverse = function() {
- return Ext.fx.CubicBezier.cubicBezier(1 - x2, 1 - y2, 1 - x1, 1 - y1);
- };
- return fn;
- }
- });
- /**
- * Represents an RGB color and provides helper functions get
- * color components in HSL color space.
- */
- Ext.define('Ext.draw.Color', {
- /* Begin Definitions */
- /* End Definitions */
- colorToHexRe: /(.*?)rgb\((\d+),\s*(\d+),\s*(\d+)\)/,
- rgbRe: /\s*rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)\s*/,
- hexRe: /\s*#([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)([0-9a-fA-F][0-9a-fA-F]?)\s*/,
- /**
- * @cfg {Number} lightnessFactor
- *
- * The default factor to compute the lighter or darker color. Defaults to 0.2.
- */
- lightnessFactor: 0.2,
- /**
- * Creates new Color.
- * @param {Number} red Red component (0..255)
- * @param {Number} green Green component (0..255)
- * @param {Number} blue Blue component (0..255)
- */
- constructor : function(red, green, blue) {
- var me = this,
- clamp = Ext.Number.constrain;
- me.r = clamp(red, 0, 255);
- me.g = clamp(green, 0, 255);
- me.b = clamp(blue, 0, 255);
- },
- /**
- * Get the red component of the color, in the range 0..255.
- * @return {Number}
- */
- getRed: function() {
- return this.r;
- },
- /**
- * Get the green component of the color, in the range 0..255.
- * @return {Number}
- */
- getGreen: function() {
- return this.g;
- },
- /**
- * Get the blue component of the color, in the range 0..255.
- * @return {Number}
- */
- getBlue: function() {
- return this.b;
- },
- /**
- * Get the RGB values.
- * @return {Number[]}
- */
- getRGB: function() {
- var me = this;
- return [me.r, me.g, me.b];
- },
- /**
- * Get the equivalent HSL components of the color.
- * @return {Number[]}
- */
- getHSL: function() {
- var me = this,
- r = me.r / 255,
- g = me.g / 255,
- b = me.b / 255,
- max = Math.max(r, g, b),
- min = Math.min(r, g, b),
- delta = max - min,
- h,
- s = 0,
- l = 0.5 * (max + min);
- // min==max means achromatic (hue is undefined)
- if (min != max) {
- s = (l < 0.5) ? delta / (max + min) : delta / (2 - max - min);
- if (r == max) {
- h = 60 * (g - b) / delta;
- } else if (g == max) {
- h = 120 + 60 * (b - r) / delta;
- } else {
- h = 240 + 60 * (r - g) / delta;
- }
- if (h < 0) {
- h += 360;
- }
- if (h >= 360) {
- h -= 360;
- }
- }
- return [h, s, l];
- },
- /**
- * Return a new color that is lighter than this color.
- * @param {Number} factor Lighter factor (0..1), default to 0.2
- * @return Ext.draw.Color
- */
- getLighter: function(factor) {
- var hsl = this.getHSL();
- factor = factor || this.lightnessFactor;
- hsl[2] = Ext.Number.constrain(hsl[2] + factor, 0, 1);
- return this.fromHSL(hsl[0], hsl[1], hsl[2]);
- },
- /**
- * Return a new color that is darker than this color.
- * @param {Number} factor Darker factor (0..1), default to 0.2
- * @return Ext.draw.Color
- */
- getDarker: function(factor) {
- factor = factor || this.lightnessFactor;
- return this.getLighter(-factor);
- },
- /**
- * Return the color in the hex format, i.e. '#rrggbb'.
- * @return {String}
- */
- toString: function() {
- var me = this,
- round = Math.round,
- r = round(me.r).toString(16),
- g = round(me.g).toString(16),
- b = round(me.b).toString(16);
- r = (r.length == 1) ? '0' + r : r;
- g = (g.length == 1) ? '0' + g : g;
- b = (b.length == 1) ? '0' + b : b;
- return ['#', r, g, b].join('');
- },
- /**
- * Convert a color to hexadecimal format.
- *
- * **Note:** This method is both static and instance.
- *
- * @param {String/String[]} color The color value (i.e 'rgb(255, 255, 255)', 'color: #ffffff').
- * Can also be an Array, in this case the function handles the first member.
- * @returns {String} The color in hexadecimal format.
- * @static
- */
- toHex: function(color) {
- if (Ext.isArray(color)) {
- color = color[0];
- }
- if (!Ext.isString(color)) {
- return '';
- }
- if (color.substr(0, 1) === '#') {
- return color;
- }
- var digits = this.colorToHexRe.exec(color);
- if (Ext.isArray(digits)) {
- var red = parseInt(digits[2], 10),
- green = parseInt(digits[3], 10),
- blue = parseInt(digits[4], 10),
- rgb = blue | (green << 8) | (red << 16);
- return digits[1] + '#' + ("000000" + rgb.toString(16)).slice(-6);
- }
- else {
- return '';
- }
- },
- /**
- * Parse the string and create a new color.
- *
- * Supported formats: '#rrggbb', '#rgb', and 'rgb(r,g,b)'.
- *
- * If the string is not recognized, an undefined will be returned instead.
- *
- * **Note:** This method is both static and instance.
- *
- * @param {String} str Color in string.
- * @returns Ext.draw.Color
- * @static
- */
- fromString: function(str) {
- var values, r, g, b,
- parse = parseInt;
- if ((str.length == 4 || str.length == 7) && str.substr(0, 1) === '#') {
- values = str.match(this.hexRe);
- if (values) {
- r = parse(values[1], 16) >> 0;
- g = parse(values[2], 16) >> 0;
- b = parse(values[3], 16) >> 0;
- if (str.length == 4) {
- r += (r * 16);
- g += (g * 16);
- b += (b * 16);
- }
- }
- }
- else {
- values = str.match(this.rgbRe);
- if (values) {
- r = values[1];
- g = values[2];
- b = values[3];
- }
- }
- return (typeof r == 'undefined') ? undefined : Ext.create('Ext.draw.Color', r, g, b);
- },
- /**
- * Returns the gray value (0 to 255) of the color.
- *
- * The gray value is calculated using the formula r*0.3 + g*0.59 + b*0.11.
- *
- * @returns {Number}
- */
- getGrayscale: function() {
- // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
- return this.r * 0.3 + this.g * 0.59 + this.b * 0.11;
- },
- /**
- * Create a new color based on the specified HSL values.
- *
- * **Note:** This method is both static and instance.
- *
- * @param {Number} h Hue component (0..359)
- * @param {Number} s Saturation component (0..1)
- * @param {Number} l Lightness component (0..1)
- * @returns Ext.draw.Color
- * @static
- */
- fromHSL: function(h, s, l) {
- var C, X, m, i, rgb = [],
- abs = Math.abs,
- floor = Math.floor;
- if (s == 0 || h == null) {
- // achromatic
- rgb = [l, l, l];
- }
- else {
- // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSL
- // C is the chroma
- // X is the second largest component
- // m is the lightness adjustment
- h /= 60;
- C = s * (1 - abs(2 * l - 1));
- X = C * (1 - abs(h - 2 * floor(h / 2) - 1));
- m = l - C / 2;
- switch (floor(h)) {
- case 0:
- rgb = [C, X, 0];
- break;
- case 1:
- rgb = [X, C, 0];
- break;
- case 2:
- rgb = [0, C, X];
- break;
- case 3:
- rgb = [0, X, C];
- break;
- case 4:
- rgb = [X, 0, C];
- break;
- case 5:
- rgb = [C, 0, X];
- break;
- }
- rgb = [rgb[0] + m, rgb[1] + m, rgb[2] + m];
- }
- return Ext.create('Ext.draw.Color', rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);
- }
- }, function() {
- var prototype = this.prototype;
- //These functions are both static and instance. TODO: find a more elegant way of copying them
- this.addStatics({
- fromHSL: function() {
- return prototype.fromHSL.apply(prototype, arguments);
- },
- fromString: function() {
- return prototype.fromString.apply(prototype, arguments);
- },
- toHex: function() {
- return prototype.toHex.apply(prototype, arguments);
- }
- });
- });
- /**
- * @class Ext.dd.StatusProxy
- * A specialized drag proxy that supports a drop status icon, {@link Ext.Layer} styles and auto-repair. This is the
- * default drag proxy used by all Ext.dd components.
- */
- Ext.define('Ext.dd.StatusProxy', {
- animRepair: false,
- /**
- * Creates new StatusProxy.
- * @param {Object} config (optional) Config object.
- */
- constructor: function(config){
- Ext.apply(this, config);
- this.id = this.id || Ext.id();
- this.proxy = Ext.createWidget('component', {
- floating: true,
- stateful: false,
- id: this.id,
- html: '<div class="' + Ext.baseCSSPrefix + 'dd-drop-icon"></div>' +
- '<div class="' + Ext.baseCSSPrefix + 'dd-drag-ghost"></div>',
- cls: Ext.baseCSSPrefix + 'dd-drag-proxy ' + this.dropNotAllowed,
- shadow: !config || config.shadow !== false,
- renderTo: document.body
- });
- this.el = this.proxy.el;
- this.el.show();
- this.el.setVisibilityMode(Ext.Element.VISIBILITY);
- this.el.hide();
- this.ghost = Ext.get(this.el.dom.childNodes[1]);
- this.dropStatus = this.dropNotAllowed;
- },
- /**
- * @cfg {String} [dropAllowed="x-dd-drop-ok"]
- * The CSS class to apply to the status element when drop is allowed.
- */
- dropAllowed : Ext.baseCSSPrefix + 'dd-drop-ok',
- /**
- * @cfg {String} [dropNotAllowed="x-dd-drop-nodrop"]
- * The CSS class to apply to the status element when drop is not allowed.
- */
- dropNotAllowed : Ext.baseCSSPrefix + 'dd-drop-nodrop',
- /**
- * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
- * over the current target element.
- * @param {String} cssClass The css class for the new drop status indicator image
- */
- setStatus : function(cssClass){
- cssClass = cssClass || this.dropNotAllowed;
- if(this.dropStatus != cssClass){
- this.el.replaceCls(this.dropStatus, cssClass);
- this.dropStatus = cssClass;
- }
- },
- /**
- * Resets the status indicator to the default dropNotAllowed value
- * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
- */
- reset : function(clearGhost){
- this.el.dom.className = Ext.baseCSSPrefix + 'dd-drag-proxy ' + this.dropNotAllowed;
- this.dropStatus = this.dropNotAllowed;
- if(clearGhost){
- this.ghost.update("");
- }
- },
- /**
- * Updates the contents of the ghost element
- * @param {String/HTMLElement} html The html that will replace the current innerHTML of the ghost element, or a
- * DOM node to append as the child of the ghost element (in which case the innerHTML will be cleared first).
- */
- update : function(html){
- if(typeof html == "string"){
- this.ghost.update(html);
- }else{
- this.ghost.update("");
- html.style.margin = "0";
- this.ghost.dom.appendChild(html);
- }
- var el = this.ghost.dom.firstChild;
- if(el){
- Ext.fly(el).setStyle('float', 'none');
- }
- },
- /**
- * Returns the underlying proxy {@link Ext.Layer}
- * @return {Ext.Layer} el
- */
- getEl : function(){
- return this.el;
- },
- /**
- * Returns the ghost element
- * @return {Ext.Element} el
- */
- getGhost : function(){
- return this.ghost;
- },
- /**
- * Hides the proxy
- * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
- */
- hide : function(clear) {
- this.proxy.hide();
- if (clear) {
- this.reset(true);
- }
- },
- /**
- * Stops the repair animation if it's currently running
- */
- stop : function(){
- if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
- this.anim.stop();
- }
- },
- /**
- * Displays this proxy
- */
- show : function() {
- this.proxy.show();
- this.proxy.toFront();
- },
- /**
- * Force the Layer to sync its shadow and shim positions to the element
- */
- sync : function(){
- this.proxy.el.sync();
- },
- /**
- * Causes the proxy to return to its position of origin via an animation. Should be called after an
- * invalid drop operation by the item being dragged.
- * @param {Number[]} xy The XY position of the element ([x, y])
- * @param {Function} callback The function to call after the repair is complete.
- * @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.
- */
- repair : function(xy, callback, scope){
- this.callback = callback;
- this.scope = scope;
- if (xy && this.animRepair !== false) {
- this.el.addCls(Ext.baseCSSPrefix + 'dd-drag-repair');
- this.el.hideUnders(true);
- this.anim = this.el.animate({
- duration: this.repairDuration || 500,
- easing: 'ease-out',
- to: {
- x: xy[0],
- y: xy[1]
- },
- stopAnimation: true,
- callback: this.afterRepair,
- scope: this
- });
- } else {
- this.afterRepair();
- }
- },
- // private
- afterRepair : function(){
- this.hide(true);
- if(typeof this.callback == "function"){
- this.callback.call(this.scope || this);
- }
- this.callback = null;
- this.scope = null;
- },
- destroy: function(){
- Ext.destroy(this.ghost, this.proxy, this.el);
- }
- });
- /**
- * A custom drag proxy implementation specific to {@link Ext.panel.Panel}s. This class
- * is primarily used internally for the Panel's drag drop implementation, and
- * should never need to be created directly.
- * @private
- */
- Ext.define('Ext.panel.Proxy', {
- alternateClassName: 'Ext.dd.PanelProxy',
- /**
- * Creates new panel proxy.
- * @param {Ext.panel.Panel} panel The {@link Ext.panel.Panel} to proxy for
- * @param {Object} [config] Config object
- */
- constructor: function(panel, config){
- /**
- * @property panel
- * @type Ext.panel.Panel
- */
- this.panel = panel;
- this.id = this.panel.id +'-ddproxy';
- Ext.apply(this, config);
- },
- /**
- * @cfg {Boolean} insertProxy
- * True to insert a placeholder proxy element while dragging the panel, false to drag with no proxy.
- * Most Panels are not absolute positioned and therefore we need to reserve this space.
- */
- insertProxy: true,
- // private overrides
- setStatus: Ext.emptyFn,
- reset: Ext.emptyFn,
- update: Ext.emptyFn,
- stop: Ext.emptyFn,
- sync: Ext.emptyFn,
- /**
- * Gets the proxy's element
- * @return {Ext.Element} The proxy's element
- */
- getEl: function(){
- return this.ghost.el;
- },
- /**
- * Gets the proxy's ghost Panel
- * @return {Ext.panel.Panel} The proxy's ghost Panel
- */
- getGhost: function(){
- return this.ghost;
- },
- /**
- * Gets the proxy element. This is the element that represents where the
- * Panel was before we started the drag operation.
- * @return {Ext.Element} The proxy's element
- */
- getProxy: function(){
- return this.proxy;
- },
- /**
- * Hides the proxy
- */
- hide : function(){
- if (this.ghost) {
- if (this.proxy) {
- this.proxy.remove();
- delete this.proxy;
- }
- // Unghost the Panel, do not move the Panel to where the ghost was
- this.panel.unghost(null, false);
- delete this.ghost;
- }
- },
- /**
- * Shows the proxy
- */
- show: function(){
- if (!this.ghost) {
- var panelSize = this.panel.getSize();
- this.panel.el.setVisibilityMode(Ext.Element.DISPLAY);
- this.ghost = this.panel.ghost();
- if (this.insertProxy) {
- // bc Panels aren't absolute positioned we need to take up the space
- // of where the panel previously was
- this.proxy = this.panel.el.insertSibling({cls: Ext.baseCSSPrefix + 'panel-dd-spacer'});
- this.proxy.setSize(panelSize);
- }
- }
- },
- // private
- repair: function(xy, callback, scope) {
- this.hide();
- if (typeof callback == "function") {
- callback.call(scope || this);
- }
- },
- /**
- * Moves the proxy to a different position in the DOM. This is typically
- * called while dragging the Panel to keep the proxy sync'd to the Panel's
- * location.
- * @param {HTMLElement} parentNode The proxy's parent DOM node
- * @param {HTMLElement} [before] The sibling node before which the
- * proxy should be inserted (defaults to the parent's last child if not
- * specified)
- */
- moveProxy : function(parentNode, before){
- if (this.proxy) {
- parentNode.insertBefore(this.proxy.dom, before);
- }
- }
- });
- /**
- * @class Ext.layout.component.AbstractDock
- * @extends Ext.layout.component.Component
- * @private
- * This ComponentLayout handles docking for Panels. It takes care of panels that are
- * part of a ContainerLayout that sets this Panel's size and Panels that are part of
- * an AutoContainerLayout in which this panel get his height based of the CSS or
- * or its content.
- */
- Ext.define('Ext.layout.component.AbstractDock', {
- /* Begin Definitions */
- extend: 'Ext.layout.component.Component',
- /* End Definitions */
- type: 'dock',
- /**
- * @private
- * @property autoSizing
- * @type Boolean
- * This flag is set to indicate this layout may have an autoHeigh