init repo
This commit is contained in:
188
OfficeWeb/3rdparty/touch/src/AbstractComponent.js
vendored
Normal file
188
OfficeWeb/3rdparty/touch/src/AbstractComponent.js
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @private
|
||||
* This is the abstract class for {@link Ext.Component}.
|
||||
*
|
||||
* This should never be overridden.
|
||||
*/
|
||||
Ext.define('Ext.AbstractComponent', {
|
||||
extend: 'Ext.Evented',
|
||||
|
||||
onClassExtended: function(Class, members) {
|
||||
if (!members.hasOwnProperty('cachedConfig')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var prototype = Class.prototype,
|
||||
config = members.config,
|
||||
cachedConfig = members.cachedConfig,
|
||||
cachedConfigList = prototype.cachedConfigList,
|
||||
hasCachedConfig = prototype.hasCachedConfig,
|
||||
name, value;
|
||||
|
||||
delete members.cachedConfig;
|
||||
|
||||
prototype.cachedConfigList = cachedConfigList = (cachedConfigList) ? cachedConfigList.slice() : [];
|
||||
prototype.hasCachedConfig = hasCachedConfig = (hasCachedConfig) ? Ext.Object.chain(hasCachedConfig) : {};
|
||||
|
||||
if (!config) {
|
||||
members.config = config = {};
|
||||
}
|
||||
|
||||
for (name in cachedConfig) {
|
||||
if (cachedConfig.hasOwnProperty(name)) {
|
||||
value = cachedConfig[name];
|
||||
|
||||
if (!hasCachedConfig[name]) {
|
||||
hasCachedConfig[name] = true;
|
||||
cachedConfigList.push(name);
|
||||
}
|
||||
|
||||
config[name] = value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getElementConfig: Ext.emptyFn,
|
||||
|
||||
referenceAttributeName: 'reference',
|
||||
|
||||
referenceSelector: '[reference]',
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Significantly improve instantiation time for Component with multiple references
|
||||
* Ext.Element instance of the reference domNode is only created the very first time
|
||||
* it's ever used.
|
||||
*/
|
||||
addReferenceNode: function(name, domNode) {
|
||||
Ext.Object.defineProperty(this, name, {
|
||||
get: function() {
|
||||
var reference;
|
||||
|
||||
delete this[name];
|
||||
this[name] = reference = new Ext.Element(domNode);
|
||||
return reference;
|
||||
},
|
||||
configurable: true
|
||||
});
|
||||
},
|
||||
|
||||
initElement: function() {
|
||||
var prototype = this.self.prototype,
|
||||
id = this.getId(),
|
||||
referenceList = [],
|
||||
cleanAttributes = true,
|
||||
referenceAttributeName = this.referenceAttributeName,
|
||||
needsOptimization = false,
|
||||
renderTemplate, renderElement, element,
|
||||
referenceNodes, i, ln, referenceNode, reference,
|
||||
configNameCache, defaultConfig, cachedConfigList, initConfigList, initConfigMap, configList,
|
||||
elements, name, nameMap, internalName;
|
||||
|
||||
if (prototype.hasOwnProperty('renderTemplate')) {
|
||||
renderTemplate = this.renderTemplate.cloneNode(true);
|
||||
renderElement = renderTemplate.firstChild;
|
||||
}
|
||||
else {
|
||||
cleanAttributes = false;
|
||||
needsOptimization = true;
|
||||
renderTemplate = document.createDocumentFragment();
|
||||
renderElement = Ext.Element.create(this.getElementConfig(), true);
|
||||
renderTemplate.appendChild(renderElement);
|
||||
}
|
||||
|
||||
referenceNodes = renderTemplate.querySelectorAll(this.referenceSelector);
|
||||
|
||||
for (i = 0,ln = referenceNodes.length; i < ln; i++) {
|
||||
referenceNode = referenceNodes[i];
|
||||
reference = referenceNode.getAttribute(referenceAttributeName);
|
||||
|
||||
if (cleanAttributes) {
|
||||
referenceNode.removeAttribute(referenceAttributeName);
|
||||
}
|
||||
|
||||
if (reference == 'element') {
|
||||
referenceNode.id = id;
|
||||
this.element = element = new Ext.Element(referenceNode);
|
||||
}
|
||||
else {
|
||||
this.addReferenceNode(reference, referenceNode);
|
||||
}
|
||||
|
||||
referenceList.push(reference);
|
||||
}
|
||||
|
||||
this.referenceList = referenceList;
|
||||
|
||||
if (!this.innerElement) {
|
||||
this.innerElement = element;
|
||||
}
|
||||
|
||||
if (!this.bodyElement) {
|
||||
this.bodyElement = this.innerElement;
|
||||
}
|
||||
|
||||
if (renderElement === element.dom) {
|
||||
this.renderElement = element;
|
||||
}
|
||||
else {
|
||||
this.addReferenceNode('renderElement', renderElement);
|
||||
}
|
||||
|
||||
// This happens only *once* per class, during the very first instantiation
|
||||
// to optimize renderTemplate based on cachedConfig
|
||||
if (needsOptimization) {
|
||||
configNameCache = Ext.Class.configNameCache;
|
||||
defaultConfig = this.config;
|
||||
cachedConfigList = this.cachedConfigList;
|
||||
initConfigList = this.initConfigList;
|
||||
initConfigMap = this.initConfigMap;
|
||||
configList = [];
|
||||
|
||||
for (i = 0,ln = cachedConfigList.length; i < ln; i++) {
|
||||
name = cachedConfigList[i];
|
||||
nameMap = configNameCache[name];
|
||||
|
||||
if (initConfigMap[name]) {
|
||||
initConfigMap[name] = false;
|
||||
Ext.Array.remove(initConfigList, name);
|
||||
}
|
||||
|
||||
if (defaultConfig[name] !== null) {
|
||||
configList.push(name);
|
||||
this[nameMap.get] = this[nameMap.initGet];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0,ln = configList.length; i < ln; i++) {
|
||||
name = configList[i];
|
||||
nameMap = configNameCache[name];
|
||||
internalName = nameMap.internal;
|
||||
|
||||
this[internalName] = null;
|
||||
this[nameMap.set].call(this, defaultConfig[name]);
|
||||
delete this[nameMap.get];
|
||||
|
||||
prototype[internalName] = this[internalName];
|
||||
}
|
||||
|
||||
renderElement = this.renderElement.dom;
|
||||
prototype.renderTemplate = renderTemplate = document.createDocumentFragment();
|
||||
renderTemplate.appendChild(renderElement.cloneNode(true));
|
||||
|
||||
elements = renderTemplate.querySelectorAll('[id]');
|
||||
|
||||
for (i = 0,ln = elements.length; i < ln; i++) {
|
||||
element = elements[i];
|
||||
element.removeAttribute('id');
|
||||
}
|
||||
|
||||
for (i = 0,ln = referenceList.length; i < ln; i++) {
|
||||
reference = referenceList[i];
|
||||
this[reference].dom.removeAttribute('reference');
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
136
OfficeWeb/3rdparty/touch/src/AbstractManager.js
vendored
Normal file
136
OfficeWeb/3rdparty/touch/src/AbstractManager.js
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
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) {
|
||||
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=this] The scope to execute in.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
});
|
||||
78
OfficeWeb/3rdparty/touch/src/ActionSheet.js
vendored
Normal file
78
OfficeWeb/3rdparty/touch/src/ActionSheet.js
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* {@link Ext.ActionSheet ActionSheets} are used to display a list of {@link Ext.Button buttons} in a popup dialog.
|
||||
*
|
||||
* The key difference between ActionSheet and {@link Ext.Sheet} is that ActionSheets are docked at the bottom of the
|
||||
* screen, and the {@link #defaultType} is set to {@link Ext.Button button}.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* @example preview miniphone
|
||||
* var actionSheet = Ext.create('Ext.ActionSheet', {
|
||||
* items: [
|
||||
* {
|
||||
* text: 'Delete draft',
|
||||
* ui : 'decline'
|
||||
* },
|
||||
* {
|
||||
* text: 'Save draft'
|
||||
* },
|
||||
* {
|
||||
* text: 'Cancel',
|
||||
* ui : 'confirm'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* Ext.Viewport.add(actionSheet);
|
||||
* actionSheet.show();
|
||||
*
|
||||
* As you can see from the code above, you no longer have to specify a `xtype` when creating buttons within a {@link Ext.ActionSheet ActionSheet},
|
||||
* because the {@link #defaultType} is set to {@link Ext.Button button}.
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.ActionSheet', {
|
||||
extend: 'Ext.Sheet',
|
||||
alias : 'widget.actionsheet',
|
||||
requires: ['Ext.Button'],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: Ext.baseCSSPrefix + 'sheet-action',
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
left: 0,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
right: 0,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
bottom: 0,
|
||||
|
||||
// @hide
|
||||
centered: false,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
height: 'auto',
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
defaultType: 'button'
|
||||
}
|
||||
});
|
||||
46
OfficeWeb/3rdparty/touch/src/Ajax.js
vendored
Normal file
46
OfficeWeb/3rdparty/touch/src/Ajax.js
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @aside guide ajax
|
||||
*
|
||||
* 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.setTimeout(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.setTimeout(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,
|
||||
|
||||
/**
|
||||
* @property {Boolean} autoAbort
|
||||
* Whether a new request should abort any pending requests.
|
||||
*/
|
||||
autoAbort : false
|
||||
});
|
||||
631
OfficeWeb/3rdparty/touch/src/Anim.js
vendored
Normal file
631
OfficeWeb/3rdparty/touch/src/Anim.js
vendored
Normal file
@@ -0,0 +1,631 @@
|
||||
/**
|
||||
* Ext.Anim is used to execute simple animations defined in {@link Ext.anims}. The {@link #run} method can take any of the
|
||||
* properties defined below.
|
||||
*
|
||||
* Ext.Anim.run(this, 'fade', {
|
||||
* out: false,
|
||||
* autoClear: true
|
||||
* });
|
||||
*
|
||||
* When using {@link Ext.Anim#run}, ensure you require {@link Ext.Anim} in your application. Either do this using {@link Ext#require}:
|
||||
*
|
||||
* Ext.requires('Ext.Anim');
|
||||
*
|
||||
* when using {@link Ext#setup}:
|
||||
*
|
||||
* Ext.setup({
|
||||
* requires: ['Ext.Anim'],
|
||||
* onReady: function() {
|
||||
* //do something
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* or when using {@link Ext#application}:
|
||||
*
|
||||
* Ext.application({
|
||||
* requires: ['Ext.Anim'],
|
||||
* launch: function() {
|
||||
* //do something
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* @singleton
|
||||
*/
|
||||
|
||||
Ext.define('Ext.Anim', {
|
||||
isAnim: true,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} disableAnimations
|
||||
* `true` to disable animations.
|
||||
*/
|
||||
disableAnimations: false,
|
||||
|
||||
defaultConfig: {
|
||||
/**
|
||||
* @cfg {Object} from
|
||||
* An object of CSS values which the animation begins with. If you define a CSS property here, you must also
|
||||
* define it in the {@link #to} config.
|
||||
*/
|
||||
from: {},
|
||||
|
||||
/**
|
||||
* @cfg {Object} to
|
||||
* An object of CSS values which the animation ends with. If you define a CSS property here, you must also
|
||||
* define it in the {@link #from} config.
|
||||
*/
|
||||
to: {},
|
||||
|
||||
/**
|
||||
* @cfg {Number} duration
|
||||
* Time in milliseconds for the animation to last.
|
||||
*/
|
||||
duration: 250,
|
||||
|
||||
/**
|
||||
* @cfg {Number} delay Time to delay before starting the animation.
|
||||
*/
|
||||
delay: 0,
|
||||
|
||||
/**
|
||||
* @cfg {String} easing
|
||||
* Valid values are 'ease', 'linear', ease-in', 'ease-out', 'ease-in-out', or a cubic-bezier curve as defined by CSS.
|
||||
*/
|
||||
easing: 'ease-in-out',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} autoClear
|
||||
* `true` to remove all custom CSS defined in the {@link #to} config when the animation is over.
|
||||
*/
|
||||
autoClear: true,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} out
|
||||
* `true` if you want the animation to slide out of the screen.
|
||||
*/
|
||||
out: true,
|
||||
|
||||
/**
|
||||
* @cfg {String} direction
|
||||
* Valid values are: 'left', 'right', 'up', 'down', and `null`.
|
||||
*/
|
||||
direction: null,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} reverse
|
||||
* `true` to reverse the animation direction. For example, if the animation direction was set to 'left', it would
|
||||
* then use 'right'.
|
||||
*/
|
||||
reverse: false
|
||||
},
|
||||
|
||||
/**
|
||||
* @cfg {Function} before
|
||||
* Code to execute before starting the animation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {Function} after
|
||||
* Code to execute after the animation ends.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {Object} scope
|
||||
* Scope to run the {@link #before} function in.
|
||||
*/
|
||||
|
||||
opposites: {
|
||||
'left': 'right',
|
||||
'right': 'left',
|
||||
'up': 'down',
|
||||
'down': 'up'
|
||||
},
|
||||
|
||||
constructor: function(config) {
|
||||
config = Ext.apply({}, config || {}, this.defaultConfig);
|
||||
this.config = config;
|
||||
|
||||
this.callSuper([config]);
|
||||
|
||||
this.running = [];
|
||||
},
|
||||
|
||||
initConfig: function(el, runConfig) {
|
||||
var me = this,
|
||||
config = Ext.apply({}, runConfig || {}, me.config);
|
||||
|
||||
config.el = el = Ext.get(el);
|
||||
|
||||
if (config.reverse && me.opposites[config.direction]) {
|
||||
config.direction = me.opposites[config.direction];
|
||||
}
|
||||
|
||||
if (me.config.before) {
|
||||
me.config.before.call(config, el, config);
|
||||
}
|
||||
|
||||
if (runConfig.before) {
|
||||
runConfig.before.call(config.scope || config, el, config);
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
run: function(el, config) {
|
||||
el = Ext.get(el);
|
||||
config = config || {};
|
||||
|
||||
|
||||
var me = this,
|
||||
style = el.dom.style,
|
||||
property,
|
||||
after = config.after;
|
||||
|
||||
if (me.running[el.id]) {
|
||||
me.onTransitionEnd(null, el, {
|
||||
config: config,
|
||||
after: after
|
||||
});
|
||||
}
|
||||
|
||||
config = this.initConfig(el, config);
|
||||
|
||||
if (this.disableAnimations) {
|
||||
for (property in config.to) {
|
||||
if (!config.to.hasOwnProperty(property)) {
|
||||
continue;
|
||||
}
|
||||
style[property] = config.to[property];
|
||||
}
|
||||
this.onTransitionEnd(null, el, {
|
||||
config: config,
|
||||
after: after
|
||||
});
|
||||
return me;
|
||||
}
|
||||
|
||||
el.un('transitionend', me.onTransitionEnd, me);
|
||||
|
||||
style.webkitTransitionDuration = '0ms';
|
||||
for (property in config.from) {
|
||||
if (!config.from.hasOwnProperty(property)) {
|
||||
continue;
|
||||
}
|
||||
style[property] = config.from[property];
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
// If this element has been destroyed since the timeout started, do nothing
|
||||
if (!el.dom) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is a 3d animation we have to set the perspective on the parent
|
||||
if (config.is3d === true) {
|
||||
el.parent().setStyle({
|
||||
// See https://sencha.jira.com/browse/TOUCH-1498
|
||||
'-webkit-perspective': '1200',
|
||||
'-webkit-transform-style': 'preserve-3d'
|
||||
});
|
||||
}
|
||||
|
||||
style.webkitTransitionDuration = config.duration + 'ms';
|
||||
style.webkitTransitionProperty = 'all';
|
||||
style.webkitTransitionTimingFunction = config.easing;
|
||||
|
||||
// Bind our listener that fires after the animation ends
|
||||
el.on('transitionend', me.onTransitionEnd, me, {
|
||||
single: true,
|
||||
config: config,
|
||||
after: after
|
||||
});
|
||||
|
||||
for (property in config.to) {
|
||||
if (!config.to.hasOwnProperty(property)) {
|
||||
continue;
|
||||
}
|
||||
style[property] = config.to[property];
|
||||
}
|
||||
}, config.delay || 5);
|
||||
|
||||
me.running[el.id] = config;
|
||||
return me;
|
||||
},
|
||||
|
||||
onTransitionEnd: function(ev, el, o) {
|
||||
el = Ext.get(el);
|
||||
|
||||
if (this.running[el.id] === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var style = el.dom.style,
|
||||
config = o.config,
|
||||
me = this,
|
||||
property;
|
||||
|
||||
if (config.autoClear) {
|
||||
for (property in config.to) {
|
||||
if (!config.to.hasOwnProperty(property) || config[property] === false) {
|
||||
continue;
|
||||
}
|
||||
style[property] = '';
|
||||
}
|
||||
}
|
||||
|
||||
style.webkitTransitionDuration = null;
|
||||
style.webkitTransitionProperty = null;
|
||||
style.webkitTransitionTimingFunction = null;
|
||||
|
||||
if (config.is3d) {
|
||||
el.parent().setStyle({
|
||||
'-webkit-perspective': '',
|
||||
'-webkit-transform-style': ''
|
||||
});
|
||||
}
|
||||
|
||||
if (me.config.after) {
|
||||
me.config.after.call(config, el, config);
|
||||
}
|
||||
|
||||
if (o.after) {
|
||||
o.after.call(config.scope || me, el, config);
|
||||
}
|
||||
|
||||
delete me.running[el.id];
|
||||
}
|
||||
}, function() {
|
||||
|
||||
Ext.Anim.seed = 1000;
|
||||
|
||||
/**
|
||||
* Used to run an animation on a specific element. Use the config argument to customize the animation.
|
||||
* @param {Ext.Element/HTMLElement} el The element to animate.
|
||||
* @param {String} anim The animation type, defined in {@link Ext.anims}.
|
||||
* @param {Object} config The config object for the animation.
|
||||
* @method run
|
||||
*/
|
||||
Ext.Anim.run = function(el, anim, config) {
|
||||
if (el.isComponent) {
|
||||
el = el.element;
|
||||
}
|
||||
|
||||
config = config || {};
|
||||
|
||||
if (anim.isAnim) {
|
||||
anim.run(el, config);
|
||||
}
|
||||
else {
|
||||
if (Ext.isObject(anim)) {
|
||||
if (config.before && anim.before) {
|
||||
config.before = Ext.createInterceptor(config.before, anim.before, anim.scope);
|
||||
}
|
||||
if (config.after && anim.after) {
|
||||
config.after = Ext.createInterceptor(config.after, anim.after, anim.scope);
|
||||
}
|
||||
config = Ext.apply({}, config, anim);
|
||||
anim = anim.type;
|
||||
}
|
||||
|
||||
if (!Ext.anims[anim]) {
|
||||
throw anim + ' is not a valid animation type.';
|
||||
}
|
||||
else {
|
||||
// add el check to make sure dom exists.
|
||||
if (el && el.dom) {
|
||||
Ext.anims[anim].run(el, config);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Ext.anims
|
||||
* Defines different types of animations.
|
||||
*
|
||||
* __Note:__ _flip_, _cube_, and _wipe_ animations do not work on Android.
|
||||
*
|
||||
* Please refer to {@link Ext.Anim} on how to use animations.
|
||||
* @singleton
|
||||
*/
|
||||
Ext.anims = {
|
||||
/**
|
||||
* Fade Animation
|
||||
*/
|
||||
fade: new Ext.Anim({
|
||||
type: 'fade',
|
||||
before: function(el) {
|
||||
var fromOpacity = 1,
|
||||
toOpacity = 1,
|
||||
curZ = el.getStyle('z-index') == 'auto' ? 0 : el.getStyle('z-index'),
|
||||
zIndex = curZ;
|
||||
|
||||
if (this.out) {
|
||||
toOpacity = 0;
|
||||
} else {
|
||||
zIndex = Math.abs(curZ) + 1;
|
||||
fromOpacity = 0;
|
||||
}
|
||||
|
||||
this.from = {
|
||||
'opacity': fromOpacity,
|
||||
'z-index': zIndex
|
||||
};
|
||||
this.to = {
|
||||
'opacity': toOpacity,
|
||||
'z-index': zIndex
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Slide Animation
|
||||
*/
|
||||
slide: new Ext.Anim({
|
||||
direction: 'left',
|
||||
cover: false,
|
||||
reveal: false,
|
||||
opacity: false,
|
||||
'z-index': false,
|
||||
|
||||
before: function(el) {
|
||||
var currentZIndex = el.getStyle('z-index') == 'auto' ? 0 : el.getStyle('z-index'),
|
||||
currentOpacity = el.getStyle('opacity'),
|
||||
zIndex = currentZIndex + 1,
|
||||
out = this.out,
|
||||
direction = this.direction,
|
||||
toX = 0,
|
||||
toY = 0,
|
||||
fromX = 0,
|
||||
fromY = 0,
|
||||
elH = el.getHeight(),
|
||||
elW = el.getWidth();
|
||||
|
||||
if (direction == 'left' || direction == 'right') {
|
||||
if (out) {
|
||||
toX = -elW;
|
||||
}
|
||||
else {
|
||||
fromX = elW;
|
||||
}
|
||||
}
|
||||
else if (direction == 'up' || direction == 'down') {
|
||||
if (out) {
|
||||
toY = -elH;
|
||||
}
|
||||
else {
|
||||
fromY = elH;
|
||||
}
|
||||
}
|
||||
|
||||
if (direction == 'right' || direction == 'down') {
|
||||
toY *= -1;
|
||||
toX *= -1;
|
||||
fromY *= -1;
|
||||
fromX *= -1;
|
||||
}
|
||||
|
||||
if (this.cover && out) {
|
||||
toX = 0;
|
||||
toY = 0;
|
||||
zIndex = currentZIndex;
|
||||
}
|
||||
else if (this.reveal && !out) {
|
||||
fromX = 0;
|
||||
fromY = 0;
|
||||
zIndex = currentZIndex;
|
||||
}
|
||||
|
||||
this.from = {
|
||||
'-webkit-transform': 'translate3d(' + fromX + 'px, ' + fromY + 'px, 0)',
|
||||
'z-index': zIndex,
|
||||
'opacity': currentOpacity - 0.01
|
||||
};
|
||||
this.to = {
|
||||
'-webkit-transform': 'translate3d(' + toX + 'px, ' + toY + 'px, 0)',
|
||||
'z-index': zIndex,
|
||||
'opacity': currentOpacity
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Pop Animation
|
||||
*/
|
||||
pop: new Ext.Anim({
|
||||
scaleOnExit: true,
|
||||
before: function(el) {
|
||||
var fromScale = 1,
|
||||
toScale = 1,
|
||||
fromOpacity = 1,
|
||||
toOpacity = 1,
|
||||
curZ = el.getStyle('z-index') == 'auto' ? 0 : el.getStyle('z-index'),
|
||||
fromZ = curZ,
|
||||
toZ = curZ;
|
||||
|
||||
if (!this.out) {
|
||||
fromScale = 0.01;
|
||||
fromZ = curZ + 1;
|
||||
toZ = curZ + 1;
|
||||
fromOpacity = 0;
|
||||
}
|
||||
else {
|
||||
if (this.scaleOnExit) {
|
||||
toScale = 0.01;
|
||||
toOpacity = 0;
|
||||
} else {
|
||||
toOpacity = 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
this.from = {
|
||||
'-webkit-transform': 'scale(' + fromScale + ')',
|
||||
'-webkit-transform-origin': '50% 50%',
|
||||
'opacity': fromOpacity,
|
||||
'z-index': fromZ
|
||||
};
|
||||
|
||||
this.to = {
|
||||
'-webkit-transform': 'scale(' + toScale + ')',
|
||||
'-webkit-transform-origin': '50% 50%',
|
||||
'opacity': toOpacity,
|
||||
'z-index': toZ
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Flip Animation
|
||||
*/
|
||||
flip: new Ext.Anim({
|
||||
is3d: true,
|
||||
direction: 'left',
|
||||
before: function(el) {
|
||||
var rotateProp = 'Y',
|
||||
fromScale = 1,
|
||||
toScale = 1,
|
||||
fromRotate = 0,
|
||||
toRotate = 0;
|
||||
|
||||
if (this.out) {
|
||||
toRotate = -180;
|
||||
toScale = 0.8;
|
||||
}
|
||||
else {
|
||||
fromRotate = 180;
|
||||
fromScale = 0.8;
|
||||
}
|
||||
|
||||
if (this.direction == 'up' || this.direction == 'down') {
|
||||
rotateProp = 'X';
|
||||
}
|
||||
|
||||
if (this.direction == 'right' || this.direction == 'left') {
|
||||
toRotate *= -1;
|
||||
fromRotate *= -1;
|
||||
}
|
||||
|
||||
this.from = {
|
||||
'-webkit-transform': 'rotate' + rotateProp + '(' + fromRotate + 'deg) scale(' + fromScale + ')',
|
||||
'-webkit-backface-visibility': 'hidden'
|
||||
};
|
||||
this.to = {
|
||||
'-webkit-transform': 'rotate' + rotateProp + '(' + toRotate + 'deg) scale(' + toScale + ')',
|
||||
'-webkit-backface-visibility': 'hidden'
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Cube Animation
|
||||
*/
|
||||
cube: new Ext.Anim({
|
||||
is3d: true,
|
||||
direction: 'left',
|
||||
style: 'outer',
|
||||
before: function(el) {
|
||||
var origin = '0% 0%',
|
||||
fromRotate = 0,
|
||||
toRotate = 0,
|
||||
rotateProp = 'Y',
|
||||
fromZ = 0,
|
||||
toZ = 0,
|
||||
elW = el.getWidth(),
|
||||
elH = el.getHeight(),
|
||||
showTranslateZ = true,
|
||||
fromTranslate = ' translateX(0)',
|
||||
toTranslate = '';
|
||||
|
||||
if (this.direction == 'left' || this.direction == 'right') {
|
||||
if (this.out) {
|
||||
origin = '100% 100%';
|
||||
toZ = elW;
|
||||
toRotate = -90;
|
||||
} else {
|
||||
origin = '0% 0%';
|
||||
fromZ = elW;
|
||||
fromRotate = 90;
|
||||
}
|
||||
} else if (this.direction == 'up' || this.direction == 'down') {
|
||||
rotateProp = 'X';
|
||||
if (this.out) {
|
||||
origin = '100% 100%';
|
||||
toZ = elH;
|
||||
toRotate = 90;
|
||||
} else {
|
||||
origin = '0% 0%';
|
||||
fromZ = elH;
|
||||
fromRotate = -90;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.direction == 'down' || this.direction == 'right') {
|
||||
fromRotate *= -1;
|
||||
toRotate *= -1;
|
||||
origin = (origin == '0% 0%') ? '100% 100%': '0% 0%';
|
||||
}
|
||||
|
||||
if (this.style == 'inner') {
|
||||
fromZ *= -1;
|
||||
toZ *= -1;
|
||||
fromRotate *= -1;
|
||||
toRotate *= -1;
|
||||
|
||||
if (!this.out) {
|
||||
toTranslate = ' translateX(0px)';
|
||||
origin = '0% 50%';
|
||||
} else {
|
||||
toTranslate = fromTranslate;
|
||||
origin = '100% 50%';
|
||||
}
|
||||
}
|
||||
|
||||
this.from = {
|
||||
'-webkit-transform': 'rotate' + rotateProp + '(' + fromRotate + 'deg)' + (showTranslateZ ? ' translateZ(' + fromZ + 'px)': '') + fromTranslate,
|
||||
'-webkit-transform-origin': origin
|
||||
};
|
||||
this.to = {
|
||||
'-webkit-transform': 'rotate' + rotateProp + '(' + toRotate + 'deg) translateZ(' + toZ + 'px)' + toTranslate,
|
||||
'-webkit-transform-origin': origin
|
||||
};
|
||||
},
|
||||
duration: 250
|
||||
}),
|
||||
|
||||
|
||||
/**
|
||||
* Wipe Animation.
|
||||
* Because of the amount of calculations involved, this animation is best used on small display
|
||||
* changes or specifically for phone environments. Does not currently accept any parameters.
|
||||
*/
|
||||
wipe: new Ext.Anim({
|
||||
before: function(el) {
|
||||
var curZ = el.getStyle('z-index'),
|
||||
zIndex,
|
||||
mask = '';
|
||||
|
||||
if (!this.out) {
|
||||
zIndex = curZ + 1;
|
||||
mask = '-webkit-gradient(linear, left bottom, right bottom, from(transparent), to(#000), color-stop(66%, #000), color-stop(33%, transparent))';
|
||||
|
||||
this.from = {
|
||||
'-webkit-mask-image': mask,
|
||||
'-webkit-mask-size': el.getWidth() * 3 + 'px ' + el.getHeight() + 'px',
|
||||
'z-index': zIndex,
|
||||
'-webkit-mask-position-x': 0
|
||||
};
|
||||
this.to = {
|
||||
'-webkit-mask-image': mask,
|
||||
'-webkit-mask-size': el.getWidth() * 3 + 'px ' + el.getHeight() + 'px',
|
||||
'z-index': zIndex,
|
||||
'-webkit-mask-position-x': -el.getWidth() * 2 + 'px'
|
||||
};
|
||||
}
|
||||
},
|
||||
duration: 500
|
||||
})
|
||||
};
|
||||
});
|
||||
138
OfficeWeb/3rdparty/touch/src/Audio.js
vendored
Normal file
138
OfficeWeb/3rdparty/touch/src/Audio.js
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* {@link Ext.Audio} is a simple class which provides a container for the [HTML5 Audio element](http://developer.mozilla.org/en-US/docs/Using_HTML5_audio_and_video).
|
||||
*
|
||||
* ## Recommended File Types/Compression:
|
||||
* * Uncompressed WAV and AIF audio
|
||||
* * MP3 audio
|
||||
* * AAC-LC
|
||||
* * HE-AAC audio
|
||||
*
|
||||
* ## Notes
|
||||
* On Android devices, the audio tags controls do not show. You must use the {@link #method-play}, {@link #method-pause} and
|
||||
* {@link #toggle} methods to control the audio (example below).
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* Here is an example of the {@link Ext.Audio} component in a fullscreen container:
|
||||
*
|
||||
* @example preview
|
||||
* Ext.create('Ext.Container', {
|
||||
* fullscreen: true,
|
||||
* layout: {
|
||||
* type : 'vbox',
|
||||
* pack : 'center',
|
||||
* align: 'stretch'
|
||||
* },
|
||||
* items: [
|
||||
* {
|
||||
* xtype : 'toolbar',
|
||||
* docked: 'top',
|
||||
* title : 'Ext.Audio'
|
||||
* },
|
||||
* {
|
||||
* xtype: 'audio',
|
||||
* url : 'touch/examples/audio/crash.mp3'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* You can also set the {@link #hidden} configuration of the {@link Ext.Audio} component to true by default,
|
||||
* and then control the audio by using the {@link #method-play}, {@link #method-pause} and {@link #toggle} methods:
|
||||
*
|
||||
* @example preview
|
||||
* Ext.create('Ext.Container', {
|
||||
* fullscreen: true,
|
||||
* layout: {
|
||||
* type: 'vbox',
|
||||
* pack: 'center'
|
||||
* },
|
||||
* items: [
|
||||
* {
|
||||
* xtype : 'toolbar',
|
||||
* docked: 'top',
|
||||
* title : 'Ext.Audio'
|
||||
* },
|
||||
* {
|
||||
* xtype: 'toolbar',
|
||||
* docked: 'bottom',
|
||||
* defaults: {
|
||||
* xtype: 'button',
|
||||
* handler: function() {
|
||||
* var container = this.getParent().getParent(),
|
||||
* // use ComponentQuery to get the audio component (using its xtype)
|
||||
* audio = container.down('audio');
|
||||
*
|
||||
* audio.toggle();
|
||||
* this.setText(audio.isPlaying() ? 'Pause' : 'Play');
|
||||
* }
|
||||
* },
|
||||
* items: [
|
||||
* { text: 'Play', flex: 1 }
|
||||
* ]
|
||||
* },
|
||||
* {
|
||||
* html: 'Hidden audio!',
|
||||
* styleHtmlContent: true
|
||||
* },
|
||||
* {
|
||||
* xtype : 'audio',
|
||||
* hidden: true,
|
||||
* url : 'touch/examples/audio/crash.mp3'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
* @aside example audio
|
||||
*/
|
||||
Ext.define('Ext.Audio', {
|
||||
extend: 'Ext.Media',
|
||||
xtype : 'audio',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
cls: Ext.baseCSSPrefix + 'audio'
|
||||
|
||||
/**
|
||||
* @cfg {String} url
|
||||
* The location of the audio to play.
|
||||
*
|
||||
* ### Recommended file types are:
|
||||
* * Uncompressed WAV and AIF audio
|
||||
* * MP3 audio
|
||||
* * AAC-LC
|
||||
* * HE-AAC audio
|
||||
* @accessor
|
||||
*/
|
||||
},
|
||||
|
||||
// @private
|
||||
onActivate: function() {
|
||||
var me = this;
|
||||
|
||||
me.callParent();
|
||||
|
||||
if (Ext.os.is.Phone) {
|
||||
me.element.show();
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
onDeactivate: function() {
|
||||
var me = this;
|
||||
|
||||
me.callParent();
|
||||
|
||||
if (Ext.os.is.Phone) {
|
||||
me.element.hide();
|
||||
}
|
||||
},
|
||||
|
||||
template: [{
|
||||
reference: 'media',
|
||||
preload: 'auto',
|
||||
tag: 'audio',
|
||||
cls: Ext.baseCSSPrefix + 'component'
|
||||
}]
|
||||
});
|
||||
781
OfficeWeb/3rdparty/touch/src/Button.js
vendored
Normal file
781
OfficeWeb/3rdparty/touch/src/Button.js
vendored
Normal file
@@ -0,0 +1,781 @@
|
||||
/**
|
||||
* A simple class to display a button in Sencha Touch.
|
||||
*
|
||||
* There are various different styles of Button you can create by using the {@link #icon},
|
||||
* {@link #iconCls}, {@link #iconAlign}, {@link #iconMask}, {@link #ui}, and {@link #text}
|
||||
* configurations.
|
||||
*
|
||||
* ## Simple Button
|
||||
*
|
||||
* Here is a Button in it's simplest form:
|
||||
*
|
||||
* @example miniphone
|
||||
* var button = Ext.create('Ext.Button', {
|
||||
* text: 'Button'
|
||||
* });
|
||||
* Ext.Viewport.add({ xtype: 'container', padding: 10, items: [button] });
|
||||
*
|
||||
* ## Icons
|
||||
*
|
||||
* You can also create a Button with just an icon using the {@link #iconCls} configuration:
|
||||
*
|
||||
* @example miniphone
|
||||
* var button = Ext.create('Ext.Button', {
|
||||
* iconCls: 'refresh',
|
||||
* iconMask: true
|
||||
* });
|
||||
* Ext.Viewport.add({ xtype: 'container', padding: 10, items: [button] });
|
||||
*
|
||||
* Note that the {@link #iconMask} configuration is required when you want to use any of the
|
||||
* bundled Pictos icons.
|
||||
*
|
||||
* Here are the included icons available (if {@link Global_CSS#$include-default-icons $include-default-icons}
|
||||
* is set to `true`):
|
||||
*
|
||||
* -  action
|
||||
* -  add
|
||||
* -  arrow_down
|
||||
* -  arrow_left
|
||||
* -  arrow_right
|
||||
* -  arrow_up
|
||||
* -  bookmarks
|
||||
* -  compose
|
||||
* -  delete
|
||||
* -  download
|
||||
* -  favorites
|
||||
* -  home
|
||||
* -  info
|
||||
* -  locate
|
||||
* -  maps
|
||||
* -  more
|
||||
* -  organize
|
||||
* -  refresh
|
||||
* -  reply
|
||||
* -  search
|
||||
* -  settings
|
||||
* -  star
|
||||
* -  team
|
||||
* -  time
|
||||
* -  trash
|
||||
* -  user
|
||||
*
|
||||
* You can also use other pictos icons by using the {@link Global_CSS#pictos-iconmask pictos-iconmask} mixin in your Sass.
|
||||
*
|
||||
* ## Badges
|
||||
*
|
||||
* Buttons can also have a badge on them, by using the {@link #badgeText} configuration:
|
||||
*
|
||||
* @example
|
||||
* Ext.create('Ext.Container', {
|
||||
* fullscreen: true,
|
||||
* padding: 10,
|
||||
* items: {
|
||||
* xtype: 'button',
|
||||
* text: 'My Button',
|
||||
* badgeText: '2'
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* ## UI
|
||||
*
|
||||
* Buttons also come with a range of different default UIs. Here are the included UIs
|
||||
* available (if {@link #$include-button-uis $include-button-uis} is set to `true`):
|
||||
*
|
||||
* - **normal** - a basic gray button
|
||||
* - **back** - a back button
|
||||
* - **forward** - a forward button
|
||||
* - **round** - a round button
|
||||
* - **action** - shaded using the {@link Global_CSS#$active-color $active-color} (dark blue by default)
|
||||
* - **decline** - shaded using the {@link Global_CSS#$alert-color $alert-color} (red by default)
|
||||
* - **confirm** - shaded using the {@link Global_CSS#$confirm-color $confirm-color} (green by default)
|
||||
*
|
||||
* And setting them is very simple:
|
||||
*
|
||||
* var uiButton = Ext.create('Ext.Button', {
|
||||
* text: 'My Button',
|
||||
* ui: 'action'
|
||||
* });
|
||||
*
|
||||
* And how they look:
|
||||
*
|
||||
* @example miniphone preview
|
||||
* Ext.create('Ext.Container', {
|
||||
* fullscreen: true,
|
||||
* padding: 4,
|
||||
* defaults: {
|
||||
* xtype: 'button',
|
||||
* margin: 5
|
||||
* },
|
||||
* layout: {
|
||||
* type: 'vbox',
|
||||
* align: 'center'
|
||||
* },
|
||||
* items: [
|
||||
* { ui: 'normal', text: 'normal' },
|
||||
* { ui: 'round', text: 'round' },
|
||||
* { ui: 'action', text: 'action' },
|
||||
* { ui: 'decline', text: 'decline' },
|
||||
* { ui: 'confirm', text: 'confirm' }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* Note that the default {@link #ui} is **normal**.
|
||||
*
|
||||
* You can also use the {@link #sencha-button-ui sencha-button-ui} CSS Mixin to create your own UIs.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* This example shows a bunch of icons on the screen in two toolbars. When you click on the center
|
||||
* button, it switches the {@link #iconCls} on every button on the page.
|
||||
*
|
||||
* @example preview
|
||||
* Ext.createWidget('container', {
|
||||
* fullscreen: true,
|
||||
* layout: {
|
||||
* type: 'vbox',
|
||||
* pack:'center',
|
||||
* align: 'center'
|
||||
* },
|
||||
* items: [
|
||||
* {
|
||||
* xtype: 'button',
|
||||
* text: 'Change iconCls',
|
||||
* handler: function() {
|
||||
* // classes for all the icons to loop through.
|
||||
* var availableIconCls = [
|
||||
* 'action', 'add', 'arrow_down', 'arrow_left',
|
||||
* 'arrow_right', 'arrow_up', 'compose', 'delete',
|
||||
* 'organize', 'refresh', 'reply', 'search',
|
||||
* 'settings', 'star', 'trash', 'maps', 'locate',
|
||||
* 'home'
|
||||
* ];
|
||||
* // get the text of this button,
|
||||
* // so we know which button we don't want to change
|
||||
* var text = this.getText();
|
||||
*
|
||||
* // use ComponentQuery to find all buttons on the page
|
||||
* // and loop through all of them
|
||||
* Ext.Array.forEach(Ext.ComponentQuery.query('button'), function(button) {
|
||||
* // if the button is the change iconCls button, continue
|
||||
* if (button.getText() === text) {
|
||||
* return;
|
||||
* }
|
||||
*
|
||||
* // get the index of the new available iconCls
|
||||
* var index = availableIconCls.indexOf(button.getIconCls()) + 1;
|
||||
*
|
||||
* // update the iconCls of the button with the next iconCls, if one exists.
|
||||
* // if not, use the first one
|
||||
* button.setIconCls(availableIconCls[(index === availableIconCls.length) ? 0 : index]);
|
||||
* });
|
||||
* }
|
||||
* },
|
||||
* {
|
||||
* xtype: 'toolbar',
|
||||
* docked: 'top',
|
||||
* defaults: {
|
||||
* iconMask: true
|
||||
* },
|
||||
* items: [
|
||||
* { xtype: 'spacer' },
|
||||
* { iconCls: 'action' },
|
||||
* { iconCls: 'add' },
|
||||
* { iconCls: 'arrow_down' },
|
||||
* { iconCls: 'arrow_left' },
|
||||
* { iconCls: 'arrow_up' },
|
||||
* { iconCls: 'compose' },
|
||||
* { iconCls: 'delete' },
|
||||
* { iconCls: 'organize' },
|
||||
* { iconCls: 'refresh' },
|
||||
* { xtype: 'spacer' }
|
||||
* ]
|
||||
* },
|
||||
* {
|
||||
* xtype: 'toolbar',
|
||||
* docked: 'bottom',
|
||||
* ui: 'light',
|
||||
* defaults: {
|
||||
* iconMask: true
|
||||
* },
|
||||
* items: [
|
||||
* { xtype: 'spacer' },
|
||||
* { iconCls: 'reply' },
|
||||
* { iconCls: 'search' },
|
||||
* { iconCls: 'settings' },
|
||||
* { iconCls: 'star' },
|
||||
* { iconCls: 'trash' },
|
||||
* { iconCls: 'maps' },
|
||||
* { iconCls: 'locate' },
|
||||
* { iconCls: 'home' },
|
||||
* { xtype: 'spacer' }
|
||||
* ]
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.Button', {
|
||||
extend: 'Ext.Component',
|
||||
|
||||
xtype: 'button',
|
||||
|
||||
/**
|
||||
* @event tap
|
||||
* @preventable doTap
|
||||
* Fires whenever a button is tapped.
|
||||
* @param {Ext.Button} this The item added to the Container.
|
||||
* @param {Ext.EventObject} e The event object.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event release
|
||||
* @preventable doRelease
|
||||
* Fires whenever the button is released.
|
||||
* @param {Ext.Button} this The item added to the Container.
|
||||
* @param {Ext.EventObject} e The event object.
|
||||
*/
|
||||
|
||||
cachedConfig: {
|
||||
/**
|
||||
* @cfg {String} pressedCls
|
||||
* The CSS class to add to the Button when it is pressed.
|
||||
* @accessor
|
||||
*/
|
||||
pressedCls: Ext.baseCSSPrefix + 'button-pressing',
|
||||
|
||||
/**
|
||||
* @cfg {String} badgeCls
|
||||
* The CSS class to add to the Button's badge, if it has one.
|
||||
* @accessor
|
||||
*/
|
||||
badgeCls: Ext.baseCSSPrefix + 'badge',
|
||||
|
||||
/**
|
||||
* @cfg {String} hasBadgeCls
|
||||
* The CSS class to add to the Button if it has a badge (note that this goes on the
|
||||
* Button element itself, not on the badge element).
|
||||
* @private
|
||||
* @accessor
|
||||
*/
|
||||
hasBadgeCls: Ext.baseCSSPrefix + 'hasbadge',
|
||||
|
||||
/**
|
||||
* @cfg {String} labelCls
|
||||
* The CSS class to add to the field's label element.
|
||||
* @accessor
|
||||
*/
|
||||
labelCls: Ext.baseCSSPrefix + 'button-label',
|
||||
|
||||
/**
|
||||
* @cfg {String} iconMaskCls
|
||||
* @private
|
||||
* The CSS class to add to the icon element as allowed by {@link #iconMask}.
|
||||
* @accessor
|
||||
*/
|
||||
iconMaskCls: Ext.baseCSSPrefix + 'icon-mask',
|
||||
|
||||
/**
|
||||
* @cfg {String} iconCls
|
||||
* Optional CSS class to add to the icon element. This is useful if you want to use a CSS
|
||||
* background image to create your Button icon.
|
||||
* @accessor
|
||||
*/
|
||||
iconCls: null
|
||||
},
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} badgeText
|
||||
* Optional badge text.
|
||||
* @accessor
|
||||
*/
|
||||
badgeText: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} text
|
||||
* The Button text.
|
||||
* @accessor
|
||||
*/
|
||||
text: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} icon
|
||||
* Url to the icon image to use if you want an icon to appear on your button.
|
||||
* @accessor
|
||||
*/
|
||||
icon: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} iconAlign
|
||||
* The position within the Button to render the icon Options are: `top`, `right`, `bottom`, `left` and `center` (when you have
|
||||
* no {@link #text} set).
|
||||
* @accessor
|
||||
*/
|
||||
iconAlign: 'left',
|
||||
|
||||
/**
|
||||
* @cfg {Number/Boolean} pressedDelay
|
||||
* The amount of delay between the `tapstart` and the moment we add the `pressedCls` (in milliseconds).
|
||||
* Settings this to `true` defaults to 100ms.
|
||||
*/
|
||||
pressedDelay: 0,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} iconMask
|
||||
* Whether or not to mask the icon with the `iconMask` configuration.
|
||||
* This is needed if you want to use any of the bundled pictos icons in the Sencha Touch Sass.
|
||||
* @accessor
|
||||
*/
|
||||
iconMask: null,
|
||||
|
||||
/**
|
||||
* @cfg {Function} handler
|
||||
* The handler function to run when the Button is tapped on.
|
||||
* @accessor
|
||||
*/
|
||||
handler: null,
|
||||
|
||||
/**
|
||||
* @cfg {Object} scope
|
||||
* The scope to fire the configured {@link #handler} in.
|
||||
* @accessor
|
||||
*/
|
||||
scope: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} autoEvent
|
||||
* Optional event name that will be fired instead of `tap` when the Button is tapped on.
|
||||
* @accessor
|
||||
*/
|
||||
autoEvent: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} ui
|
||||
* The ui style to render this button with. The valid default options are:
|
||||
*
|
||||
* - `'normal'` - a basic gray button (default).
|
||||
* - `'back'` - a back button.
|
||||
* - `'forward'` - a forward button.
|
||||
* - `'round'` - a round button.
|
||||
* - `'action'` - shaded using the {@link Global_CSS#$active-color $active-color} (dark blue by default).
|
||||
* - `'decline'` - shaded using the {@link Global_CSS#$alert-color $alert-color} (red by default).
|
||||
* - `'confirm'` - shaded using the {@link Global_CSS#$confirm-color $confirm-color} (green by default).
|
||||
* - `'plain'`
|
||||
*
|
||||
* @accessor
|
||||
*/
|
||||
ui: 'normal',
|
||||
|
||||
/**
|
||||
* @cfg {String} html The HTML to put in this button.
|
||||
*
|
||||
* If you want to just add text, please use the {@link #text} configuration.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: Ext.baseCSSPrefix + 'button'
|
||||
},
|
||||
|
||||
template: [
|
||||
{
|
||||
tag: 'span',
|
||||
reference: 'badgeElement',
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
tag: 'span',
|
||||
className: Ext.baseCSSPrefix + 'button-icon',
|
||||
reference: 'iconElement',
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
tag: 'span',
|
||||
reference: 'textElement',
|
||||
hidden: true
|
||||
}
|
||||
],
|
||||
|
||||
initialize: function() {
|
||||
this.callParent();
|
||||
|
||||
this.element.on({
|
||||
scope : this,
|
||||
tap : 'onTap',
|
||||
touchstart : 'onPress',
|
||||
touchend : 'onRelease'
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateBadgeText: function(badgeText) {
|
||||
var element = this.element,
|
||||
badgeElement = this.badgeElement;
|
||||
|
||||
if (badgeText) {
|
||||
badgeElement.show();
|
||||
badgeElement.setText(badgeText);
|
||||
}
|
||||
else {
|
||||
badgeElement.hide();
|
||||
}
|
||||
|
||||
element[(badgeText) ? 'addCls' : 'removeCls'](this.getHasBadgeCls());
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateText: function(text) {
|
||||
var textElement = this.textElement;
|
||||
if (textElement) {
|
||||
if (text) {
|
||||
textElement.show();
|
||||
textElement.setHtml(text);
|
||||
}
|
||||
else {
|
||||
textElement.hide();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateHtml: function(html) {
|
||||
var textElement = this.textElement;
|
||||
|
||||
if (html) {
|
||||
textElement.show();
|
||||
textElement.setHtml(html);
|
||||
}
|
||||
else {
|
||||
textElement.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateBadgeCls: function(badgeCls, oldBadgeCls) {
|
||||
this.badgeElement.replaceCls(oldBadgeCls, badgeCls);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateHasBadgeCls: function(hasBadgeCls, oldHasBadgeCls) {
|
||||
var element = this.element;
|
||||
|
||||
if (element.hasCls(oldHasBadgeCls)) {
|
||||
element.replaceCls(oldHasBadgeCls, hasBadgeCls);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateLabelCls: function(labelCls, oldLabelCls) {
|
||||
this.textElement.replaceCls(oldLabelCls, labelCls);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updatePressedCls: function(pressedCls, oldPressedCls) {
|
||||
var element = this.element;
|
||||
|
||||
if (element.hasCls(oldPressedCls)) {
|
||||
element.replaceCls(oldPressedCls, pressedCls);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateIcon: function(icon) {
|
||||
var me = this,
|
||||
element = me.iconElement;
|
||||
|
||||
if (icon) {
|
||||
me.showIconElement();
|
||||
element.setStyle('background-image', icon ? 'url(' + icon + ')' : '');
|
||||
me.refreshIconAlign();
|
||||
me.refreshIconMask();
|
||||
}
|
||||
else {
|
||||
me.hideIconElement();
|
||||
me.setIconAlign(false);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateIconCls: function(iconCls, oldIconCls) {
|
||||
var me = this,
|
||||
element = me.iconElement;
|
||||
|
||||
if (iconCls) {
|
||||
me.showIconElement();
|
||||
element.replaceCls(oldIconCls, iconCls);
|
||||
me.refreshIconAlign();
|
||||
me.refreshIconMask();
|
||||
}
|
||||
else {
|
||||
me.hideIconElement();
|
||||
me.setIconAlign(false);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateIconAlign: function(alignment, oldAlignment) {
|
||||
var element = this.element,
|
||||
baseCls = Ext.baseCSSPrefix + 'iconalign-';
|
||||
|
||||
if (!this.getText()) {
|
||||
alignment = "center";
|
||||
}
|
||||
|
||||
element.removeCls(baseCls + "center");
|
||||
element.removeCls(baseCls + oldAlignment);
|
||||
if (this.getIcon() || this.getIconCls()) {
|
||||
element.addCls(baseCls + alignment);
|
||||
}
|
||||
},
|
||||
|
||||
refreshIconAlign: function() {
|
||||
this.updateIconAlign(this.getIconAlign());
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateIconMaskCls: function(iconMaskCls, oldIconMaskCls) {
|
||||
var element = this.iconElement;
|
||||
|
||||
if (this.getIconMask()) {
|
||||
element.replaceCls(oldIconMaskCls, iconMaskCls);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateIconMask: function(iconMask) {
|
||||
this.iconElement[iconMask ? "addCls" : "removeCls"](this.getIconMaskCls());
|
||||
},
|
||||
|
||||
refreshIconMask: function() {
|
||||
this.updateIconMask(this.getIconMask());
|
||||
},
|
||||
|
||||
applyAutoEvent: function(autoEvent) {
|
||||
var me = this;
|
||||
|
||||
if (typeof autoEvent == 'string') {
|
||||
autoEvent = {
|
||||
name : autoEvent,
|
||||
scope: me.scope || me
|
||||
};
|
||||
}
|
||||
|
||||
return autoEvent;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateAutoEvent: function(autoEvent) {
|
||||
var name = autoEvent.name,
|
||||
scope = autoEvent.scope;
|
||||
|
||||
this.setHandler(function() {
|
||||
scope.fireEvent(name, scope, this);
|
||||
});
|
||||
|
||||
this.setScope(scope);
|
||||
},
|
||||
|
||||
/**
|
||||
* Used by `icon` and `iconCls` configurations to hide the icon element.
|
||||
* We do this because Tab needs to change the visibility of the icon, not make
|
||||
* it `display:none;`.
|
||||
* @private
|
||||
*/
|
||||
hideIconElement: function() {
|
||||
this.iconElement.hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* Used by `icon` and `iconCls` configurations to show the icon element.
|
||||
* We do this because Tab needs to change the visibility of the icon, not make
|
||||
* it `display:node;`.
|
||||
* @private
|
||||
*/
|
||||
showIconElement: function() {
|
||||
this.iconElement.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* We override this to check for '{ui}-back'. This is because if you have a UI of back, you need to actually add two class names.
|
||||
* The ui class, and the back class:
|
||||
*
|
||||
* `ui: 'action-back'` would turn into:
|
||||
*
|
||||
* `class="x-button-action x-button-back"`
|
||||
*
|
||||
* But `ui: 'action'` would turn into:
|
||||
*
|
||||
* `class="x-button-action"`
|
||||
*
|
||||
* So we just split it up into an array and add both of them as a UI, when it has `back`.
|
||||
* @private
|
||||
*/
|
||||
applyUi: function(config) {
|
||||
if (config && Ext.isString(config)) {
|
||||
var array = config.split('-');
|
||||
if (array && (array[1] == "back" || array[1] == "forward")) {
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
|
||||
getUi: function() {
|
||||
//Now that the UI can sometimes be an array, we need to check if it an array and return the proper value.
|
||||
var ui = this._ui;
|
||||
if (Ext.isArray(ui)) {
|
||||
return ui.join('-');
|
||||
}
|
||||
return ui;
|
||||
},
|
||||
|
||||
applyPressedDelay: function(delay) {
|
||||
if (Ext.isNumber(delay)) {
|
||||
return delay;
|
||||
}
|
||||
return (delay) ? 100 : 0;
|
||||
},
|
||||
|
||||
// @private
|
||||
onPress: function() {
|
||||
var me = this,
|
||||
element = me.element,
|
||||
pressedDelay = me.getPressedDelay(),
|
||||
pressedCls = me.getPressedCls();
|
||||
|
||||
if (!me.getDisabled()) {
|
||||
if (pressedDelay > 0) {
|
||||
me.pressedTimeout = setTimeout(function() {
|
||||
delete me.pressedTimeout;
|
||||
if (element) {
|
||||
element.addCls(pressedCls);
|
||||
}
|
||||
}, pressedDelay);
|
||||
}
|
||||
else {
|
||||
element.addCls(pressedCls);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
onRelease: function(e) {
|
||||
this.fireAction('release', [this, e], 'doRelease');
|
||||
},
|
||||
|
||||
// @private
|
||||
doRelease: function(me, e) {
|
||||
if (!me.getDisabled()) {
|
||||
if (me.hasOwnProperty('pressedTimeout')) {
|
||||
clearTimeout(me.pressedTimeout);
|
||||
delete me.pressedTimeout;
|
||||
}
|
||||
else {
|
||||
me.element.removeCls(me.getPressedCls());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
onTap: function(e) {
|
||||
if (this.getDisabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.fireAction('tap', [this, e], 'doTap');
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
doTap: function(me, e) {
|
||||
var handler = me.getHandler(),
|
||||
scope = me.getScope() || me;
|
||||
|
||||
if (!handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof handler == 'string') {
|
||||
handler = scope[handler];
|
||||
}
|
||||
|
||||
//this is done so if you hide the button in the handler, the tap event will not fire on the new element
|
||||
//where the button was.
|
||||
if (e && e.preventDefault) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
handler.apply(scope, arguments);
|
||||
}
|
||||
}, function() {
|
||||
//<deprecated product=touch since=2.0>
|
||||
|
||||
/**
|
||||
* Updates the badge text.
|
||||
* @method setBadge
|
||||
* @param {String} text
|
||||
* @deprecated 2.0.0 Please use {@link #setBadgeText} instead.
|
||||
*/
|
||||
Ext.deprecateClassMethod(this, 'setBadge', 'setBadgeText');
|
||||
|
||||
/**
|
||||
* Updates the icon class
|
||||
* @method setIconClass
|
||||
* @param {String} iconClass
|
||||
* @deprecated 2.0.0 Please use {@link #setIconCls} instead.
|
||||
*/
|
||||
Ext.deprecateClassMethod(this, 'setIconClass', 'setIconCls');
|
||||
|
||||
this.override({
|
||||
constructor: function(config) {
|
||||
if (config) {
|
||||
/**
|
||||
* @cfg {String} badge
|
||||
* Optional badge text.
|
||||
* @deprecated 2.0.0 Please use {@link #badgeText} instead
|
||||
*/
|
||||
if (config.hasOwnProperty('badge')) {
|
||||
//<debug warn>
|
||||
Ext.Logger.deprecate("'badge' config is deprecated, please use 'badgeText' config instead", this);
|
||||
//</debug>
|
||||
config.badgeText = config.badge;
|
||||
delete config.badge;
|
||||
}
|
||||
}
|
||||
|
||||
this.callParent([config]);
|
||||
}
|
||||
});
|
||||
|
||||
//</deprecated>
|
||||
});
|
||||
2916
OfficeWeb/3rdparty/touch/src/Component.js
vendored
Normal file
2916
OfficeWeb/3rdparty/touch/src/Component.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
111
OfficeWeb/3rdparty/touch/src/ComponentManager.js
vendored
Normal file
111
OfficeWeb/3rdparty/touch/src/ComponentManager.js
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @private
|
||||
*
|
||||
* 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#getId id} (see {@link #get}, or the convenience method {@link Ext#getCmp Ext.getCmp}).
|
||||
*
|
||||
* This object also provides a registry of available Component _classes_
|
||||
* indexed by a mnemonic code known as the Component's `xtype`.
|
||||
* The `xtype` provides a way to avoid instantiating child Components
|
||||
* when creating a full, nested config object for a complete Ext page.
|
||||
*
|
||||
* A child Component may be specified simply as a _config object_
|
||||
* as long as the correct `xtype` is specified so that if and when the Component
|
||||
* needs rendering, the correct type can be looked up for lazy instantiation.
|
||||
*
|
||||
* For a list of all available `xtype`, see {@link Ext.Component}.
|
||||
*/
|
||||
Ext.define('Ext.ComponentManager', {
|
||||
alternateClassName: 'Ext.ComponentMgr',
|
||||
singleton: true,
|
||||
|
||||
constructor: function() {
|
||||
var map = {};
|
||||
|
||||
// The sole reason for this is just to support the old code of ComponentQuery
|
||||
this.all = {
|
||||
map: map,
|
||||
|
||||
getArray: function() {
|
||||
var list = [],
|
||||
id;
|
||||
|
||||
for (id in map) {
|
||||
list.push(map[id]);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
this.map = map;
|
||||
},
|
||||
|
||||
/**
|
||||
* Registers an item to be managed.
|
||||
* @param {Object} component The item to register.
|
||||
*/
|
||||
register: function(component) {
|
||||
var id = component.getId();
|
||||
|
||||
// <debug>
|
||||
if (this.map[id]) {
|
||||
Ext.Logger.warn('Registering a component with a id (`' + id + '`) which has already been used. Please ensure the existing component has been destroyed (`Ext.Component#destroy()`.');
|
||||
}
|
||||
// </debug>
|
||||
|
||||
this.map[component.getId()] = component;
|
||||
},
|
||||
|
||||
/**
|
||||
* Unregisters an item by removing it from this manager.
|
||||
* @param {Object} component The item to unregister.
|
||||
*/
|
||||
unregister: function(component) {
|
||||
delete this.map[component.getId()];
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if an item type is registered.
|
||||
* @param {String} component The mnemonic string by which the class may be looked up.
|
||||
* @return {Boolean} Whether the type is registered.
|
||||
*/
|
||||
isRegistered : function(component){
|
||||
return this.map[component] !== undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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, or `undefined` if not found.
|
||||
*/
|
||||
get: function(id) {
|
||||
return this.map[id];
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 `xtype`. (Optional if the config contains an `xtype`).
|
||||
* @return {Ext.Component} The newly instantiated Component.
|
||||
*/
|
||||
create: function(component, defaultType) {
|
||||
if (component.isComponent) {
|
||||
return component;
|
||||
}
|
||||
else if (Ext.isString(component)) {
|
||||
return Ext.createByAlias('widget.' + component);
|
||||
}
|
||||
else {
|
||||
var type = component.xtype || defaultType;
|
||||
|
||||
return Ext.createByAlias('widget.' + type, component);
|
||||
}
|
||||
},
|
||||
|
||||
registerType: Ext.emptyFn
|
||||
});
|
||||
530
OfficeWeb/3rdparty/touch/src/ComponentQuery.js
vendored
Normal file
530
OfficeWeb/3rdparty/touch/src/ComponentQuery.js
vendored
Normal file
@@ -0,0 +1,530 @@
|
||||
/**
|
||||
* @class Ext.ComponentQuery
|
||||
* @extends Object
|
||||
* @singleton
|
||||
*
|
||||
* Provides searching of Components within {@link Ext.ComponentManager} (globally) or a specific
|
||||
* {@link Ext.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
|
||||
*
|
||||
* 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#query},
|
||||
* {@link Ext.Container#down} and {@link Ext.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, getter, getValue;
|
||||
for (; i < length; i++) {
|
||||
candidate = items[i];
|
||||
getter = Ext.Class.getConfigNameMap(property).get;
|
||||
if (candidate[getter]) {
|
||||
getValue = candidate[getter]();
|
||||
if (!value ? !!getValue : (String(getValue) === value)) {
|
||||
result.push(candidate);
|
||||
}
|
||||
}
|
||||
else if (candidate.config && candidate.config[property]) {
|
||||
if (!value ? !!candidate.config[property] : (String(candidate.config[property]) === value)) {
|
||||
result.push(candidate);
|
||||
}
|
||||
}
|
||||
else 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.getId() === id || 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
|
||||
}];
|
||||
|
||||
cq.Query = Ext.extend(Object, {
|
||||
constructor: function(cfg) {
|
||||
cfg = cfg || {};
|
||||
Ext.apply(this, cfg);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* 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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 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} 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>
|
||||
* @return {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.parse(selector);
|
||||
// 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
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
1642
OfficeWeb/3rdparty/touch/src/Container.js
vendored
Normal file
1642
OfficeWeb/3rdparty/touch/src/Container.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1525
OfficeWeb/3rdparty/touch/src/DateExtras.js
vendored
Normal file
1525
OfficeWeb/3rdparty/touch/src/DateExtras.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
166
OfficeWeb/3rdparty/touch/src/Decorator.js
vendored
Normal file
166
OfficeWeb/3rdparty/touch/src/Decorator.js
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* @class Ext.Decorator
|
||||
* @extends Ext.Component
|
||||
*
|
||||
* In a few words, a Decorator is a Component that wraps around another Component. A typical example of a Decorator is a
|
||||
* {@link Ext.field.Field Field}. A form field is nothing more than a decorator around another component, and gives the
|
||||
* component a label, as well as extra styling to make it look good in a form.
|
||||
*
|
||||
* A Decorator can be thought of as a lightweight Container that has only one child item, and no layout overhead.
|
||||
* The look and feel of decorators can be styled purely in CSS.
|
||||
*
|
||||
* Another powerful feature that Decorator provides is config proxying. For example: all config items of a
|
||||
* {@link Ext.slider.Slider Slider} also exist in a {@link Ext.field.Slider Slider Field} for API convenience.
|
||||
* The {@link Ext.field.Slider Slider Field} simply proxies all corresponding getters and setters
|
||||
* to the actual {@link Ext.slider.Slider Slider} instance. Writing out all the setters and getters to do that is a tedious task
|
||||
* and a waste of code space. Instead, when you sub-class Ext.Decorator, all you need to do is to specify those config items
|
||||
* that you want to proxy to the Component using a special 'proxyConfig' class property. Here's how it may look like
|
||||
* in a Slider Field class:
|
||||
*
|
||||
* Ext.define('My.field.Slider', {
|
||||
* extend: 'Ext.Decorator',
|
||||
*
|
||||
* config: {
|
||||
* component: {
|
||||
* xtype: 'slider'
|
||||
* }
|
||||
* },
|
||||
*
|
||||
* proxyConfig: {
|
||||
* minValue: 0,
|
||||
* maxValue: 100,
|
||||
* increment: 1
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
* });
|
||||
*
|
||||
* Once `My.field.Slider` class is created, it will have all setters and getters methods for all items listed in `proxyConfig`
|
||||
* automatically generated. These methods all proxy to the same method names that exist within the Component instance.
|
||||
*/
|
||||
Ext.define('Ext.Decorator', {
|
||||
extend: 'Ext.Component',
|
||||
|
||||
isDecorator: true,
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Object} component The config object to factory the Component that this Decorator wraps around
|
||||
*/
|
||||
component: {}
|
||||
},
|
||||
|
||||
statics: {
|
||||
generateProxySetter: function(name) {
|
||||
return function(value) {
|
||||
var component = this.getComponent();
|
||||
component[name].call(component, value);
|
||||
|
||||
return this;
|
||||
}
|
||||
},
|
||||
generateProxyGetter: function(name) {
|
||||
return function() {
|
||||
var component = this.getComponent();
|
||||
return component[name].call(component);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onClassExtended: function(Class, members) {
|
||||
if (!members.hasOwnProperty('proxyConfig')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var ExtClass = Ext.Class,
|
||||
proxyConfig = members.proxyConfig,
|
||||
config = members.config;
|
||||
|
||||
members.config = (config) ? Ext.applyIf(config, proxyConfig) : proxyConfig;
|
||||
|
||||
var name, nameMap, setName, getName;
|
||||
|
||||
for (name in proxyConfig) {
|
||||
if (proxyConfig.hasOwnProperty(name)) {
|
||||
nameMap = ExtClass.getConfigNameMap(name);
|
||||
setName = nameMap.set;
|
||||
getName = nameMap.get;
|
||||
|
||||
members[setName] = this.generateProxySetter(setName);
|
||||
members[getName] = this.generateProxyGetter(getName);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
applyComponent: function(config) {
|
||||
return Ext.factory(config, Ext.Component);
|
||||
},
|
||||
|
||||
// @private
|
||||
updateComponent: function(newComponent, oldComponent) {
|
||||
if (oldComponent) {
|
||||
if (this.isRendered() && oldComponent.setRendered(false)) {
|
||||
oldComponent.fireAction('renderedchange', [this, oldComponent, false],
|
||||
'doUnsetComponent', this, { args: [oldComponent] });
|
||||
}
|
||||
else {
|
||||
this.doUnsetComponent(oldComponent);
|
||||
}
|
||||
}
|
||||
|
||||
if (newComponent) {
|
||||
if (this.isRendered() && newComponent.setRendered(true)) {
|
||||
newComponent.fireAction('renderedchange', [this, newComponent, true],
|
||||
'doSetComponent', this, { args: [newComponent] });
|
||||
}
|
||||
else {
|
||||
this.doSetComponent(newComponent);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
doUnsetComponent: function(component) {
|
||||
if (component.renderElement.dom) {
|
||||
component.setLayoutSizeFlags(0);
|
||||
this.innerElement.dom.removeChild(component.renderElement.dom);
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
doSetComponent: function(component) {
|
||||
if (component.renderElement.dom) {
|
||||
component.setLayoutSizeFlags(this.getSizeFlags());
|
||||
this.innerElement.dom.appendChild(component.renderElement.dom);
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
setRendered: function(rendered) {
|
||||
var component;
|
||||
|
||||
if (this.callParent(arguments)) {
|
||||
component = this.getComponent();
|
||||
|
||||
if (component) {
|
||||
component.setRendered(rendered);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
// @private
|
||||
setDisabled: function(disabled) {
|
||||
this.callParent(arguments);
|
||||
this.getComponent().setDisabled(disabled);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
Ext.destroy(this.getComponent());
|
||||
this.callParent();
|
||||
}
|
||||
});
|
||||
105
OfficeWeb/3rdparty/touch/src/Evented.js
vendored
Normal file
105
OfficeWeb/3rdparty/touch/src/Evented.js
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.Evented', {
|
||||
|
||||
alternateClassName: 'Ext.EventedBase',
|
||||
|
||||
mixins: ['Ext.mixin.Observable'],
|
||||
|
||||
statics: {
|
||||
generateSetter: function(nameMap) {
|
||||
var internalName = nameMap.internal,
|
||||
applyName = nameMap.apply,
|
||||
changeEventName = nameMap.changeEvent,
|
||||
doSetName = nameMap.doSet;
|
||||
|
||||
return function(value) {
|
||||
var initialized = this.initialized,
|
||||
oldValue = this[internalName],
|
||||
applier = this[applyName];
|
||||
|
||||
if (applier) {
|
||||
value = applier.call(this, value, oldValue);
|
||||
|
||||
if (typeof value == 'undefined') {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// The old value might have been changed at this point
|
||||
// (after the apply call chain) so it should be read again
|
||||
oldValue = this[internalName];
|
||||
|
||||
if (value !== oldValue) {
|
||||
if (initialized) {
|
||||
this.fireAction(changeEventName, [this, value, oldValue], this.doSet, this, {
|
||||
nameMap: nameMap
|
||||
});
|
||||
}
|
||||
else {
|
||||
this[internalName] = value;
|
||||
if (this[doSetName]) {
|
||||
this[doSetName].call(this, value, oldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
initialized: false,
|
||||
|
||||
constructor: function(config) {
|
||||
this.initialConfig = config;
|
||||
this.initialize();
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
this.initConfig(this.initialConfig);
|
||||
this.initialized = true;
|
||||
},
|
||||
|
||||
doSet: function(me, value, oldValue, options) {
|
||||
var nameMap = options.nameMap;
|
||||
|
||||
me[nameMap.internal] = value;
|
||||
if (me[nameMap.doSet]) {
|
||||
me[nameMap.doSet].call(this, value, oldValue);
|
||||
}
|
||||
},
|
||||
|
||||
onClassExtended: function(Class, data) {
|
||||
if (!data.hasOwnProperty('eventedConfig')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var ExtClass = Ext.Class,
|
||||
config = data.config,
|
||||
eventedConfig = data.eventedConfig,
|
||||
name, nameMap;
|
||||
|
||||
data.config = (config) ? Ext.applyIf(config, eventedConfig) : eventedConfig;
|
||||
|
||||
/*
|
||||
* These are generated setters for eventedConfig
|
||||
*
|
||||
* If the component is initialized, it invokes fireAction to fire the event as well,
|
||||
* which indicate something has changed. Otherwise, it just executes the action
|
||||
* (happens during initialization)
|
||||
*
|
||||
* This is helpful when we only want the event to be fired for subsequent changes.
|
||||
* Also it's a major performance improvement for instantiation when fired events
|
||||
* are mostly useless since there's no listeners
|
||||
*/
|
||||
for (name in eventedConfig) {
|
||||
if (eventedConfig.hasOwnProperty(name)) {
|
||||
nameMap = ExtClass.getConfigNameMap(name);
|
||||
|
||||
data[nameMap.set] = this.generateSetter(nameMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
234
OfficeWeb/3rdparty/touch/src/Img.js
vendored
Normal file
234
OfficeWeb/3rdparty/touch/src/Img.js
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* This is a simple way to add an image of any size to your application and have it participate in the layout system
|
||||
* like any other component. This component typically takes between 1 and 3 configurations - a {@link #src}, and
|
||||
* optionally a {@link #height} and a {@link #width}:
|
||||
*
|
||||
* @example miniphone
|
||||
* var img = Ext.create('Ext.Img', {
|
||||
* src: 'http://www.sencha.com/assets/images/sencha-avatar-64x64.png',
|
||||
* height: 64,
|
||||
* width: 64
|
||||
* });
|
||||
* Ext.Viewport.add(img);
|
||||
*
|
||||
* It's also easy to add an image into a panel or other container using its xtype:
|
||||
*
|
||||
* @example miniphone
|
||||
* Ext.create('Ext.Panel', {
|
||||
* fullscreen: true,
|
||||
* layout: 'hbox',
|
||||
* items: [
|
||||
* {
|
||||
* xtype: 'image',
|
||||
* src: 'http://www.sencha.com/assets/images/sencha-avatar-64x64.png',
|
||||
* flex: 1
|
||||
* },
|
||||
* {
|
||||
* xtype: 'panel',
|
||||
* flex: 2,
|
||||
* html: 'Sencha Inc.<br/>1700 Seaport Boulevard Suite 120, Redwood City, CA'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* Here we created a panel which contains an image (a profile picture in this case) and a text area to allow the user
|
||||
* to enter profile information about themselves. In this case we used an {@link Ext.layout.HBox hbox layout} and
|
||||
* flexed the image to take up one third of the width and the text area to take two thirds of the width. See the
|
||||
* {@link Ext.layout.HBox hbox docs} for more information on flexing items.
|
||||
*/
|
||||
Ext.define('Ext.Img', {
|
||||
extend: 'Ext.Component',
|
||||
xtype: ['image', 'img'],
|
||||
|
||||
/**
|
||||
* @event tap
|
||||
* Fires whenever the component is tapped
|
||||
* @param {Ext.Img} this The Image instance
|
||||
* @param {Ext.EventObject} e The event object
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event load
|
||||
* Fires when the image is loaded
|
||||
* @param {Ext.Img} this The Image instance
|
||||
* @param {Ext.EventObject} e The event object
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event error
|
||||
* Fires if an error occured when trying to load the image
|
||||
* @param {Ext.Img} this The Image instance
|
||||
* @param {Ext.EventObject} e The event object
|
||||
*/
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} src The source of this image
|
||||
* @accessor
|
||||
*/
|
||||
src: null,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls : Ext.baseCSSPrefix + 'img',
|
||||
|
||||
/**
|
||||
* @cfg {String} imageCls The CSS class to be used when {@link #mode} is not set to 'background'
|
||||
* @accessor
|
||||
*/
|
||||
imageCls : Ext.baseCSSPrefix + 'img-image',
|
||||
|
||||
/**
|
||||
* @cfg {String} backgroundCls The CSS class to be used when {@link #mode} is set to 'background'
|
||||
* @accessor
|
||||
*/
|
||||
backgroundCls : Ext.baseCSSPrefix + 'img-background',
|
||||
|
||||
/**
|
||||
* @cfg {String} mode If set to 'background', uses a background-image CSS property instead of an
|
||||
* `<img>` tag to display the image.
|
||||
*/
|
||||
mode: 'background'
|
||||
},
|
||||
|
||||
beforeInitialize: function() {
|
||||
var me = this;
|
||||
me.onLoad = Ext.Function.bind(me.onLoad, me);
|
||||
me.onError = Ext.Function.bind(me.onError, me);
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
var me = this;
|
||||
me.callParent();
|
||||
|
||||
me.relayEvents(me.renderElement, '*');
|
||||
|
||||
me.element.on({
|
||||
tap: 'onTap',
|
||||
scope: me
|
||||
});
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this.callParent();
|
||||
this.hiddenSrc = this.hiddenSrc || this.getSrc();
|
||||
this.setSrc(null);
|
||||
},
|
||||
|
||||
show: function() {
|
||||
this.callParent();
|
||||
if (this.hiddenSrc) {
|
||||
this.setSrc(this.hiddenSrc);
|
||||
delete this.hiddenSrc;
|
||||
}
|
||||
},
|
||||
|
||||
updateMode: function(mode) {
|
||||
var me = this,
|
||||
imageCls = me.getImageCls(),
|
||||
backgroundCls = me.getBackgroundCls();
|
||||
|
||||
if (mode === 'background') {
|
||||
if (me.imageElement) {
|
||||
me.imageElement.destroy();
|
||||
delete me.imageElement;
|
||||
me.updateSrc(me.getSrc());
|
||||
}
|
||||
|
||||
me.replaceCls(imageCls, backgroundCls);
|
||||
} else {
|
||||
me.imageElement = me.element.createChild({ tag: 'img' });
|
||||
|
||||
me.replaceCls(backgroundCls, imageCls);
|
||||
}
|
||||
},
|
||||
|
||||
updateImageCls : function (newCls, oldCls) {
|
||||
this.replaceCls(oldCls, newCls);
|
||||
},
|
||||
|
||||
updateBackgroundCls : function (newCls, oldCls) {
|
||||
this.replaceCls(oldCls, newCls);
|
||||
},
|
||||
|
||||
onTap: function(e) {
|
||||
this.fireEvent('tap', this, e);
|
||||
},
|
||||
|
||||
onAfterRender: function() {
|
||||
this.updateSrc(this.getSrc());
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateSrc: function(newSrc) {
|
||||
var me = this,
|
||||
dom;
|
||||
|
||||
if (me.getMode() === 'background') {
|
||||
dom = this.imageObject || new Image();
|
||||
}
|
||||
else {
|
||||
dom = me.imageElement.dom;
|
||||
}
|
||||
|
||||
this.imageObject = dom;
|
||||
|
||||
dom.setAttribute('src', Ext.isString(newSrc) ? newSrc : '');
|
||||
dom.addEventListener('load', me.onLoad, false);
|
||||
dom.addEventListener('error', me.onError, false);
|
||||
},
|
||||
|
||||
detachListeners: function() {
|
||||
var dom = this.imageObject;
|
||||
|
||||
if (dom) {
|
||||
dom.removeEventListener('load', this.onLoad, false);
|
||||
dom.removeEventListener('error', this.onError, false);
|
||||
}
|
||||
},
|
||||
|
||||
onLoad : function(e) {
|
||||
this.detachListeners();
|
||||
|
||||
if (this.getMode() === 'background') {
|
||||
this.element.dom.style.backgroundImage = 'url("' + this.imageObject.src + '")';
|
||||
}
|
||||
|
||||
this.fireEvent('load', this, e);
|
||||
},
|
||||
|
||||
onError : function(e) {
|
||||
this.detachListeners();
|
||||
this.fireEvent('error', this, e);
|
||||
},
|
||||
|
||||
doSetWidth: function(width) {
|
||||
var sizingElement = (this.getMode() === 'background') ? this.element : this.imageElement;
|
||||
|
||||
sizingElement.setWidth(width);
|
||||
|
||||
this.callParent(arguments);
|
||||
},
|
||||
|
||||
doSetHeight: function(height) {
|
||||
var sizingElement = (this.getMode() === 'background') ? this.element : this.imageElement;
|
||||
|
||||
sizingElement.setHeight(height);
|
||||
|
||||
this.callParent(arguments);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.detachListeners();
|
||||
|
||||
Ext.destroy(this.imageObject, this.imageElement);
|
||||
delete this.imageObject;
|
||||
delete this.imageElement;
|
||||
|
||||
this.callParent();
|
||||
}
|
||||
});
|
||||
14
OfficeWeb/3rdparty/touch/src/ItemCollection.js
vendored
Normal file
14
OfficeWeb/3rdparty/touch/src/ItemCollection.js
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.ItemCollection', {
|
||||
extend: 'Ext.util.MixedCollection',
|
||||
|
||||
getKey: function(item) {
|
||||
return item.getItemId();
|
||||
},
|
||||
|
||||
has: function(item) {
|
||||
return this.map.hasOwnProperty(item.getId());
|
||||
}
|
||||
});
|
||||
22
OfficeWeb/3rdparty/touch/src/Label.js
vendored
Normal file
22
OfficeWeb/3rdparty/touch/src/Label.js
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* A simple label component which allows you to insert content using {@link #html} configuration.
|
||||
*
|
||||
* @example miniphone
|
||||
* Ext.Viewport.add({
|
||||
* xtype: 'label',
|
||||
* html: 'My label!'
|
||||
* });
|
||||
*/
|
||||
Ext.define('Ext.Label', {
|
||||
extend: 'Ext.Component',
|
||||
xtype: 'label',
|
||||
|
||||
config: {
|
||||
baseCls: Ext.baseCSSPrefix + 'label'
|
||||
|
||||
/**
|
||||
* @cfg {String} html
|
||||
* The label of this component.
|
||||
*/
|
||||
}
|
||||
});
|
||||
179
OfficeWeb/3rdparty/touch/src/LoadMask.js
vendored
Normal file
179
OfficeWeb/3rdparty/touch/src/LoadMask.js
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* A simple class used to mask any {@link Ext.Container}.
|
||||
*
|
||||
* This should rarely be used directly, instead look at the {@link Ext.Container#masked} configuration.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* @example miniphone
|
||||
* Ext.Viewport.add({
|
||||
* masked: {
|
||||
* xtype: 'loadmask'
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* You can customize the loading {@link #message} and whether or not you want to show the {@link #indicator}:
|
||||
*
|
||||
* @example miniphone
|
||||
* Ext.Viewport.add({
|
||||
* masked: {
|
||||
* xtype: 'loadmask',
|
||||
* message: 'A message..',
|
||||
* indicator: false
|
||||
* }
|
||||
* });
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.LoadMask', {
|
||||
extend: 'Ext.Mask',
|
||||
xtype: 'loadmask',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} message
|
||||
* The text to display in a centered loading message box.
|
||||
* @accessor
|
||||
*/
|
||||
message: 'Loading...',
|
||||
|
||||
/**
|
||||
* @cfg {String} messageCls
|
||||
* The CSS class to apply to the loading message element.
|
||||
* @accessor
|
||||
*/
|
||||
messageCls: Ext.baseCSSPrefix + 'mask-message',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} indicator
|
||||
* True to show the loading indicator on this {@link Ext.LoadMask}.
|
||||
* @accessor
|
||||
*/
|
||||
indicator: true
|
||||
},
|
||||
|
||||
getTemplate: function() {
|
||||
var prefix = Ext.baseCSSPrefix;
|
||||
|
||||
return [
|
||||
{
|
||||
//it needs an inner so it can be centered within the mask, and have a background
|
||||
reference: 'innerElement',
|
||||
cls: prefix + 'mask-inner',
|
||||
children: [
|
||||
//the elements required for the CSS loading {@link #indicator}
|
||||
{
|
||||
reference: 'indicatorElement',
|
||||
cls: prefix + 'loading-spinner-outer',
|
||||
children: [
|
||||
{
|
||||
cls: prefix + 'loading-spinner',
|
||||
children: [
|
||||
{ tag: 'span', cls: prefix + 'loading-top' },
|
||||
{ tag: 'span', cls: prefix + 'loading-right' },
|
||||
{ tag: 'span', cls: prefix + 'loading-bottom' },
|
||||
{ tag: 'span', cls: prefix + 'loading-left' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
//the element used to display the {@link #message}
|
||||
{
|
||||
reference: 'messageElement'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the message element with the new value of the {@link #message} configuration
|
||||
* @private
|
||||
*/
|
||||
updateMessage: function(newMessage) {
|
||||
var cls = Ext.baseCSSPrefix + 'has-message';
|
||||
|
||||
if (newMessage) {
|
||||
this.addCls(cls);
|
||||
} else {
|
||||
this.removeCls(cls);
|
||||
}
|
||||
|
||||
this.messageElement.setHtml(newMessage);
|
||||
},
|
||||
|
||||
/**
|
||||
* Replaces the cls of the message element with the value of the {@link #messageCls} configuration.
|
||||
* @private
|
||||
*/
|
||||
updateMessageCls: function(newMessageCls, oldMessageCls) {
|
||||
this.messageElement.replaceCls(oldMessageCls, newMessageCls);
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows or hides the loading indicator when the {@link #indicator} configuration is changed.
|
||||
* @private
|
||||
*/
|
||||
updateIndicator: function(newIndicator) {
|
||||
this[newIndicator ? 'removeCls' : 'addCls'](Ext.baseCSSPrefix + 'indicator-hidden');
|
||||
}
|
||||
|
||||
}, function() {
|
||||
//<deprecated product=touch since=2.0>
|
||||
this.override({
|
||||
constructor: function(config, other) {
|
||||
if (typeof other !== "undefined") {
|
||||
config = other;
|
||||
|
||||
Ext.Logger.deprecate("You no longer need to pass an element to create a Ext.LoadMask. " +
|
||||
"It is a component and can be shown using the Ext.Container.masked configuration.", this);
|
||||
}
|
||||
|
||||
if (config) {
|
||||
/**
|
||||
* @member Ext.LoadMask
|
||||
* @cfg {String} msg The message to display on the {@link Ext.LoadMask}
|
||||
* @deprecated 2.0.0 Please use the {@link #message} configuration
|
||||
*/
|
||||
if (config.hasOwnProperty('msg')) {
|
||||
config.message = config.msg;
|
||||
Ext.Logger.deprecate("'msg' config is deprecated, please use 'message' config instead", this);
|
||||
delete config.msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @member Ext.LoadMask
|
||||
* @cfg {String} msgCls The message cls used on the element which displays the {@link #message}
|
||||
* @deprecated 2.0.0 Please use the {@link #messageCls} configuration
|
||||
*/
|
||||
if (config.hasOwnProperty('msgCls')) {
|
||||
config.messageCls = config.msgCls;
|
||||
Ext.Logger.deprecate("'msgCls' config is deprecated, please use 'messageCls' config instead", this);
|
||||
delete config.msgCls;
|
||||
}
|
||||
|
||||
/**
|
||||
* @cfg {Ext.data.Store} store
|
||||
* Optional Store to which the mask is bound. The mask is displayed when a load request is issued, and
|
||||
* hidden on either load success, or load fail.
|
||||
* @removed 2.0.0 You can no longer bind a store to a {@link Ext.LoadMask}
|
||||
*/
|
||||
if (config.hasOwnProperty('store')) {
|
||||
Ext.Logger.deprecate("'store' config has been removed. You can no longer bind a store to a Ext.LoadMask", this);
|
||||
delete config.store;
|
||||
}
|
||||
}
|
||||
|
||||
this.callParent([config]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the data store bound to this LoadMask.
|
||||
* @param {Ext.data.Store} store The store to bind to this LoadMask
|
||||
* @removed 2.0.0 You can no longer bind a store to a {@link Ext.LoadMask}.
|
||||
*/
|
||||
bindStore: function() {
|
||||
Ext.Logger.deprecate("You can no longer bind a store to a Ext.LoadMask", this);
|
||||
}
|
||||
});
|
||||
//</deprecated>
|
||||
});
|
||||
388
OfficeWeb/3rdparty/touch/src/Map.js
vendored
Normal file
388
OfficeWeb/3rdparty/touch/src/Map.js
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
/**
|
||||
* Wraps a Google Map in an Ext.Component using the [Google Maps API](http://code.google.com/apis/maps/documentation/v3/introduction.html).
|
||||
*
|
||||
* To use this component you must include an additional JavaScript file from Google:
|
||||
*
|
||||
* <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* Ext.Viewport.add({
|
||||
* xtype: 'map',
|
||||
* useCurrentLocation: true
|
||||
* });
|
||||
*
|
||||
* @aside example maps
|
||||
*/
|
||||
Ext.define('Ext.Map', {
|
||||
extend: 'Ext.Container',
|
||||
xtype : 'map',
|
||||
requires: ['Ext.util.Geolocation'],
|
||||
|
||||
isMap: true,
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @event maprender
|
||||
* Fired when Map initially rendered.
|
||||
* @param {Ext.Map} this
|
||||
* @param {google.maps.Map} map The rendered google.map.Map instance
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event centerchange
|
||||
* Fired when map is panned around.
|
||||
* @param {Ext.Map} this
|
||||
* @param {google.maps.Map} map The rendered google.map.Map instance
|
||||
* @param {google.maps.LatLng} center The current LatLng center of the map
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event typechange
|
||||
* Fired when display type of the map changes.
|
||||
* @param {Ext.Map} this
|
||||
* @param {google.maps.Map} map The rendered google.map.Map instance
|
||||
* @param {Number} mapType The current display type of the map
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event zoomchange
|
||||
* Fired when map is zoomed.
|
||||
* @param {Ext.Map} this
|
||||
* @param {google.maps.Map} map The rendered google.map.Map instance
|
||||
* @param {Number} zoomLevel The current zoom level of the map
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {String} baseCls
|
||||
* The base CSS class to apply to the Map's element
|
||||
* @accessor
|
||||
*/
|
||||
baseCls: Ext.baseCSSPrefix + 'map',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean/Ext.util.Geolocation} useCurrentLocation
|
||||
* Pass in true to center the map based on the geolocation coordinates or pass a
|
||||
* {@link Ext.util.Geolocation GeoLocation} config to have more control over your GeoLocation options
|
||||
* @accessor
|
||||
*/
|
||||
useCurrentLocation: false,
|
||||
|
||||
/**
|
||||
* @cfg {google.maps.Map} map
|
||||
* The wrapped map.
|
||||
* @accessor
|
||||
*/
|
||||
map: null,
|
||||
|
||||
/**
|
||||
* @cfg {Ext.util.Geolocation} geo
|
||||
* Geolocation provider for the map.
|
||||
* @accessor
|
||||
*/
|
||||
geo: null,
|
||||
|
||||
/**
|
||||
* @cfg {Object} mapOptions
|
||||
* MapOptions as specified by the Google Documentation:
|
||||
* [http://code.google.com/apis/maps/documentation/v3/reference.html](http://code.google.com/apis/maps/documentation/v3/reference.html)
|
||||
* @accessor
|
||||
*/
|
||||
mapOptions: {}
|
||||
},
|
||||
|
||||
constructor: function() {
|
||||
this.callParent(arguments);
|
||||
// this.element.setVisibilityMode(Ext.Element.OFFSETS);
|
||||
|
||||
if (!(window.google || {}).maps) {
|
||||
this.setHtml('Google Maps API is required');
|
||||
}
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
this.callParent();
|
||||
this.on({
|
||||
painted: 'doResize',
|
||||
scope: this
|
||||
});
|
||||
this.innerElement.on('touchstart', 'onTouchStart', this);
|
||||
},
|
||||
|
||||
getElementConfig: function() {
|
||||
return {
|
||||
reference: 'element',
|
||||
className: 'x-container',
|
||||
children: [{
|
||||
reference: 'innerElement',
|
||||
className: 'x-inner',
|
||||
children: [{
|
||||
reference: 'mapContainer',
|
||||
className: Ext.baseCSSPrefix + 'map-container'
|
||||
}]
|
||||
}]
|
||||
};
|
||||
},
|
||||
|
||||
onTouchStart: function(e) {
|
||||
e.makeUnpreventable();
|
||||
},
|
||||
|
||||
applyMapOptions: function(options) {
|
||||
return Ext.merge({}, this.options, options);
|
||||
},
|
||||
|
||||
updateMapOptions: function(newOptions) {
|
||||
var me = this,
|
||||
gm = (window.google || {}).maps,
|
||||
map = this.getMap();
|
||||
|
||||
if (gm && map) {
|
||||
map.setOptions(newOptions);
|
||||
}
|
||||
if (newOptions.center && !me.isPainted()) {
|
||||
me.un('painted', 'setMapCenter', this);
|
||||
me.on('painted', 'setMapCenter', this, { delay: 150, single: true, args: [newOptions.center] });
|
||||
}
|
||||
},
|
||||
|
||||
getMapOptions: function() {
|
||||
return Ext.merge({}, this.options || this.getInitialConfig('mapOptions'));
|
||||
},
|
||||
|
||||
updateUseCurrentLocation: function(useCurrentLocation) {
|
||||
this.setGeo(useCurrentLocation);
|
||||
if (!useCurrentLocation) {
|
||||
this.renderMap();
|
||||
}
|
||||
},
|
||||
|
||||
applyGeo: function(config) {
|
||||
return Ext.factory(config, Ext.util.Geolocation, this.getGeo());
|
||||
},
|
||||
|
||||
updateGeo: function(newGeo, oldGeo) {
|
||||
var events = {
|
||||
locationupdate : 'onGeoUpdate',
|
||||
locationerror : 'onGeoError',
|
||||
scope : this
|
||||
};
|
||||
|
||||
if (oldGeo) {
|
||||
oldGeo.un(events);
|
||||
}
|
||||
|
||||
if (newGeo) {
|
||||
newGeo.on(events);
|
||||
newGeo.updateLocation();
|
||||
}
|
||||
},
|
||||
|
||||
doResize: function() {
|
||||
var gm = (window.google || {}).maps,
|
||||
map = this.getMap();
|
||||
|
||||
if (gm && map) {
|
||||
gm.event.trigger(map, "resize");
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
renderMap: function() {
|
||||
var me = this,
|
||||
gm = (window.google || {}).maps,
|
||||
element = me.mapContainer,
|
||||
mapOptions = me.getMapOptions(),
|
||||
map = me.getMap(),
|
||||
event;
|
||||
|
||||
if (gm) {
|
||||
if (Ext.os.is.iPad) {
|
||||
Ext.merge({
|
||||
navigationControlOptions: {
|
||||
style: gm.NavigationControlStyle.ZOOM_PAN
|
||||
}
|
||||
}, mapOptions);
|
||||
}
|
||||
|
||||
mapOptions = Ext.merge({
|
||||
zoom: 12,
|
||||
mapTypeId: gm.MapTypeId.ROADMAP
|
||||
}, mapOptions);
|
||||
|
||||
// This is done separately from the above merge so we don't have to instantiate
|
||||
// a new LatLng if we don't need to
|
||||
if (!mapOptions.hasOwnProperty('center')) {
|
||||
mapOptions.center = new gm.LatLng(37.381592, -122.135672); // Palo Alto
|
||||
}
|
||||
|
||||
if (element.dom.firstChild) {
|
||||
Ext.fly(element.dom.firstChild).destroy();
|
||||
}
|
||||
|
||||
if (map) {
|
||||
gm.event.clearInstanceListeners(map);
|
||||
}
|
||||
|
||||
me.setMap(new gm.Map(element.dom, mapOptions));
|
||||
map = me.getMap();
|
||||
|
||||
//Track zoomLevel and mapType changes
|
||||
event = gm.event;
|
||||
event.addListener(map, 'zoom_changed', Ext.bind(me.onZoomChange, me));
|
||||
event.addListener(map, 'maptypeid_changed', Ext.bind(me.onTypeChange, me));
|
||||
event.addListener(map, 'center_changed', Ext.bind(me.onCenterChange, me));
|
||||
|
||||
me.fireEvent('maprender', me, map);
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
onGeoUpdate: function(geo) {
|
||||
if (geo) {
|
||||
this.setMapCenter(new google.maps.LatLng(geo.getLatitude(), geo.getLongitude()));
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
onGeoError: Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* Moves the map center to the designated coordinates hash of the form:
|
||||
*
|
||||
* { latitude: 37.381592, longitude: -122.135672 }
|
||||
*
|
||||
* or a google.maps.LatLng object representing to the target location.
|
||||
*
|
||||
* @param {Object/google.maps.LatLng} coordinates Object representing the desired Latitude and
|
||||
* longitude upon which to center the map.
|
||||
*/
|
||||
setMapCenter: function(coordinates) {
|
||||
var me = this,
|
||||
map = me.getMap(),
|
||||
gm = (window.google || {}).maps;
|
||||
|
||||
if (gm) {
|
||||
if (!me.isPainted()) {
|
||||
me.un('painted', 'setMapCenter', this);
|
||||
me.on('painted', 'setMapCenter', this, { delay: 150, single: true, args: [coordinates] });
|
||||
return;
|
||||
}
|
||||
coordinates = coordinates || new gm.LatLng(37.381592, -122.135672);
|
||||
|
||||
if (coordinates && !(coordinates instanceof gm.LatLng) && 'longitude' in coordinates) {
|
||||
coordinates = new gm.LatLng(coordinates.latitude, coordinates.longitude);
|
||||
}
|
||||
|
||||
if (!map) {
|
||||
me.renderMap();
|
||||
map = me.getMap();
|
||||
}
|
||||
|
||||
if (map && coordinates instanceof gm.LatLng) {
|
||||
map.panTo(coordinates);
|
||||
}
|
||||
else {
|
||||
this.options = Ext.apply(this.getMapOptions(), {
|
||||
center: coordinates
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
onZoomChange : function() {
|
||||
var mapOptions = this.getMapOptions(),
|
||||
map = this.getMap(),
|
||||
zoom;
|
||||
|
||||
zoom = (map && map.getZoom) ? map.getZoom() : mapOptions.zoom || 10;
|
||||
|
||||
this.options = Ext.apply(mapOptions, {
|
||||
zoom: zoom
|
||||
});
|
||||
|
||||
this.fireEvent('zoomchange', this, map, zoom);
|
||||
},
|
||||
|
||||
// @private
|
||||
onTypeChange : function() {
|
||||
var mapOptions = this.getMapOptions(),
|
||||
map = this.getMap(),
|
||||
mapTypeId;
|
||||
|
||||
mapTypeId = (map && map.getMapTypeId) ? map.getMapTypeId() : mapOptions.mapTypeId;
|
||||
|
||||
this.options = Ext.apply(mapOptions, {
|
||||
mapTypeId: mapTypeId
|
||||
});
|
||||
|
||||
this.fireEvent('typechange', this, map, mapTypeId);
|
||||
},
|
||||
|
||||
// @private
|
||||
onCenterChange: function() {
|
||||
var mapOptions = this.getMapOptions(),
|
||||
map = this.getMap(),
|
||||
center;
|
||||
|
||||
center = (map && map.getCenter) ? map.getCenter() : mapOptions.center;
|
||||
|
||||
this.options = Ext.apply(mapOptions, {
|
||||
center: center
|
||||
});
|
||||
|
||||
this.fireEvent('centerchange', this, map, center);
|
||||
|
||||
},
|
||||
|
||||
// @private
|
||||
destroy: function() {
|
||||
Ext.destroy(this.getGeo());
|
||||
var map = this.getMap();
|
||||
|
||||
if (map && (window.google || {}).maps) {
|
||||
google.maps.event.clearInstanceListeners(map);
|
||||
}
|
||||
|
||||
this.callParent();
|
||||
}
|
||||
}, function() {
|
||||
//<deprecated product=touch since=2.0>
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} maskMap
|
||||
* Masks the map
|
||||
* @removed 2.0.0 Please mask this components container instead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {String} maskMapCls
|
||||
* CSS class to add to the map when maskMap is set to true.
|
||||
* @removed 2.0.0 Please mask this components container instead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @method getState
|
||||
* Returns the state of the Map.
|
||||
* @deprecated 2.0.0 Please use {@link #getMapOptions} instead.
|
||||
* @return {Object} mapOptions
|
||||
*/
|
||||
Ext.deprecateClassMethod(this, 'getState', 'getMapOptions');
|
||||
|
||||
/**
|
||||
* @method update
|
||||
* Moves the map center to the designated coordinates hash of the form:
|
||||
*
|
||||
* { latitude: 37.381592, longitude: -122.135672 }
|
||||
*
|
||||
* or a google.maps.LatLng object representing to the target location.
|
||||
*
|
||||
* @deprecated 2.0.0 Please use the {@link #setMapCenter}
|
||||
* @param {Object/google.maps.LatLng} coordinates Object representing the desired Latitude and
|
||||
* longitude upon which to center the map.
|
||||
*/
|
||||
Ext.deprecateClassMethod(this, 'update', 'setMapCenter');
|
||||
|
||||
//</deprecated>
|
||||
});
|
||||
91
OfficeWeb/3rdparty/touch/src/Mask.js
vendored
Normal file
91
OfficeWeb/3rdparty/touch/src/Mask.js
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* A simple class used to mask any {@link Ext.Container}.
|
||||
*
|
||||
* This should rarely be used directly, instead look at the {@link Ext.Container#masked} configuration.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* @example miniphone
|
||||
* // Create our container
|
||||
* var container = Ext.create('Ext.Container', {
|
||||
* html: 'My container!'
|
||||
* });
|
||||
*
|
||||
* // Add the container to the Viewport
|
||||
* Ext.Viewport.add(container);
|
||||
*
|
||||
* // Mask the container
|
||||
* container.setMasked(true);
|
||||
*/
|
||||
Ext.define('Ext.Mask', {
|
||||
extend: 'Ext.Component',
|
||||
xtype: 'mask',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: Ext.baseCSSPrefix + 'mask',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} transparent True to make this mask transparent.
|
||||
*/
|
||||
transparent: false,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @hide
|
||||
*/
|
||||
top: 0,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @hide
|
||||
*/
|
||||
left: 0,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @hide
|
||||
*/
|
||||
right: 0,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @hide
|
||||
*/
|
||||
bottom: 0
|
||||
},
|
||||
|
||||
/**
|
||||
* @event tap
|
||||
* A tap event fired when a user taps on this mask
|
||||
* @param {Ext.Mask} this The mask instance
|
||||
* @param {Ext.EventObject} e The event object
|
||||
*/
|
||||
initialize: function() {
|
||||
this.callSuper();
|
||||
|
||||
this.element.on('*', 'onEvent', this);
|
||||
},
|
||||
|
||||
onEvent: function(e) {
|
||||
var controller = arguments[arguments.length - 1];
|
||||
|
||||
if (controller.info.eventName === 'tap') {
|
||||
this.fireEvent('tap', this, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e && e.stopEvent) {
|
||||
e.stopEvent();
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
updateTransparent: function(newTransparent) {
|
||||
this[newTransparent ? 'addCls' : 'removeCls'](this.getBaseCls() + '-transparent');
|
||||
}
|
||||
});
|
||||
347
OfficeWeb/3rdparty/touch/src/Media.js
vendored
Normal file
347
OfficeWeb/3rdparty/touch/src/Media.js
vendored
Normal file
@@ -0,0 +1,347 @@
|
||||
/**
|
||||
* Provides a base class for audio/visual controls. Should not be used directly.
|
||||
*
|
||||
* Please see the {@link Ext.Audio} and {@link Ext.Video} classes for more information.
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.Media', {
|
||||
extend: 'Ext.Component',
|
||||
xtype: 'media',
|
||||
|
||||
/**
|
||||
* @event play
|
||||
* Fires whenever the media is played.
|
||||
* @param {Ext.Media} this
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event pause
|
||||
* Fires whenever the media is paused.
|
||||
* @param {Ext.Media} this
|
||||
* @param {Number} time The time at which the media was paused at in seconds.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event ended
|
||||
* Fires whenever the media playback has ended.
|
||||
* @param {Ext.Media} this
|
||||
* @param {Number} time The time at which the media ended at in seconds.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event stop
|
||||
* Fires whenever the media is stopped.
|
||||
* The `pause` event will also fire after the `stop` event if the media is currently playing.
|
||||
* The `timeupdate` event will also fire after the `stop` event regardless of playing status.
|
||||
* @param {Ext.Media} this
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event volumechange
|
||||
* Fires whenever the volume is changed.
|
||||
* @param {Ext.Media} this
|
||||
* @param {Number} volume The volume level from 0 to 1.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event mutedchange
|
||||
* Fires whenever the muted status is changed.
|
||||
* The volumechange event will also fire after the `mutedchange` event fires.
|
||||
* @param {Ext.Media} this
|
||||
* @param {Boolean} muted The muted status.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event timeupdate
|
||||
* Fires when the media is playing every 15 to 250ms.
|
||||
* @param {Ext.Media} this
|
||||
* @param {Number} time The current time in seconds.
|
||||
*/
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} url
|
||||
* Location of the media to play.
|
||||
* @accessor
|
||||
*/
|
||||
url: '',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} enableControls
|
||||
* Set this to `false` to turn off the native media controls.
|
||||
* Defaults to `false` when you are on Android, as it doesn't support controls.
|
||||
* @accessor
|
||||
*/
|
||||
enableControls: Ext.os.is.Android ? false : true,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} autoResume
|
||||
* Will automatically start playing the media when the container is activated.
|
||||
* @accessor
|
||||
*/
|
||||
autoResume: false,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} autoPause
|
||||
* Will automatically pause the media when the container is deactivated.
|
||||
* @accessor
|
||||
*/
|
||||
autoPause: true,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} preload
|
||||
* Will begin preloading the media immediately.
|
||||
* @accessor
|
||||
*/
|
||||
preload: true,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} loop
|
||||
* Will loop the media forever.
|
||||
* @accessor
|
||||
*/
|
||||
loop: false,
|
||||
|
||||
/**
|
||||
* @cfg {Ext.Element} media
|
||||
* A reference to the underlying audio/video element.
|
||||
* @accessor
|
||||
*/
|
||||
media: null,
|
||||
|
||||
/**
|
||||
* @cfg {Number} volume
|
||||
* The volume of the media from 0.0 to 1.0.
|
||||
* @accessor
|
||||
*/
|
||||
volume: 1,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} muted
|
||||
* Whether or not the media is muted. This will also set the volume to zero.
|
||||
* @accessor
|
||||
*/
|
||||
muted: false
|
||||
},
|
||||
|
||||
constructor: function() {
|
||||
this.mediaEvents = {};
|
||||
this.callSuper(arguments);
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
var me = this;
|
||||
me.callParent();
|
||||
|
||||
me.on({
|
||||
scope: me,
|
||||
|
||||
activate : me.onActivate,
|
||||
deactivate: me.onDeactivate
|
||||
});
|
||||
|
||||
me.addMediaListener({
|
||||
canplay: 'onCanPlay',
|
||||
play: 'onPlay',
|
||||
pause: 'onPause',
|
||||
ended: 'onEnd',
|
||||
volumechange: 'onVolumeChange',
|
||||
timeupdate: 'onTimeUpdate'
|
||||
});
|
||||
},
|
||||
|
||||
addMediaListener: function(event, fn) {
|
||||
var me = this,
|
||||
dom = me.media.dom,
|
||||
bind = Ext.Function.bind;
|
||||
|
||||
Ext.Object.each(event, function(e, fn) {
|
||||
fn = bind(me[fn], me);
|
||||
me.mediaEvents[e] = fn;
|
||||
dom.addEventListener(e, fn);
|
||||
});
|
||||
},
|
||||
|
||||
onPlay: function() {
|
||||
this.fireEvent('play', this);
|
||||
},
|
||||
|
||||
onCanPlay: function() {
|
||||
this.fireEvent('canplay', this);
|
||||
},
|
||||
|
||||
onPause: function() {
|
||||
this.fireEvent('pause', this, this.getCurrentTime());
|
||||
},
|
||||
|
||||
onEnd: function() {
|
||||
this.fireEvent('ended', this, this.getCurrentTime());
|
||||
},
|
||||
|
||||
onVolumeChange: function() {
|
||||
this.fireEvent('volumechange', this, this.media.dom.volume);
|
||||
},
|
||||
|
||||
onTimeUpdate: function() {
|
||||
this.fireEvent('timeupdate', this, this.getCurrentTime());
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns if the media is currently playing.
|
||||
* @return {Boolean} playing `true` if the media is playing.
|
||||
*/
|
||||
isPlaying: function() {
|
||||
return !Boolean(this.media.dom.paused);
|
||||
},
|
||||
|
||||
// @private
|
||||
onActivate: function() {
|
||||
var me = this;
|
||||
|
||||
if (me.getAutoResume() && !me.isPlaying()) {
|
||||
me.play();
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
onDeactivate: function() {
|
||||
var me = this;
|
||||
|
||||
if (me.getAutoPause() && me.isPlaying()) {
|
||||
me.pause();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the URL of the media element. If the media element already exists, it is update the src attribute of the
|
||||
* element. If it is currently playing, it will start the new video.
|
||||
*/
|
||||
updateUrl: function(newUrl) {
|
||||
var dom = this.media.dom;
|
||||
|
||||
//when changing the src, we must call load:
|
||||
//http://developer.apple.com/library/safari/#documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/ControllingMediaWithJavaScript/ControllingMediaWithJavaScript.html
|
||||
|
||||
dom.src = newUrl;
|
||||
|
||||
if ('load' in dom) {
|
||||
dom.load();
|
||||
}
|
||||
|
||||
if (this.isPlaying()) {
|
||||
this.play();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the controls of the video element.
|
||||
*/
|
||||
updateEnableControls: function(enableControls) {
|
||||
this.media.dom.controls = enableControls ? 'controls' : false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the loop setting of the media element.
|
||||
*/
|
||||
updateLoop: function(loop) {
|
||||
this.media.dom.loop = loop ? 'loop' : false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts or resumes media playback.
|
||||
*/
|
||||
play: function() {
|
||||
var dom = this.media.dom;
|
||||
|
||||
if ('play' in dom) {
|
||||
dom.play();
|
||||
setTimeout(function() {
|
||||
dom.play();
|
||||
}, 10);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Pauses media playback.
|
||||
*/
|
||||
pause: function() {
|
||||
var dom = this.media.dom;
|
||||
|
||||
if ('pause' in dom) {
|
||||
dom.pause();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles the media playback state.
|
||||
*/
|
||||
toggle: function() {
|
||||
if (this.isPlaying()) {
|
||||
this.pause();
|
||||
} else {
|
||||
this.play();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Stops media playback and returns to the beginning.
|
||||
*/
|
||||
stop: function() {
|
||||
var me = this;
|
||||
|
||||
me.setCurrentTime(0);
|
||||
me.fireEvent('stop', me);
|
||||
me.pause();
|
||||
},
|
||||
|
||||
//@private
|
||||
updateVolume: function(volume) {
|
||||
this.media.dom.volume = volume;
|
||||
},
|
||||
|
||||
//@private
|
||||
updateMuted: function(muted) {
|
||||
this.fireEvent('mutedchange', this, muted);
|
||||
|
||||
this.media.dom.muted = muted;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the current time of the media, in seconds.
|
||||
* @return {Number}
|
||||
*/
|
||||
getCurrentTime: function() {
|
||||
return this.media.dom.currentTime;
|
||||
},
|
||||
|
||||
/*
|
||||
* Set the current time of the media.
|
||||
* @param {Number} time The time, in seconds.
|
||||
* @return {Number}
|
||||
*/
|
||||
setCurrentTime: function(time) {
|
||||
this.media.dom.currentTime = time;
|
||||
|
||||
return time;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the duration of the media, in seconds.
|
||||
* @return {Number}
|
||||
*/
|
||||
getDuration: function() {
|
||||
return this.media.dom.duration;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
var me = this,
|
||||
dom = me.media.dom,
|
||||
mediaEvents = me.mediaEvents;
|
||||
|
||||
Ext.Object.each(mediaEvents, function(event, fn) {
|
||||
dom.removeEventListener(event, fn);
|
||||
});
|
||||
|
||||
this.callSuper();
|
||||
}
|
||||
});
|
||||
741
OfficeWeb/3rdparty/touch/src/MessageBox.js
vendored
Normal file
741
OfficeWeb/3rdparty/touch/src/MessageBox.js
vendored
Normal file
@@ -0,0 +1,741 @@
|
||||
/**
|
||||
* Utility class for generating different styles of message boxes. The framework provides a global singleton
|
||||
* {@link Ext.Msg} for common usage which you should use in most cases.
|
||||
*
|
||||
* If you want to use {@link Ext.MessageBox} directly, just think of it as a modal {@link Ext.Container}.
|
||||
*
|
||||
* Note that the MessageBox is asynchronous. Unlike a regular JavaScript `alert` (which will halt browser execution),
|
||||
* showing a MessageBox will not cause the code to stop. For this reason, if you have code that should only run _after_
|
||||
* some user feedback from the MessageBox, you must use a callback function (see the `fn` configuration option parameter
|
||||
* for the {@link #method-show show} method for more details).
|
||||
*
|
||||
* @example preview
|
||||
* Ext.Msg.alert('Title', 'The quick brown fox jumped over the lazy dog.', Ext.emptyFn);
|
||||
*
|
||||
* Checkout {@link Ext.Msg} for more examples.
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.MessageBox', {
|
||||
extend : 'Ext.Sheet',
|
||||
requires: [
|
||||
'Ext.Toolbar',
|
||||
'Ext.field.Text',
|
||||
'Ext.field.TextArea'
|
||||
],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
ui: 'dark',
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: Ext.baseCSSPrefix + 'msgbox',
|
||||
|
||||
/**
|
||||
* @cfg {String} iconCls
|
||||
* CSS class for the icon. The icon should be 40px x 40px.
|
||||
* @accessor
|
||||
*/
|
||||
iconCls: null,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
showAnimation: {
|
||||
type: 'popIn',
|
||||
duration: 250,
|
||||
easing: 'ease-out'
|
||||
},
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
hideAnimation: {
|
||||
type: 'popOut',
|
||||
duration: 250,
|
||||
easing: 'ease-out'
|
||||
},
|
||||
|
||||
/**
|
||||
* Override the default `zIndex` so it is normally always above floating components.
|
||||
*/
|
||||
zIndex: 999,
|
||||
|
||||
/**
|
||||
* @cfg {Number} defaultTextHeight
|
||||
* The default height in pixels of the message box's multiline textarea if displayed.
|
||||
* @accessor
|
||||
*/
|
||||
defaultTextHeight: 75,
|
||||
|
||||
/**
|
||||
* @cfg {String} title
|
||||
* The title of this {@link Ext.MessageBox}.
|
||||
* @accessor
|
||||
*/
|
||||
title: null,
|
||||
|
||||
/**
|
||||
* @cfg {Array/Object} buttons
|
||||
* An array of buttons, or an object of a button to be displayed in the toolbar of this {@link Ext.MessageBox}.
|
||||
*/
|
||||
buttons: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} message
|
||||
* The message to be displayed in the {@link Ext.MessageBox}.
|
||||
* @accessor
|
||||
*/
|
||||
message: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} msg
|
||||
* The message to be displayed in the {@link Ext.MessageBox}.
|
||||
* @removed 2.0.0 Please use {@link #message} instead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {Object} prompt
|
||||
* The configuration to be passed if you want an {@link Ext.field.Text} or {@link Ext.field.TextArea} field
|
||||
* in your {@link Ext.MessageBox}.
|
||||
*
|
||||
* Pass an object with the property `multiLine` with a value of `true`, if you want the prompt to use a TextArea.
|
||||
*
|
||||
* Alternatively, you can just pass in an object which has an xtype/xclass of another component.
|
||||
*
|
||||
* prompt: {
|
||||
* xtype: 'textareafield',
|
||||
* value: 'test'
|
||||
* }
|
||||
*
|
||||
* @accessor
|
||||
*/
|
||||
prompt: null,
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
modal: true,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
layout: {
|
||||
type: 'vbox',
|
||||
pack: 'center'
|
||||
}
|
||||
},
|
||||
|
||||
statics: {
|
||||
OK : {text: 'OK', itemId: 'ok', ui: 'action'},
|
||||
YES : {text: 'Yes', itemId: 'yes', ui: 'action'},
|
||||
NO : {text: 'No', itemId: 'no'},
|
||||
CANCEL: {text: 'Cancel', itemId: 'cancel'},
|
||||
|
||||
INFO : Ext.baseCSSPrefix + 'msgbox-info',
|
||||
WARNING : Ext.baseCSSPrefix + 'msgbox-warning',
|
||||
QUESTION: Ext.baseCSSPrefix + 'msgbox-question',
|
||||
ERROR : Ext.baseCSSPrefix + 'msgbox-error',
|
||||
|
||||
OKCANCEL: [
|
||||
{text: 'Cancel', itemId: 'cancel'},
|
||||
{text: 'OK', itemId: 'ok', ui : 'action'}
|
||||
],
|
||||
YESNOCANCEL: [
|
||||
{text: 'Cancel', itemId: 'cancel'},
|
||||
{text: 'No', itemId: 'no'},
|
||||
{text: 'Yes', itemId: 'yes', ui: 'action'}
|
||||
],
|
||||
YESNO: [
|
||||
{text: 'No', itemId: 'no'},
|
||||
{text: 'Yes', itemId: 'yes', ui: 'action'}
|
||||
]
|
||||
},
|
||||
|
||||
constructor: function(config) {
|
||||
config = config || {};
|
||||
|
||||
if (config.hasOwnProperty('promptConfig')) {
|
||||
//<debug warn>
|
||||
Ext.Logger.deprecate("'promptConfig' config is deprecated, please use 'prompt' config instead", this);
|
||||
//</debug>
|
||||
|
||||
Ext.applyIf(config, {
|
||||
prompt: config.promptConfig
|
||||
});
|
||||
|
||||
delete config.promptConfig;
|
||||
}
|
||||
|
||||
if (config.hasOwnProperty('multiline') || config.hasOwnProperty('multiLine')) {
|
||||
config.prompt = config.prompt || {};
|
||||
Ext.applyIf(config.prompt, {
|
||||
multiLine: config.multiline || config.multiLine
|
||||
});
|
||||
|
||||
delete config.multiline;
|
||||
delete config.multiLine;
|
||||
}
|
||||
|
||||
this.defaultAllowedConfig = {};
|
||||
var allowedConfigs = ['ui', 'showAnimation', 'hideAnimation', 'title', 'message', 'prompt', 'iconCls', 'buttons', 'defaultTextHeight'],
|
||||
ln = allowedConfigs.length,
|
||||
i, allowedConfig;
|
||||
|
||||
for (i = 0; i < ln; i++) {
|
||||
allowedConfig = allowedConfigs[i];
|
||||
this.defaultAllowedConfig[allowedConfig] = this.defaultConfig[allowedConfig];
|
||||
}
|
||||
|
||||
this.callParent([config]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a new {@link Ext.Toolbar} instance using {@link Ext#factory}.
|
||||
* @private
|
||||
*/
|
||||
applyTitle: function(config) {
|
||||
if (typeof config == "string") {
|
||||
config = {
|
||||
title: config
|
||||
};
|
||||
}
|
||||
|
||||
Ext.applyIf(config, {
|
||||
docked: 'top',
|
||||
minHeight: '1.3em',
|
||||
cls : this.getBaseCls() + '-title'
|
||||
});
|
||||
|
||||
return Ext.factory(config, Ext.Toolbar, this.getTitle());
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds the new {@link Ext.Toolbar} instance into this container.
|
||||
* @private
|
||||
*/
|
||||
updateTitle: function(newTitle) {
|
||||
if (newTitle) {
|
||||
this.add(newTitle);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds the new {@link Ext.Toolbar} instance into this container.
|
||||
* @private
|
||||
*/
|
||||
updateButtons: function(newButtons) {
|
||||
var me = this;
|
||||
|
||||
if (newButtons) {
|
||||
if (me.buttonsToolbar) {
|
||||
me.buttonsToolbar.removeAll();
|
||||
me.buttonsToolbar.setItems(newButtons);
|
||||
} else {
|
||||
me.buttonsToolbar = Ext.create('Ext.Toolbar', {
|
||||
docked : 'bottom',
|
||||
defaultType: 'button',
|
||||
layout : {
|
||||
type: 'hbox',
|
||||
pack: 'center'
|
||||
},
|
||||
ui : me.getUi(),
|
||||
cls : me.getBaseCls() + '-buttons',
|
||||
items : newButtons
|
||||
});
|
||||
|
||||
me.add(me.buttonsToolbar);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyMessage: function(config) {
|
||||
config = {
|
||||
html : config,
|
||||
cls : this.getBaseCls() + '-text'
|
||||
};
|
||||
|
||||
return Ext.factory(config, Ext.Component, this._message);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateMessage: function(newMessage) {
|
||||
if (newMessage) {
|
||||
this.add(newMessage);
|
||||
}
|
||||
},
|
||||
|
||||
getMessage: function() {
|
||||
if (this._message) {
|
||||
return this._message.getHtml();
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyIconCls: function(config) {
|
||||
config = {
|
||||
xtype : 'component',
|
||||
docked: 'left',
|
||||
width : 40,
|
||||
height: 40,
|
||||
baseCls: Ext.baseCSSPrefix + 'icon',
|
||||
hidden: (config) ? false : true,
|
||||
cls: config
|
||||
};
|
||||
|
||||
return Ext.factory(config, Ext.Component, this._iconCls);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updateIconCls: function(newIconCls, oldIconCls) {
|
||||
var me = this;
|
||||
|
||||
//ensure the title and button elements are added first
|
||||
this.getTitle();
|
||||
this.getButtons();
|
||||
|
||||
if (newIconCls) {
|
||||
this.add(newIconCls);
|
||||
} else {
|
||||
this.remove(oldIconCls);
|
||||
}
|
||||
},
|
||||
|
||||
getIconCls: function() {
|
||||
var icon = this._iconCls,
|
||||
iconCls;
|
||||
|
||||
if (icon) {
|
||||
iconCls = icon.getCls();
|
||||
return (iconCls) ? iconCls[0] : null;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyPrompt: function(prompt) {
|
||||
if (prompt) {
|
||||
var config = {
|
||||
label: false
|
||||
};
|
||||
|
||||
if (Ext.isObject(prompt)) {
|
||||
Ext.apply(config, prompt);
|
||||
}
|
||||
|
||||
if (config.multiLine) {
|
||||
config.height = Ext.isNumber(config.multiLine) ? parseFloat(config.multiLine) : this.getDefaultTextHeight();
|
||||
return Ext.factory(config, Ext.field.TextArea, this.getPrompt());
|
||||
} else {
|
||||
return Ext.factory(config, Ext.field.Text, this.getPrompt());
|
||||
}
|
||||
}
|
||||
|
||||
return prompt;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
updatePrompt: function(newPrompt, oldPrompt) {
|
||||
if (newPrompt) {
|
||||
this.add(newPrompt);
|
||||
}
|
||||
|
||||
if (oldPrompt) {
|
||||
this.remove(oldPrompt);
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
// pass `fn` config to show method instead
|
||||
onClick: function(button) {
|
||||
if (button) {
|
||||
var config = button.config.userConfig || {},
|
||||
initialConfig = button.getInitialConfig(),
|
||||
prompt = this.getPrompt();
|
||||
|
||||
if (typeof config.fn == 'function') {
|
||||
this.on({
|
||||
hiddenchange: function() {
|
||||
config.fn.call(
|
||||
config.scope || null,
|
||||
initialConfig.itemId || initialConfig.text,
|
||||
prompt ? prompt.getValue() : null,
|
||||
config
|
||||
);
|
||||
},
|
||||
single: true,
|
||||
scope: this
|
||||
});
|
||||
}
|
||||
|
||||
if (config.input) {
|
||||
config.input.dom.blur();
|
||||
}
|
||||
}
|
||||
|
||||
this.hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the {@link Ext.MessageBox} with a specified configuration. All
|
||||
* display functions (e.g. {@link #method-prompt}, {@link #alert}, {@link #confirm})
|
||||
* on MessageBox call this function internally, although those calls
|
||||
* are basic shortcuts and do not support all of the config options allowed here.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* @example
|
||||
* Ext.Msg.show({
|
||||
* title: 'Address',
|
||||
* message: 'Please enter your address:',
|
||||
* width: 300,
|
||||
* buttons: Ext.MessageBox.OKCANCEL,
|
||||
* multiLine: true,
|
||||
* prompt : { maxlength : 180, autocapitalize : true },
|
||||
* fn: function(buttonId) {
|
||||
* alert('You pressed the "' + buttonId + '" button.');
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* @param {Object} config An object with the following config options:
|
||||
*
|
||||
* @param {Object/Array} [config.buttons=false]
|
||||
* A button config object or Array of the same(e.g., `Ext.MessageBox.OKCANCEL` or `{text:'Foo', itemId:'cancel'}`),
|
||||
* or false to not show any buttons.
|
||||
*
|
||||
* @param {String} config.cls
|
||||
* A custom CSS class to apply to the message box's container element.
|
||||
*
|
||||
* @param {Function} config.fn
|
||||
* A callback function which is called when the dialog is dismissed by clicking on the configured buttons.
|
||||
*
|
||||
* @param {String} config.fn.buttonId The `itemId` of the button pressed, one of: 'ok', 'yes', 'no', 'cancel'.
|
||||
* @param {String} config.fn.value Value of the input field if either `prompt` or `multiline` option is `true`.
|
||||
* @param {Object} config.fn.opt The config object passed to show.
|
||||
*
|
||||
* @param {Number} [config.width=auto]
|
||||
* A fixed width for the MessageBox.
|
||||
*
|
||||
* @param {Number} [config.height=auto]
|
||||
* A fixed height for the MessageBox.
|
||||
*
|
||||
* @param {Object} config.scope
|
||||
* The scope of the callback function
|
||||
*
|
||||
* @param {String} config.icon
|
||||
* A CSS class that provides a background image to be used as the body icon for the dialog
|
||||
* (e.g. Ext.MessageBox.WARNING or 'custom-class').
|
||||
*
|
||||
* @param {Boolean} [config.modal=true]
|
||||
* `false` to allow user interaction with the page while the message box is displayed.
|
||||
*
|
||||
* @param {String} [config.message= ]
|
||||
* A string that will replace the existing message box body text.
|
||||
* Defaults to the XHTML-compliant non-breaking space character ` `.
|
||||
*
|
||||
* @param {Number} [config.defaultTextHeight=75]
|
||||
* The default height in pixels of the message box's multiline textarea if displayed.
|
||||
*
|
||||
* @param {Boolean} [config.prompt=false]
|
||||
* `true` to prompt the user to enter single-line text. Please view the {@link Ext.MessageBox#method-prompt} documentation in {@link Ext.MessageBox}.
|
||||
* for more information.
|
||||
*
|
||||
* @param {Boolean} [config.multiline=false]
|
||||
* `true` to prompt the user to enter multi-line text.
|
||||
*
|
||||
* @param {String} config.title
|
||||
* The title text.
|
||||
*
|
||||
* @param {String} config.value
|
||||
* The string value to set into the active textbox element if displayed.
|
||||
*
|
||||
* @return {Ext.MessageBox} this
|
||||
*/
|
||||
show: function(initialConfig) {
|
||||
//if it has not been added to a container, add it to the Viewport.
|
||||
if (!this.getParent() && Ext.Viewport) {
|
||||
Ext.Viewport.add(this);
|
||||
}
|
||||
|
||||
if (!initialConfig) {
|
||||
return this.callParent();
|
||||
}
|
||||
|
||||
var config = Ext.Object.merge({}, {
|
||||
value: ''
|
||||
}, initialConfig);
|
||||
|
||||
var buttons = initialConfig.buttons || Ext.MessageBox.OK || [],
|
||||
buttonBarItems = [],
|
||||
userConfig = initialConfig;
|
||||
|
||||
Ext.each(buttons, function(buttonConfig) {
|
||||
if (!buttonConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
buttonBarItems.push(Ext.apply({
|
||||
userConfig: userConfig,
|
||||
scope : this,
|
||||
handler : 'onClick'
|
||||
}, buttonConfig));
|
||||
}, this);
|
||||
|
||||
config.buttons = buttonBarItems;
|
||||
|
||||
if (config.promptConfig) {
|
||||
//<debug warn>
|
||||
Ext.Logger.deprecate("'promptConfig' config is deprecated, please use 'prompt' config instead", this);
|
||||
//</debug>
|
||||
}
|
||||
config.prompt = (config.promptConfig || config.prompt) || null;
|
||||
|
||||
if (config.multiLine) {
|
||||
config.prompt = config.prompt || {};
|
||||
config.prompt.multiLine = config.multiLine;
|
||||
delete config.multiLine;
|
||||
}
|
||||
|
||||
config = Ext.merge({}, this.defaultAllowedConfig, config);
|
||||
|
||||
this.setConfig(config);
|
||||
|
||||
var prompt = this.getPrompt();
|
||||
if (prompt) {
|
||||
prompt.setValue(initialConfig.value || '');
|
||||
}
|
||||
|
||||
this.callParent();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays a standard read-only message box with an OK button (comparable to the basic JavaScript alert prompt). If
|
||||
* a callback function is passed it will be called after the user clicks the button, and the `itemId` of the button
|
||||
* that was clicked will be passed as the only parameter to the callback.
|
||||
*
|
||||
* @param {String} title The title bar text.
|
||||
* @param {String} message The message box body text.
|
||||
* @param {Function} fn A callback function which is called when the dialog is dismissed by clicking on the configured buttons.
|
||||
* @param {String} fn.buttonId The `itemId` of the button pressed, one of: 'ok', 'yes', 'no', 'cancel'.
|
||||
* @param {String} fn.value Value of the input field if either `prompt` or `multiLine` option is `true`.
|
||||
* @param {Object} fn.opt The config object passed to show.
|
||||
* @param {Object} scope The scope (`this` reference) in which the callback is executed.
|
||||
* Defaults to: the browser window
|
||||
*
|
||||
* @return {Ext.MessageBox} this
|
||||
*/
|
||||
alert: function(title, message, fn, scope) {
|
||||
return this.show({
|
||||
title: title || null,
|
||||
message: message || null,
|
||||
buttons: Ext.MessageBox.OK,
|
||||
promptConfig: false,
|
||||
fn: function() {
|
||||
if (fn) {
|
||||
fn.apply(scope, arguments);
|
||||
}
|
||||
},
|
||||
scope: scope
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's confirm). If a callback
|
||||
* function is passed it will be called after the user clicks either button, and the id of the button that was
|
||||
* clicked will be passed as the only parameter to the callback (could also be the top-right close button).
|
||||
*
|
||||
* @param {String} title The title bar text.
|
||||
* @param {String} message The message box body text.
|
||||
* @param {Function} fn A callback function which is called when the dialog is dismissed by clicking on the configured buttons.
|
||||
* @param {String} fn.buttonId The `itemId` of the button pressed, one of: 'ok', 'yes', 'no', 'cancel'.
|
||||
* @param {String} fn.value Value of the input field if either `prompt` or `multiLine` option is `true`.
|
||||
* @param {Object} fn.opt The config object passed to show.
|
||||
* @param {Object} [scope] The scope (`this` reference) in which the callback is executed.
|
||||
*
|
||||
* Defaults to: the browser window
|
||||
*
|
||||
* @return {Ext.MessageBox} this
|
||||
*/
|
||||
confirm: function(title, message, fn, scope) {
|
||||
return this.show({
|
||||
title : title || null,
|
||||
message : message || null,
|
||||
buttons : Ext.MessageBox.YESNO,
|
||||
promptConfig: false,
|
||||
scope : scope,
|
||||
fn: function() {
|
||||
if (fn) {
|
||||
fn.apply(scope, arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
|
||||
* JavaScript's prompt). The prompt can be a single-line or multi-line textbox. If a callback function is passed it
|
||||
* will be called after the user clicks either button, and the id of the button that was clicked (could also be the
|
||||
* top-right close button) and the text that was entered will be passed as the two parameters to the callback.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* @example
|
||||
* Ext.Msg.prompt(
|
||||
* 'Welcome!',
|
||||
* 'What\'s your name going to be today?',
|
||||
* function (buttonId, value) {
|
||||
* console.log(value);
|
||||
* },
|
||||
* null,
|
||||
* false,
|
||||
* null,
|
||||
* {
|
||||
* autoCapitalize: true,
|
||||
* placeHolder: 'First-name please...'
|
||||
* }
|
||||
* );
|
||||
*
|
||||
* @param {String} title The title bar text.
|
||||
* @param {String} message The message box body text.
|
||||
* @param {Function} fn A callback function which is called when the dialog is dismissed by clicking on the configured buttons.
|
||||
* @param {String} fn.buttonId The `itemId` of the button pressed, one of: 'ok', 'yes', 'no', 'cancel'.
|
||||
* @param {String} fn.value Value of the input field if either `prompt` or `multiLine` option is `true`.
|
||||
* @param {Object} fn.opt The config object passed to show.
|
||||
* @param {Object} scope The scope (`this` reference) in which the callback is executed.
|
||||
*
|
||||
* Defaults to: the browser window.
|
||||
*
|
||||
* @param {Boolean/Number} [multiLine=false] `true` to create a multiline textbox using the `defaultTextHeight` property,
|
||||
* or the height in pixels to create the textbox.
|
||||
*
|
||||
* @param {String} [value] Default value of the text input element.
|
||||
*
|
||||
* @param {Object} [prompt=true]
|
||||
* The configuration for the prompt. See the {@link Ext.MessageBox#cfg-prompt prompt} documentation in {@link Ext.MessageBox}
|
||||
* for more information.
|
||||
*
|
||||
* @return {Ext.MessageBox} this
|
||||
*/
|
||||
prompt: function(title, message, fn, scope, multiLine, value, prompt) {
|
||||
return this.show({
|
||||
title : title || null,
|
||||
message : message || null,
|
||||
buttons : Ext.MessageBox.OKCANCEL,
|
||||
scope : scope,
|
||||
prompt : prompt || true,
|
||||
multiLine: multiLine,
|
||||
value : value,
|
||||
fn: function() {
|
||||
if (fn) {
|
||||
fn.apply(scope, arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}, function(MessageBox) {
|
||||
// <deprecated product=touch since=2.0>
|
||||
this.override({
|
||||
/**
|
||||
* @cfg {String} icon
|
||||
* Sets CSS class for icon.
|
||||
* @removed 2.0 Use #iconCls instead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets #icon.
|
||||
* @deprecated 2.0 Please use #setIconCls instead.
|
||||
* @param {String} icon A CSS class name or empty string to clear the icon.
|
||||
* @return {Ext.MessageBox} this
|
||||
*/
|
||||
setIcon: function(iconCls, doLayout){
|
||||
//<debug warn>
|
||||
Ext.Logger.deprecate("Ext.MessageBox#setIcon is deprecated, use setIconCls instead", 2);
|
||||
//</debug>
|
||||
this.setIconCls(iconCls);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* @inheritdoc Ext.MessageBox#setMessage
|
||||
* @deprecated 2.0.0 Please use #setMessage instead.
|
||||
*/
|
||||
updateText: function(text){
|
||||
//<debug warn>
|
||||
Ext.Logger.deprecate("Ext.MessageBox#updateText is deprecated, use setMessage instead", 2);
|
||||
//</debug>
|
||||
this.setMessage(text);
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
// </deprecated>
|
||||
|
||||
Ext.onSetup(function() {
|
||||
/**
|
||||
* @class Ext.Msg
|
||||
* @extends Ext.MessageBox
|
||||
* @singleton
|
||||
*
|
||||
* A global shared singleton instance of the {@link Ext.MessageBox} class.
|
||||
*
|
||||
* Allows for simple creation of various different alerts and notifications.
|
||||
*
|
||||
* To change any configurations on this singleton instance, you must change the
|
||||
* `defaultAllowedConfig` object. For example to remove all animations on `Msg`:
|
||||
*
|
||||
* Ext.Msg.defaultAllowedConfig.showAnimation = false;
|
||||
* Ext.Msg.defaultAllowedConfig.hideAnimation = false;
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* ### Alert
|
||||
* Use the {@link #alert} method to show a basic alert:
|
||||
*
|
||||
* @example preview
|
||||
* Ext.Msg.alert('Title', 'The quick brown fox jumped over the lazy dog.', Ext.emptyFn);
|
||||
*
|
||||
* ### Prompt
|
||||
* Use the {@link #method-prompt} method to show an alert which has a textfield:
|
||||
*
|
||||
* @example preview
|
||||
* Ext.Msg.prompt('Name', 'Please enter your name:', function(text) {
|
||||
* // process text value and close...
|
||||
* });
|
||||
*
|
||||
* ### Confirm
|
||||
* Use the {@link #confirm} method to show a confirmation alert (shows yes and no buttons).
|
||||
*
|
||||
* @example preview
|
||||
* Ext.Msg.confirm("Confirmation", "Are you sure you want to do that?", Ext.emptyFn);
|
||||
*/
|
||||
Ext.Msg = new MessageBox;
|
||||
});
|
||||
});
|
||||
|
||||
213
OfficeWeb/3rdparty/touch/src/Panel.js
vendored
Normal file
213
OfficeWeb/3rdparty/touch/src/Panel.js
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* @aside guide floating_components
|
||||
*
|
||||
* Panels are most useful as Overlays - containers that float over your application. They contain extra styling such
|
||||
* that when you {@link #showBy} another component, the container will appear in a rounded black box with a 'tip'
|
||||
* pointing to a reference component.
|
||||
*
|
||||
* If you don't need this extra functionality, you should use {@link Ext.Container} instead. See the
|
||||
* [Overlays example](#!/example/overlays) for more use cases.
|
||||
*
|
||||
* @example miniphone preview
|
||||
*
|
||||
* var button = Ext.create('Ext.Button', {
|
||||
* text: 'Button',
|
||||
* id: 'rightButton'
|
||||
* });
|
||||
*
|
||||
* Ext.create('Ext.Container', {
|
||||
* fullscreen: true,
|
||||
* items: [
|
||||
* {
|
||||
* docked: 'top',
|
||||
* xtype: 'titlebar',
|
||||
* items: [
|
||||
* button
|
||||
* ]
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* Ext.create('Ext.Panel', {
|
||||
* html: 'Floating Panel',
|
||||
* left: 0,
|
||||
* padding: 10
|
||||
* }).showBy(button);
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.Panel', {
|
||||
extend: 'Ext.Container',
|
||||
requires: ['Ext.util.LineSegment'],
|
||||
|
||||
alternateClassName: 'Ext.lib.Panel',
|
||||
|
||||
xtype: 'panel',
|
||||
|
||||
isPanel: true,
|
||||
|
||||
config: {
|
||||
baseCls: Ext.baseCSSPrefix + 'panel',
|
||||
|
||||
/**
|
||||
* @cfg {Number/Boolean/String} bodyPadding
|
||||
* A shortcut for setting a padding style on the body element. The value can either be
|
||||
* a number to be applied to all sides, or a normal CSS string describing padding.
|
||||
* @deprecated 2.0.0
|
||||
*/
|
||||
bodyPadding: null,
|
||||
|
||||
/**
|
||||
* @cfg {Number/Boolean/String} bodyMargin
|
||||
* A shortcut for setting a margin style on the body element. The value can either be
|
||||
* a number to be applied to all sides, or a normal CSS string describing margins.
|
||||
* @deprecated 2.0.0
|
||||
*/
|
||||
bodyMargin: null,
|
||||
|
||||
/**
|
||||
* @cfg {Number/Boolean/String} bodyBorder
|
||||
* A shortcut for setting a border style on the body element. The value can either be
|
||||
* a number to be applied to all sides, or a normal CSS string describing borders.
|
||||
* @deprecated 2.0.0
|
||||
*/
|
||||
bodyBorder: null
|
||||
},
|
||||
|
||||
getElementConfig: function() {
|
||||
var config = this.callParent();
|
||||
|
||||
config.children.push({
|
||||
reference: 'tipElement',
|
||||
className: 'x-anchor',
|
||||
hidden: true
|
||||
});
|
||||
|
||||
return config;
|
||||
},
|
||||
|
||||
applyBodyPadding: function(bodyPadding) {
|
||||
if (bodyPadding === true) {
|
||||
bodyPadding = 5;
|
||||
}
|
||||
|
||||
if (bodyPadding) {
|
||||
bodyPadding = Ext.dom.Element.unitizeBox(bodyPadding);
|
||||
}
|
||||
|
||||
return bodyPadding;
|
||||
},
|
||||
|
||||
updateBodyPadding: function(newBodyPadding) {
|
||||
this.element.setStyle('padding', newBodyPadding);
|
||||
},
|
||||
|
||||
applyBodyMargin: function(bodyMargin) {
|
||||
if (bodyMargin === true) {
|
||||
bodyMargin = 5;
|
||||
}
|
||||
|
||||
if (bodyMargin) {
|
||||
bodyMargin = Ext.dom.Element.unitizeBox(bodyMargin);
|
||||
}
|
||||
|
||||
return bodyMargin;
|
||||
},
|
||||
|
||||
updateBodyMargin: function(newBodyMargin) {
|
||||
this.element.setStyle('margin', newBodyMargin);
|
||||
},
|
||||
|
||||
applyBodyBorder: function(bodyBorder) {
|
||||
if (bodyBorder === true) {
|
||||
bodyBorder = 1;
|
||||
}
|
||||
|
||||
if (bodyBorder) {
|
||||
bodyBorder = Ext.dom.Element.unitizeBox(bodyBorder);
|
||||
}
|
||||
|
||||
return bodyBorder;
|
||||
},
|
||||
|
||||
updateBodyBorder: function(newBodyBorder) {
|
||||
this.element.setStyle('border-width', newBodyBorder);
|
||||
},
|
||||
|
||||
alignTo: function(component) {
|
||||
var tipElement = this.tipElement;
|
||||
|
||||
tipElement.hide();
|
||||
|
||||
if (this.currentTipPosition) {
|
||||
tipElement.removeCls('x-anchor-' + this.currentTipPosition);
|
||||
}
|
||||
|
||||
this.callParent(arguments);
|
||||
|
||||
var LineSegment = Ext.util.LineSegment,
|
||||
alignToElement = component.isComponent ? component.renderElement : component,
|
||||
element = this.renderElement,
|
||||
alignToBox = alignToElement.getPageBox(),
|
||||
box = element.getPageBox(),
|
||||
left = box.left,
|
||||
top = box.top,
|
||||
right = box.right,
|
||||
bottom = box.bottom,
|
||||
centerX = left + (box.width / 2),
|
||||
centerY = top + (box.height / 2),
|
||||
leftTopPoint = { x: left, y: top },
|
||||
rightTopPoint = { x: right, y: top },
|
||||
leftBottomPoint = { x: left, y: bottom },
|
||||
rightBottomPoint = { x: right, y: bottom },
|
||||
boxCenterPoint = { x: centerX, y: centerY },
|
||||
alignToCenterX = alignToBox.left + (alignToBox.width / 2),
|
||||
alignToCenterY = alignToBox.top + (alignToBox.height / 2),
|
||||
alignToBoxCenterPoint = { x: alignToCenterX, y: alignToCenterY },
|
||||
centerLineSegment = new LineSegment(boxCenterPoint, alignToBoxCenterPoint),
|
||||
offsetLeft = 0,
|
||||
offsetTop = 0,
|
||||
tipSize, tipWidth, tipHeight, tipPosition, tipX, tipY;
|
||||
|
||||
tipElement.setVisibility(false);
|
||||
tipElement.show();
|
||||
tipSize = tipElement.getSize();
|
||||
tipWidth = tipSize.width;
|
||||
tipHeight = tipSize.height;
|
||||
|
||||
if (centerLineSegment.intersects(new LineSegment(leftTopPoint, rightTopPoint))) {
|
||||
tipX = Math.min(Math.max(alignToCenterX, left + tipWidth), right - (tipWidth));
|
||||
tipY = top;
|
||||
offsetTop = tipHeight + 10;
|
||||
tipPosition = 'top';
|
||||
}
|
||||
else if (centerLineSegment.intersects(new LineSegment(leftTopPoint, leftBottomPoint))) {
|
||||
tipX = left;
|
||||
tipY = Math.min(Math.max(alignToCenterY + (tipWidth / 2), tipWidth * 1.6), bottom - (tipWidth / 2.2));
|
||||
offsetLeft = tipHeight + 10;
|
||||
tipPosition = 'left';
|
||||
}
|
||||
else if (centerLineSegment.intersects(new LineSegment(leftBottomPoint, rightBottomPoint))) {
|
||||
tipX = Math.min(Math.max(alignToCenterX, left + tipWidth), right - tipWidth);
|
||||
tipY = bottom;
|
||||
offsetTop = -tipHeight - 10;
|
||||
tipPosition = 'bottom';
|
||||
}
|
||||
else if (centerLineSegment.intersects(new LineSegment(rightTopPoint, rightBottomPoint))) {
|
||||
tipX = right;
|
||||
tipY = Math.max(Math.min(alignToCenterY - tipHeight, bottom - tipWidth * 1.3), tipWidth / 2);
|
||||
offsetLeft = -tipHeight - 10;
|
||||
tipPosition = 'right';
|
||||
}
|
||||
|
||||
if (tipX || tipY) {
|
||||
this.currentTipPosition = tipPosition;
|
||||
tipElement.addCls('x-anchor-' + tipPosition);
|
||||
tipElement.setLeft(tipX - left);
|
||||
tipElement.setTop(tipY - top);
|
||||
tipElement.setVisibility(true);
|
||||
|
||||
this.setLeft(this.getLeft() + offsetLeft);
|
||||
this.setTop(this.getTop() + offsetTop);
|
||||
}
|
||||
}
|
||||
});
|
||||
361
OfficeWeb/3rdparty/touch/src/SegmentedButton.js
vendored
Normal file
361
OfficeWeb/3rdparty/touch/src/SegmentedButton.js
vendored
Normal file
@@ -0,0 +1,361 @@
|
||||
/**
|
||||
* SegmentedButton is a container for a group of {@link Ext.Button}s. Generally a SegmentedButton would be
|
||||
* a child of a {@link Ext.Toolbar} and would be used to switch between different views.
|
||||
*
|
||||
* ## Example usage:
|
||||
*
|
||||
* @example
|
||||
* var segmentedButton = Ext.create('Ext.SegmentedButton', {
|
||||
* allowMultiple: true,
|
||||
* items: [
|
||||
* {
|
||||
* text: 'Option 1'
|
||||
* },
|
||||
* {
|
||||
* text: 'Option 2',
|
||||
* pressed: true
|
||||
* },
|
||||
* {
|
||||
* text: 'Option 3'
|
||||
* }
|
||||
* ],
|
||||
* listeners: {
|
||||
* toggle: function(container, button, pressed){
|
||||
* alert("User toggled the '" + button.getText() + "' button: " + (pressed ? 'on' : 'off'));
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
* Ext.Viewport.add({ xtype: 'container', padding: 10, items: [segmentedButton] });
|
||||
*/
|
||||
Ext.define('Ext.SegmentedButton', {
|
||||
extend: 'Ext.Container',
|
||||
xtype : 'segmentedbutton',
|
||||
requires: ['Ext.Button'],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: Ext.baseCSSPrefix + 'segmentedbutton',
|
||||
|
||||
/**
|
||||
* @cfg {String} pressedCls
|
||||
* CSS class when a button is in pressed state.
|
||||
* @accessor
|
||||
*/
|
||||
pressedCls: Ext.baseCSSPrefix + 'button-pressed',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} allowMultiple
|
||||
* Allow multiple pressed buttons.
|
||||
* @accessor
|
||||
*/
|
||||
allowMultiple: false,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} allowDepress
|
||||
* Allow toggling the pressed state of each button.
|
||||
* Defaults to `true` when {@link #allowMultiple} is `true`.
|
||||
* @accessor
|
||||
*/
|
||||
allowDepress: false,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} allowToggle Allow child buttons to be pressed when tapped on. Set to `false` to allow tapping but not toggling of the buttons.
|
||||
* @accessor
|
||||
*/
|
||||
allowToggle: true,
|
||||
|
||||
/**
|
||||
* @cfg {Array} pressedButtons
|
||||
* The pressed buttons for this segmented button.
|
||||
*
|
||||
* You can remove all pressed buttons by calling {@link #setPressedButtons} with an empty array.
|
||||
* @accessor
|
||||
*/
|
||||
pressedButtons: [],
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
layout: {
|
||||
type : 'hbox',
|
||||
align: 'stretch'
|
||||
},
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
defaultType: 'button'
|
||||
},
|
||||
|
||||
/**
|
||||
* @event toggle
|
||||
* Fires when any child button's pressed state has changed.
|
||||
* @param {Ext.SegmentedButton} this
|
||||
* @param {Ext.Button} button The toggled button.
|
||||
* @param {Boolean} isPressed Boolean to indicate if the button was pressed or not.
|
||||
*/
|
||||
|
||||
initialize: function() {
|
||||
var me = this;
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.on({
|
||||
delegate: '> button',
|
||||
scope : me,
|
||||
tap: 'onButtonRelease'
|
||||
});
|
||||
|
||||
me.onAfter({
|
||||
delegate: '> button',
|
||||
scope : me,
|
||||
hiddenchange: 'onButtonHiddenChange'
|
||||
});
|
||||
},
|
||||
|
||||
updateAllowMultiple: function(allowMultiple) {
|
||||
if (!this.initialized && !this.getInitialConfig().hasOwnProperty('allowDepress') && allowMultiple) {
|
||||
this.setAllowDepress(true);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* We override `initItems` so we can check for the pressed config.
|
||||
*/
|
||||
applyItems: function() {
|
||||
var me = this,
|
||||
pressedButtons = [],
|
||||
ln, i, item, items;
|
||||
|
||||
//call the parent first so the items get converted into a MixedCollection
|
||||
me.callParent(arguments);
|
||||
|
||||
items = this.getItems();
|
||||
ln = items.length;
|
||||
|
||||
for (i = 0; i < ln; i++) {
|
||||
item = items.items[i];
|
||||
if (item.getInitialConfig('pressed')) {
|
||||
pressedButtons.push(items.items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
me.updateFirstAndLastCls(items);
|
||||
|
||||
me.setPressedButtons(pressedButtons);
|
||||
},
|
||||
|
||||
/**
|
||||
* Button sets a timeout of 10ms to remove the {@link #pressedCls} on the release event.
|
||||
* We don't want this to happen, so lets return `false` and cancel the event.
|
||||
* @private
|
||||
*/
|
||||
onButtonRelease: function(button) {
|
||||
if (!this.getAllowToggle()) {
|
||||
return;
|
||||
}
|
||||
var me = this,
|
||||
pressedButtons = me.getPressedButtons() || [],
|
||||
buttons = [],
|
||||
alreadyPressed;
|
||||
|
||||
if (!me.getDisabled() && !button.getDisabled()) {
|
||||
//if we allow for multiple pressed buttons, use the existing pressed buttons
|
||||
if (me.getAllowMultiple()) {
|
||||
buttons = pressedButtons.concat(buttons);
|
||||
}
|
||||
|
||||
alreadyPressed = (buttons.indexOf(button) !== -1) || (pressedButtons.indexOf(button) !== -1);
|
||||
|
||||
//if we allow for depressing buttons, and the new pressed button is currently pressed, remove it
|
||||
if (alreadyPressed && me.getAllowDepress()) {
|
||||
Ext.Array.remove(buttons, button);
|
||||
} else if (!alreadyPressed || !me.getAllowDepress()) {
|
||||
buttons.push(button);
|
||||
}
|
||||
|
||||
me.setPressedButtons(buttons);
|
||||
}
|
||||
},
|
||||
|
||||
onItemAdd: function() {
|
||||
this.callParent(arguments);
|
||||
this.updateFirstAndLastCls(this.getItems());
|
||||
},
|
||||
|
||||
onItemRemove: function() {
|
||||
this.callParent(arguments);
|
||||
this.updateFirstAndLastCls(this.getItems());
|
||||
},
|
||||
|
||||
// @private
|
||||
onButtonHiddenChange: function() {
|
||||
this.updateFirstAndLastCls(this.getItems());
|
||||
},
|
||||
|
||||
// @private
|
||||
updateFirstAndLastCls: function(items) {
|
||||
var ln = items.length,
|
||||
basePrefix = Ext.baseCSSPrefix,
|
||||
firstCls = basePrefix + 'first',
|
||||
lastCls = basePrefix + 'last',
|
||||
item, i;
|
||||
|
||||
//remove all existing classes
|
||||
for (i = 0; i < ln; i++) {
|
||||
item = items.items[i];
|
||||
item.removeCls(firstCls);
|
||||
item.removeCls(lastCls);
|
||||
}
|
||||
|
||||
//add a first cls to the first non-hidden button
|
||||
for (i = 0; i < ln; i++) {
|
||||
item = items.items[i];
|
||||
if (!item.isHidden()) {
|
||||
item.addCls(firstCls);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//add a last cls to the last non-hidden button
|
||||
for (i = ln - 1; i >= 0; i--) {
|
||||
item = items.items[i];
|
||||
if (!item.isHidden()) {
|
||||
item.addCls(lastCls);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyPressedButtons: function(newButtons) {
|
||||
var me = this,
|
||||
array = [],
|
||||
button, ln, i;
|
||||
|
||||
if (me.getAllowToggle()) {
|
||||
if (Ext.isArray(newButtons)) {
|
||||
ln = newButtons.length;
|
||||
for (i = 0; i< ln; i++) {
|
||||
button = me.getComponent(newButtons[i]);
|
||||
if (button && array.indexOf(button) === -1) {
|
||||
array.push(button);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
button = me.getComponent(newButtons);
|
||||
if (button && array.indexOf(button) === -1) {
|
||||
array.push(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the pressed buttons.
|
||||
* @private
|
||||
*/
|
||||
updatePressedButtons: function(newButtons, oldButtons) {
|
||||
var me = this,
|
||||
items = me.getItems(),
|
||||
pressedCls = me.getPressedCls(),
|
||||
events = [],
|
||||
item, button, ln, i, e;
|
||||
|
||||
//loop through existing items and remove the pressed cls from them
|
||||
ln = items.length;
|
||||
if (oldButtons && oldButtons.length) {
|
||||
for (i = 0; i < ln; i++) {
|
||||
item = items.items[i];
|
||||
|
||||
if (oldButtons.indexOf(item) != -1 && newButtons.indexOf(item) == -1) {
|
||||
item.removeCls([pressedCls, item.getPressedCls()]);
|
||||
events.push({
|
||||
item: item,
|
||||
toggle: false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//loop through the new pressed buttons and add the pressed cls to them
|
||||
ln = newButtons.length;
|
||||
for (i = 0; i < ln; i++) {
|
||||
button = newButtons[i];
|
||||
if (!oldButtons || oldButtons.indexOf(button) == -1) {
|
||||
button.addCls(pressedCls);
|
||||
events.push({
|
||||
item: button,
|
||||
toggle: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//loop through each of the events and fire them after a delay
|
||||
ln = events.length;
|
||||
if (ln && oldButtons !== undefined) {
|
||||
Ext.defer(function() {
|
||||
for (i = 0; i < ln; i++) {
|
||||
e = events[i];
|
||||
me.fireEvent('toggle', me, e.item, e.toggle);
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns `true` if a specified {@link Ext.Button} is pressed.
|
||||
* @param {Ext.Button} button The button to check if pressed.
|
||||
* @return {Boolean} pressed
|
||||
*/
|
||||
isPressed: function(button) {
|
||||
var pressedButtons = this.getPressedButtons();
|
||||
return pressedButtons.indexOf(button) != -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
doSetDisabled: function(disabled) {
|
||||
var me = this;
|
||||
|
||||
me.items.each(function(item) {
|
||||
item.setDisabled(disabled);
|
||||
}, me);
|
||||
|
||||
me.callParent(arguments);
|
||||
}
|
||||
}, function() {
|
||||
//<deprecated product=touch since=2.0>
|
||||
var me = this;
|
||||
|
||||
/**
|
||||
* Activates a button.
|
||||
* @param {Number/String/Ext.Button} button The button to activate.
|
||||
* @param {Boolean} pressed If defined, sets the pressed state of the button,
|
||||
* otherwise the pressed state is toggled.
|
||||
* @param {Boolean} suppressEvents `true` to suppress toggle events during the action.
|
||||
* If {@link #allowMultiple} is `true`, then {@link #setPressed} will toggle the button state.
|
||||
* @method setPressed
|
||||
* @deprecated 2.0.0 Please use {@link #setPressedButtons} instead
|
||||
*/
|
||||
Ext.deprecateClassMethod(me, 'setPressed', 'setPressedButtons');
|
||||
|
||||
/**
|
||||
* Gets the currently pressed button(s).
|
||||
* @method getPressed
|
||||
* @deprecated 2.0.0 Please use {@link #getPressedButtons} instead
|
||||
*/
|
||||
Ext.deprecateClassMethod(me, 'getPressed', 'getPressedButtons');
|
||||
|
||||
//</deprecated>
|
||||
});
|
||||
167
OfficeWeb/3rdparty/touch/src/Sheet.js
vendored
Normal file
167
OfficeWeb/3rdparty/touch/src/Sheet.js
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* A general sheet class. This renderable container provides base support for orientation-aware transitions for popup or
|
||||
* side-anchored sliding Panels.
|
||||
*
|
||||
* In most cases, you should use {@link Ext.ActionSheet}, {@link Ext.MessageBox}, {@link Ext.picker.Picker}, or {@link Ext.picker.Date}.
|
||||
*/
|
||||
Ext.define('Ext.Sheet', {
|
||||
extend: 'Ext.Panel',
|
||||
|
||||
xtype: 'sheet',
|
||||
|
||||
requires: ['Ext.fx.Animation'],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: Ext.baseCSSPrefix + 'sheet',
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
modal: true,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} centered
|
||||
* Whether or not this component is absolutely centered inside its container.
|
||||
* @accessor
|
||||
* @evented
|
||||
*/
|
||||
centered: true,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} stretchX `true` to stretch this sheet horizontally.
|
||||
*/
|
||||
stretchX: null,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} stretchY `true` to stretch this sheet vertically.
|
||||
*/
|
||||
stretchY: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} enter
|
||||
* The viewport side used as the enter point when shown. Valid values are 'top', 'bottom', 'left', and 'right'.
|
||||
* Applies to sliding animation effects only.
|
||||
*/
|
||||
enter: 'bottom',
|
||||
|
||||
/**
|
||||
* @cfg {String} exit
|
||||
* The viewport side used as the exit point when hidden. Valid values are 'top', 'bottom', 'left', and 'right'.
|
||||
* Applies to sliding animation effects only.
|
||||
*/
|
||||
exit: 'bottom',
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
showAnimation: !Ext.os.is.Android2 ? {
|
||||
type: 'slideIn',
|
||||
duration: 250,
|
||||
easing: 'ease-out'
|
||||
} : null,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
hideAnimation: !Ext.os.is.Android2 ? {
|
||||
type: 'slideOut',
|
||||
duration: 250,
|
||||
easing: 'ease-in'
|
||||
} : null
|
||||
},
|
||||
|
||||
applyHideAnimation: function(config) {
|
||||
var exit = this.getExit(),
|
||||
direction = exit;
|
||||
|
||||
if (exit === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (config === true) {
|
||||
config = {
|
||||
type: 'slideOut'
|
||||
};
|
||||
}
|
||||
if (Ext.isString(config)) {
|
||||
config = {
|
||||
type: config
|
||||
};
|
||||
}
|
||||
var anim = Ext.factory(config, Ext.fx.Animation);
|
||||
|
||||
if (anim) {
|
||||
if (exit == 'bottom') {
|
||||
direction = 'down';
|
||||
}
|
||||
if (exit == 'top') {
|
||||
direction = 'up';
|
||||
}
|
||||
anim.setDirection(direction);
|
||||
}
|
||||
return anim;
|
||||
},
|
||||
|
||||
applyShowAnimation: function(config) {
|
||||
var enter = this.getEnter(),
|
||||
direction = enter;
|
||||
|
||||
if (enter === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (config === true) {
|
||||
config = {
|
||||
type: 'slideIn'
|
||||
};
|
||||
}
|
||||
if (Ext.isString(config)) {
|
||||
config = {
|
||||
type: config
|
||||
};
|
||||
}
|
||||
var anim = Ext.factory(config, Ext.fx.Animation);
|
||||
|
||||
if (anim) {
|
||||
if (enter == 'bottom') {
|
||||
direction = 'down';
|
||||
}
|
||||
if (enter == 'top') {
|
||||
direction = 'up';
|
||||
}
|
||||
anim.setBefore({
|
||||
display: null
|
||||
});
|
||||
anim.setReverse(true);
|
||||
anim.setDirection(direction);
|
||||
}
|
||||
return anim;
|
||||
},
|
||||
|
||||
updateStretchX: function(newStretchX) {
|
||||
this.getLeft();
|
||||
this.getRight();
|
||||
|
||||
if (newStretchX) {
|
||||
this.setLeft(0);
|
||||
this.setRight(0);
|
||||
}
|
||||
},
|
||||
|
||||
updateStretchY: function(newStretchY) {
|
||||
this.getTop();
|
||||
this.getBottom();
|
||||
|
||||
if (newStretchY) {
|
||||
this.setTop(0);
|
||||
this.setBottom(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
328
OfficeWeb/3rdparty/touch/src/Sortable.js
vendored
Normal file
328
OfficeWeb/3rdparty/touch/src/Sortable.js
vendored
Normal file
@@ -0,0 +1,328 @@
|
||||
/**
|
||||
* A mixin which allows a data component to be sorted
|
||||
* @ignore
|
||||
*/
|
||||
Ext.define('Ext.Sortable', {
|
||||
mixins: {
|
||||
observable: 'Ext.mixin.Observable'
|
||||
},
|
||||
|
||||
requires: ['Ext.util.Draggable'],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: Ext.baseCSSPrefix + 'sortable',
|
||||
|
||||
/**
|
||||
* @cfg {Number} delay
|
||||
* How many milliseconds a user must hold the draggable before starting a
|
||||
* drag operation.
|
||||
* @private
|
||||
* @accessor
|
||||
*/
|
||||
delay: 0
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* @cfg {String} direction
|
||||
* Possible values: 'vertical', 'horizontal'.
|
||||
*/
|
||||
direction: 'vertical',
|
||||
|
||||
/**
|
||||
* @cfg {String} cancelSelector
|
||||
* A simple CSS selector that represents elements within the draggable
|
||||
* that should NOT initiate a drag.
|
||||
*/
|
||||
cancelSelector: null,
|
||||
|
||||
// not yet implemented
|
||||
//indicator: true,
|
||||
//proxy: true,
|
||||
//tolerance: null,
|
||||
|
||||
/**
|
||||
* @cfg {HTMLElement/Boolean} constrain
|
||||
* An Element to constrain the Sortable dragging to.
|
||||
* If `true` is specified, the dragging will be constrained to the element
|
||||
* of the sortable.
|
||||
*/
|
||||
constrain: window,
|
||||
/**
|
||||
* @cfg {String} group
|
||||
* Draggable and Droppable objects can participate in a group which are
|
||||
* capable of interacting.
|
||||
*/
|
||||
group: 'base',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} revert
|
||||
* This should NOT be changed.
|
||||
* @private
|
||||
*/
|
||||
revert: true,
|
||||
|
||||
/**
|
||||
* @cfg {String} itemSelector
|
||||
* A simple CSS selector that represents individual items within the Sortable.
|
||||
*/
|
||||
itemSelector: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} handleSelector
|
||||
* A simple CSS selector to indicate what is the handle to drag the Sortable.
|
||||
*/
|
||||
handleSelector: null,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} disabled
|
||||
* Passing in `true` will disable this Sortable.
|
||||
*/
|
||||
disabled: false,
|
||||
|
||||
// Properties
|
||||
|
||||
/**
|
||||
* Read-only property that indicates whether a Sortable is currently sorting.
|
||||
* @type Boolean
|
||||
* @private
|
||||
* @readonly
|
||||
*/
|
||||
sorting: false,
|
||||
|
||||
/**
|
||||
* Read-only value representing whether the Draggable can be moved vertically.
|
||||
* This is automatically calculated by Draggable by the direction configuration.
|
||||
* @type Boolean
|
||||
* @private
|
||||
* @readonly
|
||||
*/
|
||||
vertical: false,
|
||||
|
||||
/**
|
||||
* Creates new Sortable.
|
||||
* @param {Mixed} el
|
||||
* @param {Object} config
|
||||
*/
|
||||
constructor : function(el, config) {
|
||||
config = config || {};
|
||||
Ext.apply(this, config);
|
||||
|
||||
this.addEvents(
|
||||
/**
|
||||
* @event sortstart
|
||||
* @param {Ext.Sortable} this
|
||||
* @param {Ext.event.Event} e
|
||||
*/
|
||||
'sortstart',
|
||||
/**
|
||||
* @event sortend
|
||||
* @param {Ext.Sortable} this
|
||||
* @param {Ext.event.Event} e
|
||||
*/
|
||||
'sortend',
|
||||
/**
|
||||
* @event sortchange
|
||||
* @param {Ext.Sortable} this
|
||||
* @param {Ext.Element} el The Element being dragged.
|
||||
* @param {Number} index The index of the element after the sort change.
|
||||
*/
|
||||
'sortchange'
|
||||
|
||||
// not yet implemented.
|
||||
// 'sortupdate',
|
||||
// 'sortreceive',
|
||||
// 'sortremove',
|
||||
// 'sortenter',
|
||||
// 'sortleave',
|
||||
// 'sortactivate',
|
||||
// 'sortdeactivate'
|
||||
);
|
||||
|
||||
this.el = Ext.get(el);
|
||||
this.callParent();
|
||||
|
||||
this.mixins.observable.constructor.call(this);
|
||||
|
||||
if (this.direction == 'horizontal') {
|
||||
this.horizontal = true;
|
||||
}
|
||||
else if (this.direction == 'vertical') {
|
||||
this.vertical = true;
|
||||
}
|
||||
else {
|
||||
this.horizontal = this.vertical = true;
|
||||
}
|
||||
|
||||
this.el.addCls(this.baseCls);
|
||||
this.startEventName = (this.getDelay() > 0) ? 'taphold' : 'tapstart';
|
||||
if (!this.disabled) {
|
||||
this.enable();
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
onStart : function(e, t) {
|
||||
if (this.cancelSelector && e.getTarget(this.cancelSelector)) {
|
||||
return;
|
||||
}
|
||||
if (this.handleSelector && !e.getTarget(this.handleSelector)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.sorting) {
|
||||
this.onSortStart(e, t);
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
onSortStart : function(e, t) {
|
||||
this.sorting = true;
|
||||
var draggable = Ext.create('Ext.util.Draggable', t, {
|
||||
threshold: 0,
|
||||
revert: this.revert,
|
||||
direction: this.direction,
|
||||
constrain: this.constrain === true ? this.el : this.constrain,
|
||||
animationDuration: 100
|
||||
});
|
||||
draggable.on({
|
||||
drag: this.onDrag,
|
||||
dragend: this.onDragEnd,
|
||||
scope: this
|
||||
});
|
||||
|
||||
this.dragEl = t;
|
||||
this.calculateBoxes();
|
||||
|
||||
if (!draggable.dragging) {
|
||||
draggable.onStart(e);
|
||||
}
|
||||
|
||||
this.fireEvent('sortstart', this, e);
|
||||
},
|
||||
|
||||
// @private
|
||||
calculateBoxes : function() {
|
||||
this.items = [];
|
||||
var els = this.el.select(this.itemSelector, false),
|
||||
ln = els.length, i, item, el, box;
|
||||
|
||||
for (i = 0; i < ln; i++) {
|
||||
el = els[i];
|
||||
if (el != this.dragEl) {
|
||||
item = Ext.fly(el).getPageBox(true);
|
||||
item.el = el;
|
||||
this.items.push(item);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
onDrag : function(draggable, e) {
|
||||
var items = this.items,
|
||||
ln = items.length,
|
||||
region = draggable.region,
|
||||
sortChange = false,
|
||||
i, intersect, overlap, item;
|
||||
|
||||
for (i = 0; i < ln; i++) {
|
||||
item = items[i];
|
||||
intersect = region.intersect(item);
|
||||
if (intersect) {
|
||||
if (this.vertical && Math.abs(intersect.top - intersect.bottom) > (region.bottom - region.top) / 2) {
|
||||
if (region.bottom > item.top && item.top > region.top) {
|
||||
draggable.el.insertAfter(item.el);
|
||||
}
|
||||
else {
|
||||
draggable.el.insertBefore(item.el);
|
||||
}
|
||||
sortChange = true;
|
||||
}
|
||||
else if (this.horizontal && Math.abs(intersect.left - intersect.right) > (region.right - region.left) / 2) {
|
||||
if (region.right > item.left && item.left > region.left) {
|
||||
draggable.el.insertAfter(item.el);
|
||||
}
|
||||
else {
|
||||
draggable.el.insertBefore(item.el);
|
||||
}
|
||||
sortChange = true;
|
||||
}
|
||||
|
||||
if (sortChange) {
|
||||
// We reset the draggable (initializes all the new start values)
|
||||
draggable.reset();
|
||||
|
||||
// Move the draggable to its current location (since the transform is now
|
||||
// different)
|
||||
draggable.moveTo(region.left, region.top);
|
||||
|
||||
// Finally lets recalculate all the items boxes
|
||||
this.calculateBoxes();
|
||||
this.fireEvent('sortchange', this, draggable.el, this.el.select(this.itemSelector, false).indexOf(draggable.el.dom));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// @private
|
||||
onDragEnd : function(draggable, e) {
|
||||
draggable.destroy();
|
||||
this.sorting = false;
|
||||
this.fireEvent('sortend', this, draggable, e);
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables sorting for this Sortable.
|
||||
* This method is invoked immediately after construction of a Sortable unless
|
||||
* the disabled configuration is set to `true`.
|
||||
*/
|
||||
enable : function() {
|
||||
this.el.on(this.startEventName, this.onStart, this, {delegate: this.itemSelector, holdThreshold: this.getDelay()});
|
||||
this.disabled = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables sorting for this Sortable.
|
||||
*/
|
||||
disable : function() {
|
||||
this.el.un(this.startEventName, this.onStart, this);
|
||||
this.disabled = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to determine whether this Sortable is currently disabled.
|
||||
* @return {Boolean} The disabled state of this Sortable.
|
||||
*/
|
||||
isDisabled: function() {
|
||||
return this.disabled;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to determine whether this Sortable is currently sorting.
|
||||
* @return {Boolean} The sorting state of this Sortable.
|
||||
*/
|
||||
isSorting : function() {
|
||||
return this.sorting;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to determine whether this Sortable is currently disabled.
|
||||
* @return {Boolean} The disabled state of this Sortable.
|
||||
*/
|
||||
isVertical : function() {
|
||||
return this.vertical;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to determine whether this Sortable is currently sorting.
|
||||
* @return {Boolean} The sorting state of this Sortable.
|
||||
*/
|
||||
isHorizontal : function() {
|
||||
return this.horizontal;
|
||||
}
|
||||
});
|
||||
144
OfficeWeb/3rdparty/touch/src/Spacer.js
vendored
Normal file
144
OfficeWeb/3rdparty/touch/src/Spacer.js
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
The {@link Ext.Spacer} component is generally used to put space between items in {@link Ext.Toolbar} components.
|
||||
|
||||
## Examples
|
||||
|
||||
By default the {@link #flex} configuration is set to 1:
|
||||
|
||||
@example miniphone preview
|
||||
Ext.create('Ext.Container', {
|
||||
fullscreen: true,
|
||||
items: [
|
||||
{
|
||||
xtype : 'toolbar',
|
||||
docked: 'top',
|
||||
items: [
|
||||
{
|
||||
xtype: 'button',
|
||||
text : 'Button One'
|
||||
},
|
||||
{
|
||||
xtype: 'spacer'
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
text : 'Button Two'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
Alternatively you can just set the {@link #width} configuration which will get the {@link Ext.Spacer} a fixed width:
|
||||
|
||||
@example preview
|
||||
Ext.create('Ext.Container', {
|
||||
fullscreen: true,
|
||||
layout: {
|
||||
type: 'vbox',
|
||||
pack: 'center',
|
||||
align: 'stretch'
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype : 'toolbar',
|
||||
docked: 'top',
|
||||
items: [
|
||||
{
|
||||
xtype: 'button',
|
||||
text : 'Button One'
|
||||
},
|
||||
{
|
||||
xtype: 'spacer',
|
||||
width: 50
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
text : 'Button Two'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
xtype: 'container',
|
||||
items: [
|
||||
{
|
||||
xtype: 'button',
|
||||
text : 'Change Ext.Spacer width',
|
||||
handler: function() {
|
||||
//get the spacer using ComponentQuery
|
||||
var spacer = Ext.ComponentQuery.query('spacer')[0],
|
||||
from = 10,
|
||||
to = 250;
|
||||
|
||||
//set the width to a random number
|
||||
spacer.setWidth(Math.floor(Math.random() * (to - from + 1) + from));
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
You can also insert multiple {@link Ext.Spacer}'s:
|
||||
|
||||
@example preview
|
||||
Ext.create('Ext.Container', {
|
||||
fullscreen: true,
|
||||
items: [
|
||||
{
|
||||
xtype : 'toolbar',
|
||||
docked: 'top',
|
||||
items: [
|
||||
{
|
||||
xtype: 'button',
|
||||
text : 'Button One'
|
||||
},
|
||||
{
|
||||
xtype: 'spacer'
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
text : 'Button Two'
|
||||
},
|
||||
{
|
||||
xtype: 'spacer',
|
||||
width: 20
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
text : 'Button Three'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
*/
|
||||
Ext.define('Ext.Spacer', {
|
||||
extend: 'Ext.Component',
|
||||
alias : 'widget.spacer',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Number} flex
|
||||
* The flex value of this spacer. This defaults to 1, if no width has been set.
|
||||
* @accessor
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {Number} width
|
||||
* The width of this spacer. If this is set, the value of {@link #flex} will be ignored.
|
||||
* @accessor
|
||||
*/
|
||||
},
|
||||
|
||||
// @private
|
||||
constructor: function(config) {
|
||||
config = config || {};
|
||||
|
||||
if (!config.width) {
|
||||
config.flex = 1;
|
||||
}
|
||||
|
||||
this.callParent([config]);
|
||||
}
|
||||
});
|
||||
120
OfficeWeb/3rdparty/touch/src/TaskQueue.js
vendored
Normal file
120
OfficeWeb/3rdparty/touch/src/TaskQueue.js
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
(function() {
|
||||
var lastTime = 0,
|
||||
vendors = ['ms', 'moz', 'webkit', 'o'],
|
||||
ln = vendors.length,
|
||||
i, vendor;
|
||||
|
||||
for (i = 0; i < ln && !window.requestAnimationFrame; ++i) {
|
||||
vendor = vendors[i];
|
||||
window.requestAnimationFrame = window[vendor + 'RequestAnimationFrame'];
|
||||
window.cancelAnimationFrame = window[vendor + 'CancelAnimationFrame'] || window[vendor + 'CancelRequestAnimationFrame'];
|
||||
}
|
||||
|
||||
if (!window.requestAnimationFrame) {
|
||||
window.requestAnimationFrame = function(callback, element) {
|
||||
var currTime = new Date().getTime(),
|
||||
timeToCall = Math.max(0, 16 - (currTime - lastTime)),
|
||||
id = window.setTimeout(function() {
|
||||
callback(currTime + timeToCall);
|
||||
}, timeToCall);
|
||||
lastTime = currTime + timeToCall;
|
||||
return id;
|
||||
};
|
||||
}
|
||||
|
||||
if (!window.cancelAnimationFrame) {
|
||||
window.cancelAnimationFrame = function(id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
}
|
||||
}());
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Handle batch read / write of DOMs, currently used in SizeMonitor + PaintMonitor
|
||||
*/
|
||||
Ext.define('Ext.TaskQueue', {
|
||||
singleton: true,
|
||||
|
||||
pending: false,
|
||||
|
||||
mode: true,
|
||||
|
||||
constructor: function() {
|
||||
this.readQueue = [];
|
||||
this.writeQueue = [];
|
||||
|
||||
this.run = Ext.Function.bind(this.run, this);
|
||||
},
|
||||
|
||||
requestRead: function(fn, scope, args) {
|
||||
this.request(true);
|
||||
this.readQueue.push(arguments);
|
||||
},
|
||||
|
||||
requestWrite: function(fn, scope, args) {
|
||||
this.request(false);
|
||||
this.writeQueue.push(arguments);
|
||||
},
|
||||
|
||||
request: function(mode) {
|
||||
if (!this.pending) {
|
||||
this.pending = true;
|
||||
this.mode = mode;
|
||||
|
||||
requestAnimationFrame(this.run);
|
||||
}
|
||||
},
|
||||
|
||||
run: function() {
|
||||
this.pending = false;
|
||||
|
||||
var readQueue = this.readQueue,
|
||||
writeQueue = this.writeQueue,
|
||||
request = null,
|
||||
queue;
|
||||
|
||||
if (this.mode) {
|
||||
queue = readQueue;
|
||||
|
||||
if (writeQueue.length > 0) {
|
||||
request = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
queue = writeQueue;
|
||||
|
||||
if (readQueue.length > 0) {
|
||||
request = true;
|
||||
}
|
||||
}
|
||||
|
||||
var tasks = queue.slice(),
|
||||
i, ln, task, fn, scope;
|
||||
|
||||
queue.length = 0;
|
||||
|
||||
for (i = 0, ln = tasks.length; i < ln; i++) {
|
||||
task = tasks[i];
|
||||
fn = task[0];
|
||||
scope = task[1];
|
||||
|
||||
if (typeof fn == 'string') {
|
||||
fn = scope[fn];
|
||||
}
|
||||
|
||||
if (task.length > 2) {
|
||||
fn.apply(scope, task[2]);
|
||||
}
|
||||
else {
|
||||
fn.call(scope);
|
||||
}
|
||||
}
|
||||
|
||||
tasks.length = 0;
|
||||
|
||||
if (request !== null) {
|
||||
this.request(request);
|
||||
}
|
||||
}
|
||||
});
|
||||
329
OfficeWeb/3rdparty/touch/src/Template.js
vendored
Normal file
329
OfficeWeb/3rdparty/touch/src/Template.js
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
/**
|
||||
* 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.dom.Helper', '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 = {};
|
||||
|
||||
// Allow an array to be passed here so we can
|
||||
// pass an array of strings and an object
|
||||
// at the end
|
||||
if (length === 1 && Ext.isArray(html)) {
|
||||
args = html;
|
||||
length = args.length;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buffer.push(html);
|
||||
}
|
||||
|
||||
// @private
|
||||
me.html = buffer.join('');
|
||||
|
||||
if (me.compiled) {
|
||||
me.compile();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @property {Boolean} isTemplate
|
||||
* `true` in this class to identify an object as an instantiated Template, or subclass thereof.
|
||||
*/
|
||||
isTemplate: true,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} [compiled=false]
|
||||
* `true` to immediately compile the template.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} [disableFormats=false]
|
||||
* `true` to disable format functions in the template. If the template doesn't contain
|
||||
* format functions, setting `disableFormats` to `true` will reduce apply time.
|
||||
*/
|
||||
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.apply(['John', 25]);
|
||||
*
|
||||
* or an object:
|
||||
*
|
||||
* var tpl = new Ext.Template('Name: {name}, Age: {age}');
|
||||
* tpl.apply({name: 'John', age: 25});
|
||||
*
|
||||
* @return {String} The HTML fragment.
|
||||
*/
|
||||
apply: function(values) {
|
||||
var me = this,
|
||||
useFormat = me.disableFormats !== true,
|
||||
fm = Ext.util.Format,
|
||||
tpl = me,
|
||||
ret;
|
||||
|
||||
if (me.compiled) {
|
||||
return me.compiled(values).join('');
|
||||
}
|
||||
|
||||
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] : "";
|
||||
}
|
||||
}
|
||||
|
||||
ret = me.html.replace(me.re, fn);
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
* Appends the result of this template to the provided output array.
|
||||
* @param {Object/Array} values The template values. See {@link #apply}.
|
||||
* @param {Array} out The array to which output is pushed.
|
||||
* @return {Array} The given out array.
|
||||
*/
|
||||
applyOut: function(values, out) {
|
||||
var me = this;
|
||||
|
||||
if (me.compiled) {
|
||||
out.push.apply(out, me.compiled(values));
|
||||
} else {
|
||||
out.push(me.apply(values));
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
/**
|
||||
* @method applyTemplate
|
||||
* @member Ext.Template
|
||||
* Alias for {@link #apply}.
|
||||
* @inheritdoc Ext.Template#apply
|
||||
*/
|
||||
applyTemplate: function () {
|
||||
return this.apply.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 + "'];};";
|
||||
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 an 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, returnElement) {
|
||||
var newNode = Ext.DomHelper.insertHtml(where, Ext.getDom(el), this.apply(values));
|
||||
return returnElement ? Ext.get(newNode) : 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) {
|
||||
var newNode = Ext.DomHelper.overwrite(Ext.getDom(el), this.apply(values));
|
||||
return returnElement ? Ext.get(newNode) : newNode;
|
||||
}
|
||||
});
|
||||
26
OfficeWeb/3rdparty/touch/src/Title.js
vendored
Normal file
26
OfficeWeb/3rdparty/touch/src/Title.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* {@link Ext.Title} is used for the {@link Ext.Toolbar#title} configuration in the {@link Ext.Toolbar} component.
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.Title', {
|
||||
extend: 'Ext.Component',
|
||||
xtype: 'title',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: 'x-title',
|
||||
|
||||
/**
|
||||
* @cfg {String} title The title text
|
||||
*/
|
||||
title: ''
|
||||
},
|
||||
|
||||
// @private
|
||||
updateTitle: function(newTitle) {
|
||||
this.setHtml(newTitle);
|
||||
}
|
||||
});
|
||||
331
OfficeWeb/3rdparty/touch/src/TitleBar.js
vendored
Normal file
331
OfficeWeb/3rdparty/touch/src/TitleBar.js
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
/**
|
||||
* {@link Ext.TitleBar}'s are most commonly used as a docked item within an {@link Ext.Container}.
|
||||
*
|
||||
* The main difference between a {@link Ext.TitleBar} and an {@link Ext.Toolbar} is that
|
||||
* the {@link #title} configuration is **always** centered horizontally in a {@link Ext.TitleBar} between
|
||||
* any items aligned left or right.
|
||||
*
|
||||
* You can also give items of a {@link Ext.TitleBar} an `align` configuration of `left` or `right`
|
||||
* which will dock them to the `left` or `right` of the bar.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* @example preview
|
||||
* Ext.Viewport.add({
|
||||
* xtype: 'titlebar',
|
||||
* docked: 'top',
|
||||
* title: 'Navigation',
|
||||
* items: [
|
||||
* {
|
||||
* iconCls: 'add',
|
||||
* iconMask: true,
|
||||
* align: 'left'
|
||||
* },
|
||||
* {
|
||||
* iconCls: 'home',
|
||||
* iconMask: true,
|
||||
* align: 'right'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* Ext.Viewport.setStyleHtmlContent(true);
|
||||
* Ext.Viewport.setHtml('This shows the title being centered and buttons using align <i>left</i> and <i>right</i>.');
|
||||
*
|
||||
* <br />
|
||||
*
|
||||
* @example preview
|
||||
* Ext.Viewport.add({
|
||||
* xtype: 'titlebar',
|
||||
* docked: 'top',
|
||||
* title: 'Navigation',
|
||||
* items: [
|
||||
* {
|
||||
* align: 'left',
|
||||
* text: 'This button has a super long title'
|
||||
* },
|
||||
* {
|
||||
* iconCls: 'home',
|
||||
* iconMask: true,
|
||||
* align: 'right'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* Ext.Viewport.setStyleHtmlContent(true);
|
||||
* Ext.Viewport.setHtml('This shows how the title is automatically moved to the right when one of the aligned buttons is very wide.');
|
||||
*
|
||||
* <br />
|
||||
*
|
||||
* @example preview
|
||||
* Ext.Viewport.add({
|
||||
* xtype: 'titlebar',
|
||||
* docked: 'top',
|
||||
* title: 'A very long title',
|
||||
* items: [
|
||||
* {
|
||||
* align: 'left',
|
||||
* text: 'This button has a super long title'
|
||||
* },
|
||||
* {
|
||||
* align: 'right',
|
||||
* text: 'Another button'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* Ext.Viewport.setStyleHtmlContent(true);
|
||||
* Ext.Viewport.setHtml('This shows how the title and buttons will automatically adjust their size when the width of the items are too wide..');
|
||||
*
|
||||
* The {@link #defaultType} of Toolbar's is {@link Ext.Button button}.
|
||||
*/
|
||||
Ext.define('Ext.TitleBar', {
|
||||
extend: 'Ext.Container',
|
||||
xtype: 'titlebar',
|
||||
|
||||
requires: [
|
||||
'Ext.Button',
|
||||
'Ext.Title',
|
||||
'Ext.Spacer'
|
||||
],
|
||||
|
||||
// @private
|
||||
isToolbar: true,
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: Ext.baseCSSPrefix + 'toolbar',
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
cls: Ext.baseCSSPrefix + 'navigation-bar',
|
||||
|
||||
/**
|
||||
* @cfg {String} ui
|
||||
* Style options for Toolbar. Either 'light' or 'dark'.
|
||||
* @accessor
|
||||
*/
|
||||
ui: 'dark',
|
||||
|
||||
/**
|
||||
* @cfg {String} title
|
||||
* The title of the toolbar.
|
||||
* @accessor
|
||||
*/
|
||||
title: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} defaultType
|
||||
* The default xtype to create.
|
||||
* @accessor
|
||||
*/
|
||||
defaultType: 'button',
|
||||
|
||||
height: '2.6em',
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @hide
|
||||
*/
|
||||
layout: {
|
||||
type: 'hbox'
|
||||
},
|
||||
|
||||
/**
|
||||
* @cfg {Array/Object} items The child items to add to this TitleBar. The {@link #defaultType} of
|
||||
* a TitleBar is {@link Ext.Button}, so you do not need to specify an `xtype` if you are adding
|
||||
* buttons.
|
||||
*
|
||||
* You can also give items a `align` configuration which will align the item to the `left` or `right` of
|
||||
* the TitleBar.
|
||||
* @accessor
|
||||
*/
|
||||
items: []
|
||||
},
|
||||
|
||||
/**
|
||||
* The max button width in this toolbar
|
||||
* @private
|
||||
*/
|
||||
maxButtonWidth: '40%',
|
||||
|
||||
constructor: function() {
|
||||
this.refreshTitlePosition = Ext.Function.createThrottled(this.refreshTitlePosition, 50, this);
|
||||
|
||||
this.callParent(arguments);
|
||||
},
|
||||
|
||||
beforeInitialize: function() {
|
||||
this.applyItems = this.applyInitialItems;
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
delete this.applyItems;
|
||||
|
||||
this.add(this.initialItems);
|
||||
delete this.initialItems;
|
||||
|
||||
this.on({
|
||||
painted: 'refreshTitlePosition',
|
||||
single: true
|
||||
});
|
||||
},
|
||||
|
||||
applyInitialItems: function(items) {
|
||||
var me = this,
|
||||
defaults = me.getDefaults() || {};
|
||||
|
||||
me.initialItems = items;
|
||||
|
||||
me.leftBox = me.add({
|
||||
xtype: 'container',
|
||||
style: 'position: relative',
|
||||
layout: {
|
||||
type: 'hbox',
|
||||
align: 'center'
|
||||
},
|
||||
listeners: {
|
||||
resize: 'refreshTitlePosition',
|
||||
scope: me
|
||||
}
|
||||
});
|
||||
|
||||
me.spacer = me.add({
|
||||
xtype: 'component',
|
||||
style: 'position: relative',
|
||||
flex: 1,
|
||||
listeners: {
|
||||
resize: 'refreshTitlePosition',
|
||||
scope: me
|
||||
}
|
||||
});
|
||||
|
||||
me.rightBox = me.add({
|
||||
xtype: 'container',
|
||||
style: 'position: relative',
|
||||
layout: {
|
||||
type: 'hbox',
|
||||
align: 'center'
|
||||
},
|
||||
listeners: {
|
||||
resize: 'refreshTitlePosition',
|
||||
scope: me
|
||||
}
|
||||
});
|
||||
|
||||
me.titleComponent = me.add({
|
||||
xtype: 'title',
|
||||
hidden: defaults.hidden,
|
||||
centered: true
|
||||
});
|
||||
|
||||
me.doAdd = me.doBoxAdd;
|
||||
me.remove = me.doBoxRemove;
|
||||
me.doInsert = me.doBoxInsert;
|
||||
},
|
||||
|
||||
doBoxAdd: function(item) {
|
||||
if (item.config.align == 'right') {
|
||||
this.rightBox.add(item);
|
||||
}
|
||||
else {
|
||||
this.leftBox.add(item);
|
||||
}
|
||||
},
|
||||
|
||||
doBoxRemove: function(item) {
|
||||
if (item.config.align == 'right') {
|
||||
this.rightBox.remove(item);
|
||||
}
|
||||
else {
|
||||
this.leftBox.remove(item);
|
||||
}
|
||||
},
|
||||
|
||||
doBoxInsert: function(index, item) {
|
||||
if (item.config.align == 'right') {
|
||||
this.rightBox.add(item);
|
||||
}
|
||||
else {
|
||||
this.leftBox.add(item);
|
||||
}
|
||||
},
|
||||
|
||||
getMaxButtonWidth: function() {
|
||||
var value = this.maxButtonWidth;
|
||||
|
||||
//check if it is a percentage
|
||||
if (Ext.isString(this.maxButtonWidth)) {
|
||||
value = parseInt(value.replace('%', ''), 10);
|
||||
value = Math.round((this.element.getWidth() / 100) * value);
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
refreshTitlePosition: function() {
|
||||
var titleElement = this.titleComponent.renderElement;
|
||||
|
||||
titleElement.setWidth(null);
|
||||
titleElement.setLeft(null);
|
||||
|
||||
//set the min/max width of the left button
|
||||
var leftBox = this.leftBox,
|
||||
leftButton = leftBox.down('button'),
|
||||
singleButton = leftBox.getItems().getCount() == 1,
|
||||
leftBoxWidth, maxButtonWidth;
|
||||
|
||||
if (leftButton && singleButton) {
|
||||
if (leftButton.getWidth() == null) {
|
||||
leftButton.renderElement.setWidth('auto');
|
||||
}
|
||||
|
||||
leftBoxWidth = leftBox.renderElement.getWidth();
|
||||
maxButtonWidth = this.getMaxButtonWidth();
|
||||
|
||||
if (leftBoxWidth > maxButtonWidth) {
|
||||
leftButton.renderElement.setWidth(maxButtonWidth);
|
||||
}
|
||||
}
|
||||
|
||||
var spacerBox = this.spacer.renderElement.getPageBox(),
|
||||
titleBox = titleElement.getPageBox(),
|
||||
widthDiff = titleBox.width - spacerBox.width,
|
||||
titleLeft = titleBox.left,
|
||||
titleRight = titleBox.right,
|
||||
halfWidthDiff, leftDiff, rightDiff;
|
||||
|
||||
if (widthDiff > 0) {
|
||||
titleElement.setWidth(spacerBox.width);
|
||||
halfWidthDiff = widthDiff / 2;
|
||||
titleLeft += halfWidthDiff;
|
||||
titleRight -= halfWidthDiff;
|
||||
}
|
||||
|
||||
leftDiff = spacerBox.left - titleLeft;
|
||||
rightDiff = titleRight - spacerBox.right;
|
||||
|
||||
if (leftDiff > 0) {
|
||||
titleElement.setLeft(leftDiff);
|
||||
}
|
||||
else if (rightDiff > 0) {
|
||||
titleElement.setLeft(-rightDiff);
|
||||
}
|
||||
|
||||
titleElement.repaint();
|
||||
},
|
||||
|
||||
// @private
|
||||
updateTitle: function(newTitle) {
|
||||
this.titleComponent.setTitle(newTitle);
|
||||
|
||||
if (this.isPainted()) {
|
||||
this.refreshTitlePosition();
|
||||
}
|
||||
}
|
||||
});
|
||||
260
OfficeWeb/3rdparty/touch/src/Toolbar.js
vendored
Normal file
260
OfficeWeb/3rdparty/touch/src/Toolbar.js
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* @aside video tabs-toolbars
|
||||
*
|
||||
* {@link Ext.Toolbar}s are most commonly used as docked items as within a {@link Ext.Container}. They can be docked either `top` or `bottom` using the {@link #docked} configuration.
|
||||
*
|
||||
* They allow you to insert items (normally {@link Ext.Button buttons}) and also add a {@link #title}.
|
||||
*
|
||||
* The {@link #defaultType} of {@link Ext.Toolbar} is {@link Ext.Button}.
|
||||
*
|
||||
* You can alternatively use {@link Ext.TitleBar} if you want the title to automatically adjust the size of its items.
|
||||
*
|
||||
* ## Examples
|
||||
*
|
||||
* @example miniphone preview
|
||||
* Ext.create('Ext.Container', {
|
||||
* fullscreen: true,
|
||||
* layout: {
|
||||
* type: 'vbox',
|
||||
* pack: 'center'
|
||||
* },
|
||||
* items: [
|
||||
* {
|
||||
* xtype : 'toolbar',
|
||||
* docked: 'top',
|
||||
* title: 'My Toolbar'
|
||||
* },
|
||||
* {
|
||||
* xtype: 'container',
|
||||
* defaults: {
|
||||
* xtype: 'button',
|
||||
* margin: '10 10 0 10'
|
||||
* },
|
||||
* items: [
|
||||
* {
|
||||
* text: 'Toggle docked',
|
||||
* handler: function() {
|
||||
* var toolbar = Ext.ComponentQuery.query('toolbar')[0],
|
||||
* newDocked = (toolbar.getDocked() === 'top') ? 'bottom' : 'top';
|
||||
*
|
||||
* toolbar.setDocked(newDocked);
|
||||
* }
|
||||
* },
|
||||
* {
|
||||
* text: 'Toggle UI',
|
||||
* handler: function() {
|
||||
* var toolbar = Ext.ComponentQuery.query('toolbar')[0],
|
||||
* newUi = (toolbar.getUi() === 'light') ? 'dark' : 'light';
|
||||
*
|
||||
* toolbar.setUi(newUi);
|
||||
* }
|
||||
* },
|
||||
* {
|
||||
* text: 'Change title',
|
||||
* handler: function() {
|
||||
* var toolbar = Ext.ComponentQuery.query('toolbar')[0],
|
||||
* titles = ['My Toolbar', 'Ext.Toolbar', 'Configurations are awesome!', 'Beautiful.'],
|
||||
//internally, the title configuration gets converted into a {@link Ext.Title} component,
|
||||
//so you must get the title configuration of that component
|
||||
* title = toolbar.getTitle().getTitle(),
|
||||
* newTitle = titles[titles.indexOf(title) + 1] || titles[0];
|
||||
*
|
||||
* toolbar.setTitle(newTitle);
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* ## Notes
|
||||
*
|
||||
* You must use a HTML5 doctype for {@link #docked} `bottom` to work. To do this, simply add the following code to the HTML file:
|
||||
*
|
||||
* <!doctype html>
|
||||
*
|
||||
* So your index.html file should look a little like this:
|
||||
*
|
||||
* <!doctype html>
|
||||
* <html>
|
||||
* <head>
|
||||
* <title>MY application title</title>
|
||||
* ...
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.Toolbar', {
|
||||
extend: 'Ext.Container',
|
||||
xtype : 'toolbar',
|
||||
|
||||
requires: [
|
||||
'Ext.Button',
|
||||
'Ext.Title',
|
||||
'Ext.Spacer',
|
||||
'Ext.layout.HBox'
|
||||
],
|
||||
|
||||
// @private
|
||||
isToolbar: true,
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg baseCls
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: Ext.baseCSSPrefix + 'toolbar',
|
||||
|
||||
/**
|
||||
* @cfg {String} ui
|
||||
* The ui for this {@link Ext.Toolbar}. Either 'light' or 'dark'. You can create more UIs by using using the CSS Mixin {@link #sencha-toolbar-ui}
|
||||
* @accessor
|
||||
*/
|
||||
ui: 'dark',
|
||||
|
||||
/**
|
||||
* @cfg {String/Ext.Title} title
|
||||
* The title of the toolbar.
|
||||
* @accessor
|
||||
*/
|
||||
title: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} defaultType
|
||||
* The default xtype to create.
|
||||
* @accessor
|
||||
*/
|
||||
defaultType: 'button',
|
||||
|
||||
/**
|
||||
* @cfg {String} docked
|
||||
* The docked position for this {@link Ext.Toolbar}.
|
||||
* If you specify `left` or `right`, the {@link #layout} configuration will automatically change to a `vbox`. It's also
|
||||
* recommended to adjust the {@link #width} of the toolbar if you do this.
|
||||
* @accessor
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {String} minHeight
|
||||
* The minimum height height of the Toolbar.
|
||||
* @accessor
|
||||
*/
|
||||
minHeight: '2.6em',
|
||||
|
||||
/**
|
||||
* @cfg {Object/String} layout Configuration for this Container's layout. Example:
|
||||
*
|
||||
* Ext.create('Ext.Container', {
|
||||
* layout: {
|
||||
* type: 'hbox',
|
||||
* align: 'middle'
|
||||
* },
|
||||
* items: [
|
||||
* {
|
||||
* xtype: 'panel',
|
||||
* flex: 1,
|
||||
* style: 'background-color: red;'
|
||||
* },
|
||||
* {
|
||||
* xtype: 'panel',
|
||||
* flex: 2,
|
||||
* style: 'background-color: green'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* See the [layouts guide](#!/guides/layouts) for more information
|
||||
*
|
||||
* __Note:__ If you set the {@link #docked} configuration to `left` or `right`, the default layout will change from the
|
||||
* `hbox` to a `vbox`.
|
||||
*
|
||||
* @accessor
|
||||
*/
|
||||
layout: {
|
||||
type: 'hbox',
|
||||
align: 'center'
|
||||
}
|
||||
},
|
||||
|
||||
constructor: function(config) {
|
||||
config = config || {};
|
||||
|
||||
if (config.docked == "left" || config.docked == "right") {
|
||||
config.layout = {
|
||||
type: 'vbox',
|
||||
align: 'stretch'
|
||||
};
|
||||
}
|
||||
|
||||
this.callParent([config]);
|
||||
},
|
||||
|
||||
// @private
|
||||
applyTitle: function(title) {
|
||||
if (typeof title == 'string') {
|
||||
title = {
|
||||
title: title,
|
||||
centered: true
|
||||
};
|
||||
}
|
||||
|
||||
return Ext.factory(title, Ext.Title, this.getTitle());
|
||||
},
|
||||
|
||||
// @private
|
||||
updateTitle: function(newTitle, oldTitle) {
|
||||
if (newTitle) {
|
||||
this.add(newTitle);
|
||||
}
|
||||
|
||||
if (oldTitle) {
|
||||
oldTitle.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the title, if it exists.
|
||||
*/
|
||||
showTitle: function() {
|
||||
var title = this.getTitle();
|
||||
|
||||
if (title) {
|
||||
title.show();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides the title, if it exists.
|
||||
*/
|
||||
hideTitle: function() {
|
||||
var title = this.getTitle();
|
||||
|
||||
if (title) {
|
||||
title.hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link Ext.Title} component.
|
||||
* @member Ext.Toolbar
|
||||
* @method getTitle
|
||||
* @return {Ext.Title}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Use this to update the {@link #title} configuration.
|
||||
* @member Ext.Toolbar
|
||||
* @method setTitle
|
||||
* @param {String/Ext.Title} title You can either pass a String, or a config/instance of {@link Ext.Title}.
|
||||
*/
|
||||
|
||||
}, function() {
|
||||
//<deprecated product=touch since=2.0>
|
||||
/**
|
||||
* @member Ext.Toolbar
|
||||
* @cfg {Boolean} titleCls
|
||||
* The CSS class to apply to the `titleEl`.
|
||||
* @removed 2.0.0 Title class is now a config option of the title
|
||||
*/
|
||||
Ext.deprecateProperty(this, 'titleCls', null, "Ext.Toolbar.titleCls has been removed. Use #cls config of title instead.");
|
||||
//</deprecated>
|
||||
});
|
||||
|
||||
195
OfficeWeb/3rdparty/touch/src/Video.js
vendored
Normal file
195
OfficeWeb/3rdparty/touch/src/Video.js
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* @aside example video
|
||||
* Provides a simple Container for HTML5 Video.
|
||||
*
|
||||
* ## Notes
|
||||
*
|
||||
* - There are quite a few issues with the `<video>` tag on Android devices. On Android 2+, the video will
|
||||
* appear and play on first attempt, but any attempt afterwards will not work.
|
||||
*
|
||||
* ## Useful Properties
|
||||
*
|
||||
* - {@link #url}
|
||||
* - {@link #autoPause}
|
||||
* - {@link #autoResume}
|
||||
*
|
||||
* ## Useful Methods
|
||||
*
|
||||
* - {@link #method-pause}
|
||||
* - {@link #method-play}
|
||||
* - {@link #toggle}
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* var panel = Ext.create('Ext.Panel', {
|
||||
* fullscreen: true,
|
||||
* items: [
|
||||
* {
|
||||
* xtype : 'video',
|
||||
* x : 600,
|
||||
* y : 300,
|
||||
* width : 175,
|
||||
* height : 98,
|
||||
* url : "porsche911.mov",
|
||||
* posterUrl: 'porsche.png'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*/
|
||||
Ext.define('Ext.Video', {
|
||||
extend: 'Ext.Media',
|
||||
xtype: 'video',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String/Array} urls
|
||||
* Location of the video to play. This should be in H.264 format and in a .mov file format.
|
||||
* @accessor
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {String} posterUrl
|
||||
* Location of a poster image to be shown before showing the video.
|
||||
* @accessor
|
||||
*/
|
||||
posterUrl: null,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
cls: Ext.baseCSSPrefix + 'video'
|
||||
},
|
||||
|
||||
template: [{
|
||||
/**
|
||||
* @property {Ext.dom.Element} ghost
|
||||
* @private
|
||||
*/
|
||||
reference: 'ghost',
|
||||
classList: [Ext.baseCSSPrefix + 'video-ghost']
|
||||
}, {
|
||||
tag: 'video',
|
||||
reference: 'media',
|
||||
classList: [Ext.baseCSSPrefix + 'media']
|
||||
}],
|
||||
|
||||
initialize: function() {
|
||||
var me = this;
|
||||
|
||||
me.callParent();
|
||||
|
||||
me.media.hide();
|
||||
|
||||
me.onBefore({
|
||||
erased: 'onErased',
|
||||
scope: me
|
||||
});
|
||||
|
||||
me.ghost.on({
|
||||
tap: 'onGhostTap',
|
||||
scope: me
|
||||
});
|
||||
|
||||
me.media.on({
|
||||
pause: 'onPause',
|
||||
scope: me
|
||||
});
|
||||
|
||||
if (Ext.os.is.Android4 || Ext.os.is.iPad) {
|
||||
this.isInlineVideo = true;
|
||||
}
|
||||
},
|
||||
|
||||
applyUrl: function(url) {
|
||||
return [].concat(url);
|
||||
},
|
||||
|
||||
updateUrl: function(newUrl) {
|
||||
var me = this,
|
||||
media = me.media,
|
||||
newLn = newUrl.length,
|
||||
existingSources = media.query('source'),
|
||||
oldLn = existingSources.length,
|
||||
i;
|
||||
|
||||
|
||||
for (i = 0; i < oldLn; i++) {
|
||||
Ext.fly(existingSources[i]).destroy();
|
||||
}
|
||||
|
||||
for (i = 0; i < newLn; i++) {
|
||||
media.appendChild(Ext.Element.create({
|
||||
tag: 'source',
|
||||
src: newUrl[i]
|
||||
}));
|
||||
}
|
||||
|
||||
if (me.isPlaying()) {
|
||||
me.play();
|
||||
}
|
||||
},
|
||||
|
||||
onErased: function() {
|
||||
this.pause();
|
||||
this.media.setTop(-2000);
|
||||
this.ghost.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Called when the {@link #ghost} element is tapped.
|
||||
*/
|
||||
onGhostTap: function() {
|
||||
var me = this,
|
||||
media = this.media,
|
||||
ghost = this.ghost;
|
||||
|
||||
media.show();
|
||||
if (Ext.os.is.Android2) {
|
||||
setTimeout(function() {
|
||||
me.play();
|
||||
setTimeout(function() {
|
||||
media.hide();
|
||||
}, 10);
|
||||
}, 10);
|
||||
} else {
|
||||
// Browsers which support native video tag display only, move the media down so
|
||||
// we can control the Viewport
|
||||
ghost.hide();
|
||||
me.play();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* native video tag display only, move the media down so we can control the Viewport
|
||||
*/
|
||||
onPause: function() {
|
||||
this.callParent(arguments);
|
||||
if (!this.isInlineVideo) {
|
||||
this.media.setTop(-2000);
|
||||
this.ghost.show();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* native video tag display only, move the media down so we can control the Viewport
|
||||
*/
|
||||
onPlay: function() {
|
||||
this.callParent(arguments);
|
||||
this.media.setTop(0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the URL to the poster, even if it is rendered.
|
||||
* @param {Object} newUrl
|
||||
*/
|
||||
updatePosterUrl: function(newUrl) {
|
||||
var ghost = this.ghost;
|
||||
if (ghost) {
|
||||
ghost.setStyle('background-image', 'url(' + newUrl + ')');
|
||||
}
|
||||
}
|
||||
});
|
||||
377
OfficeWeb/3rdparty/touch/src/XTemplate.js
vendored
Normal file
377
OfficeWeb/3rdparty/touch/src/XTemplate.js
vendored
Normal file
@@ -0,0 +1,377 @@
|
||||
/**
|
||||
* 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.DataView}.
|
||||
*
|
||||
* 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: 'Don Griffin',
|
||||
* title: 'Senior Technomage',
|
||||
* company: 'Sencha Inc.',
|
||||
* drinks: ['Coffee', 'Water', 'More Coffee'],
|
||||
* kids: [
|
||||
* { name: 'Aubrey', age: 17 },
|
||||
* { name: 'Joshua', age: 13 },
|
||||
* { name: 'Cale', age: 10 },
|
||||
* { name: 'Nikol', age: 5 },
|
||||
* { 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.
|
||||
*
|
||||
* 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);
|
||||
*
|
||||
* More advanced conditionals are also supported:
|
||||
*
|
||||
* var tpl = new Ext.XTemplate(
|
||||
* '<p>Name: {name}</p>',
|
||||
* '<p>Kids: ',
|
||||
* '<tpl for="kids">',
|
||||
* '<p>{name} is a ',
|
||||
* '<tpl if="age >= 13">',
|
||||
* '<p>teenager</p>',
|
||||
* '<tpl elseif="age >= 2">',
|
||||
* '<p>kid</p>',
|
||||
* '<tpl else>',
|
||||
* '<p>baby</p>',
|
||||
* '</tpl>',
|
||||
* '</tpl></p>'
|
||||
* );
|
||||
*
|
||||
* var tpl = new Ext.XTemplate(
|
||||
* '<p>Name: {name}</p>',
|
||||
* '<p>Kids: ',
|
||||
* '<tpl for="kids">',
|
||||
* '<p>{name} is a ',
|
||||
* '<tpl switch="name">',
|
||||
* '<tpl case="Aubrey" case="Nikol">',
|
||||
* '<p>girl</p>',
|
||||
* '<tpl default">',
|
||||
* '<p>boy</p>',
|
||||
* '</tpl>',
|
||||
* '</tpl></p>'
|
||||
* );
|
||||
*
|
||||
* A `break` is implied between each case and default, however, multiple cases can be listed
|
||||
* in a single <tpl> tag.
|
||||
*
|
||||
* # Using double quotes
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* var tpl = new Ext.XTemplate(
|
||||
* "<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>",
|
||||
* "<tpl if='name == \"Don\"'>Hello</tpl>"
|
||||
* );
|
||||
*
|
||||
* # 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.
|
||||
* The expression is evaluated and the result is included in the generated result. There are
|
||||
* some special variables available in that code:
|
||||
*
|
||||
* - **out**: The output array into which the template is being appended (using `push` to later
|
||||
* `join`).
|
||||
* - **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>'
|
||||
* );
|
||||
*
|
||||
* Any code contained in "verbatim" blocks (using "{% ... %}") will be inserted directly in
|
||||
* the generated code for the template. These blocks are not included in the output. This
|
||||
* can be used for simple things like break/continue in a loop, or control structures or
|
||||
* method calls (when they don't produce output). The `this` references the template instance.
|
||||
*
|
||||
* var tpl = new Ext.XTemplate(
|
||||
* '<p>Name: {name}</p>',
|
||||
* '<p>Company: {[values.company.toUpperCase() + ", " + values.title]}</p>',
|
||||
* '<p>Kids: ',
|
||||
* '<tpl for="kids">',
|
||||
* '{% if (xindex % 2 === 0) continue; %}',
|
||||
* '{name}',
|
||||
* '{% if (xindex > 100) break; %}',
|
||||
* '</div>',
|
||||
* '</tpl></p>'
|
||||
* );
|
||||
*
|
||||
* # 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 else>',
|
||||
* '<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', {
|
||||
extend: 'Ext.Template',
|
||||
|
||||
requires: 'Ext.XTemplateCompiler',
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
emptyObj: {},
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} compiled
|
||||
* Only applies to {@link Ext.Template}, XTemplates are compiled automatically on the
|
||||
* first call to {@link #apply} or {@link #applyOut}.
|
||||
* @hide
|
||||
*/
|
||||
|
||||
apply: function(values) {
|
||||
return this.applyOut(values, []).join('');
|
||||
},
|
||||
|
||||
/**
|
||||
* Appends the result of this template to the provided output array.
|
||||
* @param {Object/Array} values The template values. See {@link #apply}.
|
||||
* @param {Array} out The array to which output is pushed.
|
||||
* @param {Object} parent
|
||||
* @return {Array} The given out array.
|
||||
*/
|
||||
applyOut: function(values, out, parent) {
|
||||
var me = this,
|
||||
xindex = values.xindex,
|
||||
xcount = values.xcount,
|
||||
compiler;
|
||||
|
||||
if (!me.fn) {
|
||||
compiler = new Ext.XTemplateCompiler({
|
||||
useFormat : me.disableFormats !== true,
|
||||
definitions : me.definitions
|
||||
});
|
||||
|
||||
me.fn = compiler.compile(me.html);
|
||||
}
|
||||
|
||||
try {
|
||||
xindex = typeof xindex === 'number' ? xindex : 1;
|
||||
xcount = typeof xcount === 'number' ? xcount : 1;
|
||||
|
||||
me.fn.call(me, out, values, parent || me.emptyObj, xindex, xcount);
|
||||
} catch (e) {
|
||||
//<debug>
|
||||
Ext.Logger.log('Error: ' + e.message);
|
||||
//</debug>
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
/**
|
||||
* Does nothing. XTemplates are compiled automatically, so this function simply returns this.
|
||||
* @return {Ext.XTemplate} this
|
||||
*/
|
||||
compile: function() {
|
||||
return this;
|
||||
},
|
||||
|
||||
statics: {
|
||||
/**
|
||||
* Gets an `XTemplate` from an object (an instance of an {@link Ext#define}'d class).
|
||||
* Many times, templates are configured high in the class hierarchy and are to be
|
||||
* shared by all classes that derive from that base. To further complicate matters,
|
||||
* these templates are seldom actual instances but are rather configurations. For
|
||||
* example:
|
||||
*
|
||||
* Ext.define('MyApp.Class', {
|
||||
* someTpl: [
|
||||
* 'tpl text here'
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* The goal being to share that template definition with all instances and even
|
||||
* instances of derived classes, until `someTpl` is overridden. This method will
|
||||
* "upgrade" these configurations to be real `XTemplate` instances *in place* (to
|
||||
* avoid creating one instance per object).
|
||||
*
|
||||
* @param {Object} instance The object from which to get the `XTemplate` (must be
|
||||
* an instance of an {@link Ext#define}'d class).
|
||||
* @param {String} name The name of the property by which to get the `XTemplate`.
|
||||
* @return {Ext.XTemplate} The `XTemplate` instance or null if not found.
|
||||
* @protected
|
||||
*/
|
||||
getTpl: function (instance, name) {
|
||||
var tpl = instance[name], // go for it! 99% of the time we will get it!
|
||||
proto;
|
||||
|
||||
if (tpl && !tpl.isTemplate) { // tpl is just a configuration (not an instance)
|
||||
// create the template instance from the configuration:
|
||||
tpl = Ext.ClassManager.dynInstantiate('Ext.XTemplate', tpl);
|
||||
|
||||
// and replace the reference with the new instance:
|
||||
if (instance.hasOwnProperty(name)) { // the tpl is on the instance
|
||||
instance[name] = tpl;
|
||||
} else { // must be somewhere in the prototype chain
|
||||
for (proto = instance.self.prototype; proto; proto = proto.superclass) {
|
||||
if (proto.hasOwnProperty(name)) {
|
||||
proto[name] = tpl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// else !tpl (no such tpl) or the tpl is an instance already... either way, tpl
|
||||
// is ready to return
|
||||
|
||||
return tpl || null;
|
||||
}
|
||||
}
|
||||
});
|
||||
450
OfficeWeb/3rdparty/touch/src/XTemplateCompiler.js
vendored
Normal file
450
OfficeWeb/3rdparty/touch/src/XTemplateCompiler.js
vendored
Normal file
@@ -0,0 +1,450 @@
|
||||
/**
|
||||
* This class compiles the XTemplate syntax into a function object. The function is used
|
||||
* like so:
|
||||
*
|
||||
* function (out, values, parent, xindex, xcount) {
|
||||
* // out is the output array to store results
|
||||
* // values, parent, xindex and xcount have their historical meaning
|
||||
* }
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.XTemplateCompiler', {
|
||||
extend: 'Ext.XTemplateParser',
|
||||
|
||||
// Chrome really likes "new Function" to realize the code block (as in it is
|
||||
// 2x-3x faster to call it than using eval), but Firefox chokes on it badly.
|
||||
// IE and Opera are also fine with the "new Function" technique.
|
||||
useEval: Ext.isGecko,
|
||||
|
||||
// See [http://jsperf.com/nige-array-append](http://jsperf.com/nige-array-append) for quickest way to append to an array of unknown length
|
||||
// (Due to arbitrary code execution inside a template, we cannot easily track the length in var)
|
||||
// On IE6 and 7 `myArray[myArray.length]='foo'` is better. On other browsers `myArray.push('foo')` is better.
|
||||
useIndex: Ext.isIE6 || Ext.isIE7,
|
||||
|
||||
useFormat: true,
|
||||
|
||||
propNameRe: /^[\w\d\$]*$/,
|
||||
|
||||
compile: function (tpl) {
|
||||
var me = this,
|
||||
code = me.generate(tpl);
|
||||
|
||||
// When using "new Function", we have to pass our "Ext" variable to it in order to
|
||||
// support sandboxing. If we did not, the generated function would use the global
|
||||
// "Ext", not the "Ext" from our sandbox (scope chain).
|
||||
//
|
||||
return me.useEval ? me.evalTpl(code) : (new Function('Ext', code))(Ext);
|
||||
},
|
||||
|
||||
generate: function (tpl) {
|
||||
var me = this,
|
||||
// note: Ext here is properly sandboxed
|
||||
definitions = 'var fm=Ext.util.Format,ts=Object.prototype.toString;',
|
||||
code;
|
||||
|
||||
// Track how many levels we use, so that we only "var" each level's variables once
|
||||
me.maxLevel = 0;
|
||||
|
||||
me.body = [
|
||||
'var c0=values, a0=' + me.createArrayTest(0) + ', p0=parent, n0=xcount, i0=xindex, v;\n'
|
||||
];
|
||||
if (me.definitions) {
|
||||
if (typeof me.definitions === 'string') {
|
||||
me.definitions = [me.definitions, definitions ];
|
||||
} else {
|
||||
me.definitions.push(definitions);
|
||||
}
|
||||
} else {
|
||||
me.definitions = [ definitions ];
|
||||
}
|
||||
me.switches = [];
|
||||
|
||||
me.parse(tpl);
|
||||
|
||||
me.definitions.push(
|
||||
(me.useEval ? '$=' : 'return') + ' function (' + me.fnArgs + ') {',
|
||||
me.body.join(''),
|
||||
'}'
|
||||
);
|
||||
|
||||
code = me.definitions.join('\n');
|
||||
|
||||
// Free up the arrays.
|
||||
me.definitions.length = me.body.length = me.switches.length = 0;
|
||||
delete me.definitions;
|
||||
delete me.body;
|
||||
delete me.switches;
|
||||
|
||||
return code;
|
||||
},
|
||||
|
||||
//-----------------------------------
|
||||
// XTemplateParser callouts
|
||||
|
||||
//
|
||||
doText: function (text) {
|
||||
var me = this,
|
||||
out = me.body;
|
||||
|
||||
text = text.replace(me.aposRe, "\\'").replace(me.newLineRe, '\\n');
|
||||
if (me.useIndex) {
|
||||
out.push('out[out.length]=\'', text, '\'\n');
|
||||
} else {
|
||||
out.push('out.push(\'', text, '\')\n');
|
||||
}
|
||||
},
|
||||
|
||||
doExpr: function (expr) {
|
||||
var out = this.body;
|
||||
out.push('if ((v=' + expr + ')!==undefined && (v=' + expr + ')!==null) out');
|
||||
|
||||
// Coerce value to string using concatenation of an empty string literal.
|
||||
// See http://jsperf.com/tostringvscoercion/5
|
||||
if (this.useIndex) {
|
||||
out.push('[out.length]=v+\'\'\n');
|
||||
} else {
|
||||
out.push('.push(v+\'\')\n');
|
||||
}
|
||||
},
|
||||
|
||||
doTag: function (tag) {
|
||||
this.doExpr(this.parseTag(tag));
|
||||
},
|
||||
|
||||
doElse: function () {
|
||||
this.body.push('} else {\n');
|
||||
},
|
||||
|
||||
doEval: function (text) {
|
||||
this.body.push(text, '\n');
|
||||
},
|
||||
|
||||
doIf: function (action, actions) {
|
||||
var me = this;
|
||||
|
||||
// If it's just a propName, use it directly in the if
|
||||
if (action === '.') {
|
||||
me.body.push('if (values) {\n');
|
||||
} else if (me.propNameRe.test(action)) {
|
||||
me.body.push('if (', me.parseTag(action), ') {\n');
|
||||
}
|
||||
// Otherwise, it must be an expression, and needs to be returned from an fn which uses with(values)
|
||||
else {
|
||||
me.body.push('if (', me.addFn(action), me.callFn, ') {\n');
|
||||
}
|
||||
if (actions.exec) {
|
||||
me.doExec(actions.exec);
|
||||
}
|
||||
},
|
||||
|
||||
doElseIf: function (action, actions) {
|
||||
var me = this;
|
||||
|
||||
// If it's just a propName, use it directly in the else if
|
||||
if (action === '.') {
|
||||
me.body.push('else if (values) {\n');
|
||||
} else if (me.propNameRe.test(action)) {
|
||||
me.body.push('} else if (', me.parseTag(action), ') {\n');
|
||||
}
|
||||
// Otherwise, it must be an expression, and needs to be returned from an fn which uses with(values)
|
||||
else {
|
||||
me.body.push('} else if (', me.addFn(action), me.callFn, ') {\n');
|
||||
}
|
||||
if (actions.exec) {
|
||||
me.doExec(actions.exec);
|
||||
}
|
||||
},
|
||||
|
||||
doSwitch: function (action) {
|
||||
var me = this;
|
||||
|
||||
// If it's just a propName, use it directly in the switch
|
||||
if (action === '.') {
|
||||
me.body.push('switch (values) {\n');
|
||||
} else if (me.propNameRe.test(action)) {
|
||||
me.body.push('switch (', me.parseTag(action), ') {\n');
|
||||
}
|
||||
// Otherwise, it must be an expression, and needs to be returned from an fn which uses with(values)
|
||||
else {
|
||||
me.body.push('switch (', me.addFn(action), me.callFn, ') {\n');
|
||||
}
|
||||
me.switches.push(0);
|
||||
},
|
||||
|
||||
doCase: function (action) {
|
||||
var me = this,
|
||||
cases = Ext.isArray(action) ? action : [action],
|
||||
n = me.switches.length - 1,
|
||||
match, i;
|
||||
|
||||
if (me.switches[n]) {
|
||||
me.body.push('break;\n');
|
||||
} else {
|
||||
me.switches[n]++;
|
||||
}
|
||||
|
||||
for (i = 0, n = cases.length; i < n; ++i) {
|
||||
match = me.intRe.exec(cases[i]);
|
||||
cases[i] = match ? match[1] : ("'" + cases[i].replace(me.aposRe,"\\'") + "'");
|
||||
}
|
||||
|
||||
me.body.push('case ', cases.join(': case '), ':\n');
|
||||
},
|
||||
|
||||
doDefault: function () {
|
||||
var me = this,
|
||||
n = me.switches.length - 1;
|
||||
|
||||
if (me.switches[n]) {
|
||||
me.body.push('break;\n');
|
||||
} else {
|
||||
me.switches[n]++;
|
||||
}
|
||||
|
||||
me.body.push('default:\n');
|
||||
},
|
||||
|
||||
doEnd: function (type, actions) {
|
||||
var me = this,
|
||||
L = me.level-1;
|
||||
|
||||
if (type == 'for') {
|
||||
/*
|
||||
To exit a for loop we must restore the outer loop's context. The code looks
|
||||
like this (which goes with that produced by doFor:
|
||||
|
||||
for (...) { // the part generated by doFor
|
||||
... // the body of the for loop
|
||||
|
||||
// ... any tpl for exec statement goes here...
|
||||
}
|
||||
parent = p1;
|
||||
values = r2;
|
||||
xcount = n1;
|
||||
xindex = i1
|
||||
*/
|
||||
if (actions.exec) {
|
||||
me.doExec(actions.exec);
|
||||
}
|
||||
|
||||
me.body.push('}\n');
|
||||
me.body.push('parent=p',L,';values=r',L+1,';xcount=n',L,';xindex=i',L,'\n');
|
||||
} else if (type == 'if' || type == 'switch') {
|
||||
me.body.push('}\n');
|
||||
}
|
||||
},
|
||||
|
||||
doFor: function (action, actions) {
|
||||
var me = this,
|
||||
s,
|
||||
L = me.level,
|
||||
up = L-1,
|
||||
pL = 'p' + L,
|
||||
parentAssignment;
|
||||
|
||||
// If it's just a propName, use it directly in the switch
|
||||
if (action === '.') {
|
||||
s = 'values';
|
||||
} else if (me.propNameRe.test(action)) {
|
||||
s = me.parseTag(action);
|
||||
}
|
||||
// Otherwise, it must be an expression, and needs to be returned from an fn which uses with(values)
|
||||
else {
|
||||
s = me.addFn(action) + me.callFn;
|
||||
}
|
||||
|
||||
/*
|
||||
We are trying to produce a block of code that looks like below. We use the nesting
|
||||
level to uniquely name the control variables.
|
||||
|
||||
// Omit "var " if we have already been through level 2
|
||||
var i2 = 0,
|
||||
n2 = 0,
|
||||
c2 = values['propName'],
|
||||
// c2 is the context object for the for loop
|
||||
a2 = Array.isArray(c2);
|
||||
p2 = c1,
|
||||
// p2 is the parent context (of the outer for loop)
|
||||
r2 = values
|
||||
// r2 is the values object to
|
||||
|
||||
// If iterating over the current data, the parent is always set to c2
|
||||
parent = c2;
|
||||
// If iterating over a property in an object, set the parent to the object
|
||||
parent = a1 ? c1[i1] : p2 // set parent
|
||||
if (c2) {
|
||||
if (a2) {
|
||||
n2 = c2.length;
|
||||
} else if (c2.isMixedCollection) {
|
||||
c2 = c2.items;
|
||||
n2 = c2.length;
|
||||
} else if (c2.isStore) {
|
||||
c2 = c2.data.items;
|
||||
n2 = c2.length;
|
||||
} else {
|
||||
c2 = [ c2 ];
|
||||
n2 = 1;
|
||||
}
|
||||
}
|
||||
// i2 is the loop index and n2 is the number (xcount) of this for loop
|
||||
for (xcount = n2; i2 < n2; ++i2) {
|
||||
values = c2[i2] // adjust special vars to inner scope
|
||||
xindex = i2 + 1 // xindex is 1-based
|
||||
|
||||
The body of the loop is whatever comes between the tpl and /tpl statements (which
|
||||
is handled by doEnd).
|
||||
*/
|
||||
|
||||
// Declare the vars for a particular level only if we have not already declared them.
|
||||
if (me.maxLevel < L) {
|
||||
me.maxLevel = L;
|
||||
me.body.push('var ');
|
||||
}
|
||||
|
||||
if (action == '.') {
|
||||
parentAssignment = 'c' + L;
|
||||
} else {
|
||||
parentAssignment = 'a' + up + '?c' + up + '[i' + up + ']:p' + L;
|
||||
}
|
||||
|
||||
me.body.push('i',L,'=0,n', L, '=0,c',L,'=',s,',a',L,'=', me.createArrayTest(L), ',p',L,'=c',up,',r',L,'=values;\n',
|
||||
'parent=',parentAssignment,'\n',
|
||||
'if (c',L,'){if(a',L,'){n', L,'=c', L, '.length;}else if (c', L, '.isMixedCollection){c',L,'=c',L,'.items;n',L,'=c',L,'.length;}else if(c',L,'.isStore){c',L,'=c',L,'.data.items;n',L,'=c',L,'.length;}else{c',L,'=[c',L,'];n',L,'=1;}}\n',
|
||||
'for (xcount=n',L,';i',L,'<n'+L+';++i',L,'){\n',
|
||||
'values=c',L,'[i',L,']');
|
||||
if (actions.propName) {
|
||||
me.body.push('.', actions.propName);
|
||||
}
|
||||
me.body.push('\n',
|
||||
'xindex=i',L,'+1\n');
|
||||
},
|
||||
|
||||
createArrayTest: ('isArray' in Array) ? function(L) {
|
||||
return 'Array.isArray(c' + L + ')';
|
||||
} : function(L) {
|
||||
return 'ts.call(c' + L + ')==="[object Array]"';
|
||||
},
|
||||
|
||||
doExec: function (action, actions) {
|
||||
var me = this,
|
||||
name = 'f' + me.definitions.length;
|
||||
|
||||
me.definitions.push('function ' + name + '(' + me.fnArgs + ') {',
|
||||
' try { with(values) {',
|
||||
' ' + action,
|
||||
' }} catch(e) {',
|
||||
//<debug>
|
||||
'Ext.Logger.log("XTemplate Error: " + e.message);',
|
||||
//</debug>
|
||||
'}',
|
||||
'}');
|
||||
|
||||
me.body.push(name + me.callFn + '\n');
|
||||
},
|
||||
|
||||
//-----------------------------------
|
||||
// Internal
|
||||
|
||||
//
|
||||
addFn: function (body) {
|
||||
var me = this,
|
||||
name = 'f' + me.definitions.length;
|
||||
|
||||
if (body === '.') {
|
||||
me.definitions.push('function ' + name + '(' + me.fnArgs + ') {',
|
||||
' return values',
|
||||
'}');
|
||||
} else if (body === '..') {
|
||||
me.definitions.push('function ' + name + '(' + me.fnArgs + ') {',
|
||||
' return parent',
|
||||
'}');
|
||||
} else {
|
||||
me.definitions.push('function ' + name + '(' + me.fnArgs + ') {',
|
||||
' try { with(values) {',
|
||||
' return(' + body + ')',
|
||||
' }} catch(e) {',
|
||||
//<debug>
|
||||
'Ext.Logger.log("XTemplate Error: " + e.message);',
|
||||
//</debug>
|
||||
'}',
|
||||
'}');
|
||||
}
|
||||
|
||||
return name;
|
||||
},
|
||||
|
||||
parseTag: function (tag) {
|
||||
var me = this,
|
||||
m = me.tagRe.exec(tag),
|
||||
name = m[1],
|
||||
format = m[2],
|
||||
args = m[3],
|
||||
math = m[4],
|
||||
v;
|
||||
|
||||
// name = "." - Just use the values object.
|
||||
if (name == '.') {
|
||||
// filter to not include arrays/objects/nulls
|
||||
if (!me.validTypes) {
|
||||
me.definitions.push('var validTypes={string:1,number:1,boolean:1};');
|
||||
me.validTypes = true;
|
||||
}
|
||||
v = 'validTypes[typeof values] || ts.call(values) === "[object Date]" ? values : ""';
|
||||
}
|
||||
// name = "#" - Use the xindex
|
||||
else if (name == '#') {
|
||||
v = 'xindex';
|
||||
}
|
||||
else if (name.substr(0, 7) == "parent.") {
|
||||
v = name;
|
||||
}
|
||||
// compound JavaScript property name (e.g., "foo.bar")
|
||||
else if (isNaN(name) && name.indexOf('-') == -1 && name.indexOf('.') != -1) {
|
||||
v = "values." + name;
|
||||
}
|
||||
// number or a '-' in it or a single word (maybe a keyword): use array notation
|
||||
// (http://jsperf.com/string-property-access/4)
|
||||
else {
|
||||
v = "values['" + name + "']";
|
||||
}
|
||||
|
||||
if (math) {
|
||||
v = '(' + v + math + ')';
|
||||
}
|
||||
|
||||
if (format && me.useFormat) {
|
||||
args = args ? ',' + args : "";
|
||||
if (format.substr(0, 5) != "this.") {
|
||||
format = "fm." + format + '(';
|
||||
} else {
|
||||
format += '(';
|
||||
}
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
|
||||
return format + v + args + ')';
|
||||
},
|
||||
|
||||
// @private
|
||||
evalTpl: function ($) {
|
||||
|
||||
// We have to use eval to realize the code block and capture the inner func we also
|
||||
// don't want a deep scope chain. We only do this in Firefox and it is also unhappy
|
||||
// with eval containing a return statement, so instead we assign to "$" and return
|
||||
// that. Because we use "eval", we are automatically sandboxed properly.
|
||||
eval($);
|
||||
return $;
|
||||
},
|
||||
|
||||
newLineRe: /\r\n|\r|\n/g,
|
||||
aposRe: /[']/g,
|
||||
intRe: /^\s*(\d+)\s*$/,
|
||||
tagRe: /([\w-\.\#\$]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\/]\s?[\d\.\+\-\*\/\(\)]+)?/
|
||||
}, function () {
|
||||
var proto = this.prototype;
|
||||
|
||||
proto.fnArgs = 'out,values,parent,xindex,xcount';
|
||||
proto.callFn = '.call(this,' + proto.fnArgs + ')';
|
||||
});
|
||||
250
OfficeWeb/3rdparty/touch/src/XTemplateParser.js
vendored
Normal file
250
OfficeWeb/3rdparty/touch/src/XTemplateParser.js
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* This class parses the XTemplate syntax and calls abstract methods to process the parts.
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.XTemplateParser', {
|
||||
constructor: function (config) {
|
||||
Ext.apply(this, config);
|
||||
},
|
||||
|
||||
/**
|
||||
* @property {Number} level The 'for' loop context level. This is adjusted up by one
|
||||
* prior to calling {@link #doFor} and down by one after calling the corresponding
|
||||
* {@link #doEnd} that closes the loop. This will be 1 on the first {@link #doFor}
|
||||
* call.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This method is called to process a piece of raw text from the tpl.
|
||||
* @param {String} text
|
||||
* @method doText
|
||||
*/
|
||||
// doText: function (text)
|
||||
|
||||
/**
|
||||
* This method is called to process expressions (like `{[expr]}`).
|
||||
* @param {String} expr The body of the expression (inside "{[" and "]}").
|
||||
* @method doExpr
|
||||
*/
|
||||
// doExpr: function (expr)
|
||||
|
||||
/**
|
||||
* This method is called to process simple tags (like `{tag}`).
|
||||
* @param {String} tag
|
||||
* @method doTag
|
||||
*/
|
||||
// doTag: function (tag)
|
||||
|
||||
/**
|
||||
* This method is called to process `<tpl else>`.
|
||||
* @method doElse
|
||||
*/
|
||||
// doElse: function ()
|
||||
|
||||
/**
|
||||
* This method is called to process `{% text %}`.
|
||||
* @param {String} text
|
||||
* @method doEval
|
||||
*/
|
||||
// doEval: function (text)
|
||||
|
||||
/**
|
||||
* This method is called to process `<tpl if="action">`. If there are other attributes,
|
||||
* these are passed in the actions object.
|
||||
* @param {String} action
|
||||
* @param {Object} actions Other actions keyed by the attribute name (such as 'exec').
|
||||
* @method doIf
|
||||
*/
|
||||
// doIf: function (action, actions)
|
||||
|
||||
/**
|
||||
* This method is called to process `<tpl elseif="action">`. If there are other attributes,
|
||||
* these are passed in the actions object.
|
||||
* @param {String} action
|
||||
* @param {Object} actions Other actions keyed by the attribute name (such as 'exec').
|
||||
* @method doElseIf
|
||||
*/
|
||||
// doElseIf: function (action, actions)
|
||||
|
||||
/**
|
||||
* This method is called to process `<tpl switch="action">`. If there are other attributes,
|
||||
* these are passed in the actions object.
|
||||
* @param {String} action
|
||||
* @param {Object} actions Other actions keyed by the attribute name (such as 'exec').
|
||||
* @method doSwitch
|
||||
*/
|
||||
// doSwitch: function (action, actions)
|
||||
|
||||
/**
|
||||
* This method is called to process `<tpl case="action">`. If there are other attributes,
|
||||
* these are passed in the actions object.
|
||||
* @param {String} action
|
||||
* @param {Object} actions Other actions keyed by the attribute name (such as 'exec').
|
||||
* @method doCase
|
||||
*/
|
||||
// doCase: function (action, actions)
|
||||
|
||||
/**
|
||||
* This method is called to process `<tpl default>`.
|
||||
* @method doDefault
|
||||
*/
|
||||
// doDefault: function ()
|
||||
|
||||
/**
|
||||
* This method is called to process `</tpl>`. It is given the action type that started
|
||||
* the tpl and the set of additional actions.
|
||||
* @param {String} type The type of action that is being ended.
|
||||
* @param {Object} actions The other actions keyed by the attribute name (such as 'exec').
|
||||
* @method doEnd
|
||||
*/
|
||||
// doEnd: function (type, actions)
|
||||
|
||||
/**
|
||||
* This method is called to process `<tpl for="action">`. If there are other attributes,
|
||||
* these are passed in the actions object.
|
||||
* @param {String} action
|
||||
* @param {Object} actions Other actions keyed by the attribute name (such as 'exec').
|
||||
* @method doFor
|
||||
*/
|
||||
// doFor: function (action, actions)
|
||||
|
||||
/**
|
||||
* This method is called to process `<tpl exec="action">`. If there are other attributes,
|
||||
* these are passed in the actions object.
|
||||
* @param {String} action
|
||||
* @param {Object} actions Other actions keyed by the attribute name.
|
||||
* @method doExec
|
||||
*/
|
||||
// doExec: function (action, actions)
|
||||
|
||||
/**
|
||||
* This method is called to process an empty `<tpl>`. This is unlikely to need to be
|
||||
* implemented, so a default (do nothing) version is provided.
|
||||
* @method
|
||||
*/
|
||||
doTpl: Ext.emptyFn,
|
||||
|
||||
parse: function (str) {
|
||||
var me = this,
|
||||
len = str.length,
|
||||
aliases = { elseif: 'elif' },
|
||||
topRe = me.topRe,
|
||||
actionsRe = me.actionsRe,
|
||||
index, stack, s, m, t, prev, frame, subMatch, begin, end, actions,
|
||||
prop;
|
||||
|
||||
me.level = 0;
|
||||
me.stack = stack = [];
|
||||
|
||||
for (index = 0; index < len; index = end) {
|
||||
topRe.lastIndex = index;
|
||||
m = topRe.exec(str);
|
||||
|
||||
if (!m) {
|
||||
me.doText(str.substring(index, len));
|
||||
break;
|
||||
}
|
||||
|
||||
begin = m.index;
|
||||
end = topRe.lastIndex;
|
||||
|
||||
if (index < begin) {
|
||||
me.doText(str.substring(index, begin));
|
||||
}
|
||||
|
||||
if (m[1]) {
|
||||
end = str.indexOf('%}', begin+2);
|
||||
me.doEval(str.substring(begin+2, end));
|
||||
end += 2;
|
||||
} else if (m[2]) {
|
||||
end = str.indexOf(']}', begin+2);
|
||||
me.doExpr(str.substring(begin+2, end));
|
||||
end += 2;
|
||||
} else if (m[3]) { // if ('{' token)
|
||||
me.doTag(m[3]);
|
||||
} else if (m[4]) { // content of a <tpl xxxxxx xxx> tag
|
||||
actions = null;
|
||||
while ((subMatch = actionsRe.exec(m[4])) !== null) {
|
||||
s = subMatch[2] || subMatch[3];
|
||||
if (s) {
|
||||
s = Ext.String.htmlDecode(s); // decode attr value
|
||||
t = subMatch[1];
|
||||
t = aliases[t] || t;
|
||||
actions = actions || {};
|
||||
prev = actions[t];
|
||||
|
||||
if (typeof prev == 'string') {
|
||||
actions[t] = [prev, s];
|
||||
} else if (prev) {
|
||||
actions[t].push(s);
|
||||
} else {
|
||||
actions[t] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!actions) {
|
||||
if (me.elseRe.test(m[4])) {
|
||||
me.doElse();
|
||||
} else if (me.defaultRe.test(m[4])) {
|
||||
me.doDefault();
|
||||
} else {
|
||||
me.doTpl();
|
||||
stack.push({ type: 'tpl' });
|
||||
}
|
||||
}
|
||||
else if (actions['if']) {
|
||||
me.doIf(actions['if'], actions);
|
||||
stack.push({ type: 'if' });
|
||||
}
|
||||
else if (actions['switch']) {
|
||||
me.doSwitch(actions['switch'], actions);
|
||||
stack.push({ type: 'switch' });
|
||||
}
|
||||
else if (actions['case']) {
|
||||
me.doCase(actions['case'], actions);
|
||||
}
|
||||
else if (actions['elif']) {
|
||||
me.doElseIf(actions['elif'], actions);
|
||||
}
|
||||
else if (actions['for']) {
|
||||
++me.level;
|
||||
|
||||
// Extract property name to use from indexed item
|
||||
if (prop = me.propRe.exec(m[4])) {
|
||||
actions.propName = prop[1] || prop[2];
|
||||
}
|
||||
me.doFor(actions['for'], actions);
|
||||
stack.push({ type: 'for', actions: actions });
|
||||
}
|
||||
else if (actions.exec) {
|
||||
me.doExec(actions.exec, actions);
|
||||
stack.push({ type: 'exec', actions: actions });
|
||||
}
|
||||
/*
|
||||
else {
|
||||
// todo - error
|
||||
}
|
||||
*/
|
||||
} else if (m[0].length === 5) {
|
||||
// if the length of m[0] is 5, assume that we're dealing with an opening tpl tag with no attributes (e.g. <tpl>...</tpl>)
|
||||
// in this case no action is needed other than pushing it on to the stack
|
||||
stack.push({ type: 'tpl' });
|
||||
} else {
|
||||
frame = stack.pop();
|
||||
me.doEnd(frame.type, frame.actions);
|
||||
if (frame.type == 'for') {
|
||||
--me.level;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Internal regexes
|
||||
|
||||
topRe: /(?:(\{\%)|(\{\[)|\{([^{}]*)\})|(?:<tpl([^>]*)\>)|(?:<\/tpl>)/g,
|
||||
actionsRe: /\s*(elif|elseif|if|for|exec|switch|case|eval)\s*\=\s*(?:(?:"([^"]*)")|(?:'([^']*)'))\s*/g,
|
||||
propRe: /prop=(?:(?:"([^"]*)")|(?:'([^']*)'))/,
|
||||
defaultRe: /^\s*default\s*$/,
|
||||
elseRe: /^\s*else\s*$/
|
||||
});
|
||||
136
OfficeWeb/3rdparty/touch/src/app/Action.js
vendored
Normal file
136
OfficeWeb/3rdparty/touch/src/app/Action.js
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @author Ed Spencer
|
||||
* @private
|
||||
*
|
||||
* Represents a single action as {@link Ext.app.Application#dispatch dispatched} by an Application. This is typically
|
||||
* generated as a result of a url change being matched by a Route, triggering Application's dispatch function.
|
||||
*
|
||||
* This is a private class and its functionality and existence may change in the future. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.app.Action', {
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Object} scope The scope in which the {@link #action} should be called.
|
||||
*/
|
||||
scope: null,
|
||||
|
||||
/**
|
||||
* @cfg {Ext.app.Application} application The Application that this Action is bound to.
|
||||
*/
|
||||
application: null,
|
||||
|
||||
/**
|
||||
* @cfg {Ext.app.Controller} controller The {@link Ext.app.Controller controller} whose {@link #action} should
|
||||
* be called.
|
||||
*/
|
||||
controller: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} action The name of the action on the {@link #controller} that should be called.
|
||||
*/
|
||||
action: null,
|
||||
|
||||
/**
|
||||
* @cfg {Array} args The set of arguments that will be passed to the controller's {@link #action}.
|
||||
*/
|
||||
args: [],
|
||||
|
||||
/**
|
||||
* @cfg {String} url The url that was decoded into the controller/action/args in this Action.
|
||||
*/
|
||||
url: undefined,
|
||||
data: {},
|
||||
title: null,
|
||||
|
||||
/**
|
||||
* @cfg {Array} beforeFilters The (optional) set of functions to call before the {@link #action} is called.
|
||||
* This is usually handled directly by the Controller or Application when an Ext.app.Action instance is
|
||||
* created, but is alterable before {@link #resume} is called.
|
||||
* @accessor
|
||||
*/
|
||||
beforeFilters: [],
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Keeps track of which before filter is currently being executed by {@link #resume}
|
||||
*/
|
||||
currentFilterIndex: -1
|
||||
},
|
||||
|
||||
constructor: function(config) {
|
||||
this.initConfig(config);
|
||||
|
||||
this.getUrl();
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts execution of this Action by calling each of the {@link #beforeFilters} in turn (if any are specified),
|
||||
* before calling the Controller {@link #action}. Same as calling {@link #resume}.
|
||||
*/
|
||||
execute: function() {
|
||||
this.resume();
|
||||
},
|
||||
|
||||
/**
|
||||
* Resumes the execution of this Action (or starts it if it had not been started already). This iterates over all
|
||||
* of the configured {@link #beforeFilters} and calls them. Each before filter is called with this Action as the
|
||||
* sole argument, and is expected to call `action.resume()` in order to allow the next filter to be called, or if
|
||||
* this is the final filter, the original {@link Ext.app.Controller Controller} function.
|
||||
*/
|
||||
resume: function() {
|
||||
var index = this.getCurrentFilterIndex() + 1,
|
||||
filters = this.getBeforeFilters(),
|
||||
controller = this.getController(),
|
||||
nextFilter = filters[index];
|
||||
|
||||
if (nextFilter) {
|
||||
this.setCurrentFilterIndex(index);
|
||||
nextFilter.call(controller, this);
|
||||
} else {
|
||||
controller[this.getAction()].apply(controller, this.getArgs());
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyUrl: function(url) {
|
||||
if (url === null || url === undefined) {
|
||||
url = this.urlEncode();
|
||||
}
|
||||
|
||||
return url;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* If the controller config is a string, swap it for a reference to the actual controller instance.
|
||||
* @param {String} controller The controller name.
|
||||
*/
|
||||
applyController: function(controller) {
|
||||
var app = this.getApplication(),
|
||||
profile = app.getCurrentProfile();
|
||||
|
||||
if (Ext.isString(controller)) {
|
||||
controller = app.getController(controller, profile ? profile.getNamespace() : null);
|
||||
}
|
||||
|
||||
return controller;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
urlEncode: function() {
|
||||
var controller = this.getController(),
|
||||
splits;
|
||||
|
||||
if (controller instanceof Ext.app.Controller) {
|
||||
splits = controller.$className.split('.');
|
||||
controller = splits[splits.length - 1];
|
||||
}
|
||||
|
||||
return controller + "/" + this.getAction();
|
||||
}
|
||||
});
|
||||
905
OfficeWeb/3rdparty/touch/src/app/Application.js
vendored
Normal file
905
OfficeWeb/3rdparty/touch/src/app/Application.js
vendored
Normal file
@@ -0,0 +1,905 @@
|
||||
/**
|
||||
* @author Ed Spencer
|
||||
*
|
||||
* @aside guide apps_intro
|
||||
* @aside guide first_app
|
||||
* @aside video mvc-part-1
|
||||
* @aside video mvc-part-2
|
||||
*
|
||||
* Ext.app.Application defines the set of {@link Ext.data.Model Models}, {@link Ext.app.Controller Controllers},
|
||||
* {@link Ext.app.Profile Profiles}, {@link Ext.data.Store Stores} and {@link Ext.Component Views} that an application
|
||||
* consists of. It automatically loads all of those dependencies and can optionally specify a {@link #launch} function
|
||||
* that will be called when everything is ready.
|
||||
*
|
||||
* Sample usage:
|
||||
*
|
||||
* Ext.application({
|
||||
* name: 'MyApp',
|
||||
*
|
||||
* models: ['User', 'Group'],
|
||||
* stores: ['Users'],
|
||||
* controllers: ['Users'],
|
||||
* views: ['Main', 'ShowUser'],
|
||||
*
|
||||
* launch: function() {
|
||||
* Ext.create('MyApp.view.Main');
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* Creating an Application instance is the only time in Sencha Touch 2 that we don't use Ext.create to create the new
|
||||
* instance. Instead, the {@link Ext#application} function instantiates an Ext.app.Application internally,
|
||||
* automatically loading the Ext.app.Application class if it is not present on the page already and hooking in to
|
||||
* {@link Ext#onReady} before creating the instance itself. An alternative is to use Ext.create inside an Ext.onReady
|
||||
* callback, but Ext.application is preferred.
|
||||
*
|
||||
* ## Dependencies
|
||||
*
|
||||
* Application follows a simple convention when it comes to specifying the controllers, views, models, stores and
|
||||
* profiles it requires. By default it expects each of them to be found inside the *app/controller*, *app/view*,
|
||||
* *app/model*, *app/store* and *app/profile* directories in your app - if you follow this convention you can just
|
||||
* specify the last part of each class name and Application will figure out the rest for you:
|
||||
*
|
||||
* Ext.application({
|
||||
* name: 'MyApp',
|
||||
*
|
||||
* controllers: ['Users'],
|
||||
* models: ['User', 'Group'],
|
||||
* stores: ['Users'],
|
||||
* views: ['Main', 'ShowUser']
|
||||
* });
|
||||
*
|
||||
* The example above will load 6 files:
|
||||
*
|
||||
* - app/model/User.js
|
||||
* - app/model/Group.js
|
||||
* - app/store/Users.js
|
||||
* - app/controller/Users.js
|
||||
* - app/view/Main.js
|
||||
* - app/view/ShowUser.js
|
||||
*
|
||||
* ### Nested Dependencies
|
||||
*
|
||||
* For larger apps it's common to split the models, views and controllers into subfolders so keep the project
|
||||
* organized. This is especially true of views - it's not unheard of for large apps to have over a hundred separate
|
||||
* view classes so organizing them into folders can make maintenance much simpler.
|
||||
*
|
||||
* To specify dependencies in subfolders just use a period (".") to specify the folder:
|
||||
*
|
||||
* Ext.application({
|
||||
* name: 'MyApp',
|
||||
*
|
||||
* controllers: ['Users', 'nested.MyController'],
|
||||
* views: ['products.Show', 'products.Edit', 'user.Login']
|
||||
* });
|
||||
*
|
||||
* In this case these 5 files will be loaded:
|
||||
*
|
||||
* - app/controller/Users.js
|
||||
* - app/controller/nested/MyController.js
|
||||
* - app/view/products/Show.js
|
||||
* - app/view/products/Edit.js
|
||||
* - app/view/user/Login.js
|
||||
*
|
||||
* Note that we can mix and match within each configuration here - for each model, view, controller, profile or store
|
||||
* you can specify either just the final part of the class name (if you follow the directory conventions), or the full
|
||||
* class name.
|
||||
*
|
||||
* ### External Dependencies
|
||||
*
|
||||
* Finally, we can specify application dependencies from outside our application by fully-qualifying the classes we
|
||||
* want to load. A common use case for this is sharing authentication logic between multiple applications. Perhaps you
|
||||
* have several apps that login via a common user database and you want to share that code between them. An easy way to
|
||||
* do this is to create a folder alongside your app folder and then add its contents as dependencies for your app.
|
||||
*
|
||||
* For example, let's say our shared login code contains a login controller, a user model and a login form view. We
|
||||
* want to use all of these in our application:
|
||||
*
|
||||
* Ext.Loader.setPath({
|
||||
* 'Auth': 'Auth'
|
||||
* });
|
||||
*
|
||||
* Ext.application({
|
||||
* views: ['Auth.view.LoginForm', 'Welcome'],
|
||||
* controllers: ['Auth.controller.Sessions', 'Main'],
|
||||
* models: ['Auth.model.User']
|
||||
* });
|
||||
*
|
||||
* This will load the following files:
|
||||
*
|
||||
* - Auth/view/LoginForm.js
|
||||
* - Auth/controller/Sessions.js
|
||||
* - Auth/model/User.js
|
||||
* - app/view/Welcome.js
|
||||
* - app/controller/Main.js
|
||||
*
|
||||
* The first three were loaded from outside our application, the last two from the application itself. Note how we can
|
||||
* still mix and match application files and external dependency files.
|
||||
*
|
||||
* Note that to enable the loading of external dependencies we just have to tell the Loader where to find those files,
|
||||
* which is what we do with the Ext.Loader.setPath call above. In this case we're telling the Loader to find any class
|
||||
* starting with the 'Auth' namespace inside our 'Auth' folder. This means we can drop our common Auth code into our
|
||||
* application alongside the app folder and the framework will be able to figure out how to load everything.
|
||||
*
|
||||
* ## Launching
|
||||
*
|
||||
* Each Application can define a {@link Ext.app.Application#launch launch} function, which is called as soon as all of
|
||||
* your app's classes have been loaded and the app is ready to be launched. This is usually the best place to put any
|
||||
* application startup logic, typically creating the main view structure for your app.
|
||||
*
|
||||
* In addition to the Application launch function, there are two other places you can put app startup logic. Firstly,
|
||||
* each Controller is able to define an {@link Ext.app.Controller#init init} function, which is called before the
|
||||
* Application launch function. Secondly, if you are using Device Profiles, each Profile can define a
|
||||
* {@link Ext.app.Profile#launch launch} function, which is called after the Controller init functions but before the
|
||||
* Application launch function.
|
||||
*
|
||||
* Note that only the active Profile has its launch function called - for example if you define profiles for Phone and
|
||||
* Tablet and then launch the app on a tablet, only the Tablet Profile's launch function is called.
|
||||
*
|
||||
* 1. Controller#init functions called
|
||||
* 2. Profile#launch function called
|
||||
* 3. Application#launch function called
|
||||
* 4. Controller#launch functions called
|
||||
*
|
||||
* When using Profiles it is common to place most of the bootup logic inside the Profile launch function because each
|
||||
* Profile has a different set of views that need to be constructed at startup.
|
||||
*
|
||||
* ## Adding to Home Screen
|
||||
*
|
||||
* iOS devices allow your users to add your app to their home screen for easy access. iOS allows you to customize
|
||||
* several aspects of this, including the icon that will appear on the home screen and the startup image. These can be
|
||||
* specified in the Ext.application setup block:
|
||||
*
|
||||
* Ext.application({
|
||||
* name: 'MyApp',
|
||||
*
|
||||
* {@link #icon}: 'resources/img/icon.png',
|
||||
* {@link #isIconPrecomposed}: false,
|
||||
* {@link #startupImage}: {
|
||||
* '320x460': 'resources/startup/320x460.jpg',
|
||||
* '640x920': 'resources/startup/640x920.png',
|
||||
* '640x1096': 'resources/startup/640x1096.png',
|
||||
* '768x1004': 'resources/startup/768x1004.png',
|
||||
* '748x1024': 'resources/startup/748x1024.png',
|
||||
* '1536x2008': 'resources/startup/1536x2008.png',
|
||||
* '1496x2048': 'resources/startup/1496x2048.png'
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* When the user adds your app to the home screen, your resources/img/icon.png file will be used as the application
|
||||
* {@link #icon}. We also used the {@link #isIconPrecomposed} configuration to turn off the gloss effect that is automatically added
|
||||
* to icons in iOS. Finally we used the {@link #startupImage} configuration to provide the images that will be displayed
|
||||
* while your application is starting up. See also {@link #statusBarStyle}.
|
||||
*
|
||||
* ## Find out more
|
||||
*
|
||||
* If you are not already familiar with writing applications with Sencha Touch 2 we recommend reading the
|
||||
* [intro to applications guide](#!/guide/apps_intro), which lays out the core principles of writing apps
|
||||
* with Sencha Touch 2.
|
||||
*/
|
||||
Ext.define('Ext.app.Application', {
|
||||
extend: 'Ext.app.Controller',
|
||||
|
||||
requires: [
|
||||
'Ext.app.History',
|
||||
'Ext.app.Profile',
|
||||
'Ext.app.Router',
|
||||
'Ext.app.Action'
|
||||
],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String/Object} icon
|
||||
* Specifies a set of URLs to the application icon for different device form factors. This icon is displayed
|
||||
* when the application is added to the device's Home Screen.
|
||||
*
|
||||
* Ext.setup({
|
||||
* icon: {
|
||||
* 57: 'resources/icons/Icon.png',
|
||||
* 72: 'resources/icons/Icon~ipad.png',
|
||||
* 114: 'resources/icons/Icon@2x.png',
|
||||
* 144: 'resources/icons/Icon~ipad@2x.png'
|
||||
* },
|
||||
* onReady: function() {
|
||||
* // ...
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* Each key represents the dimension of the icon as a square shape. For example: '57' is the key for a 57 x 57
|
||||
* icon image. Here is the breakdown of each dimension and its device target:
|
||||
*
|
||||
* - 57: Non-retina iPhone, iPod touch, and all Android devices
|
||||
* - 72: Retina iPhone and iPod touch
|
||||
* - 114: Non-retina iPad (first and second generation)
|
||||
* - 144: Retina iPad (third generation)
|
||||
*
|
||||
* Note that the dimensions of the icon images must be exactly 57x57, 72x72, 114x114 and 144x144 respectively.
|
||||
*
|
||||
* It is highly recommended that you provide all these different sizes to accommodate a full range of
|
||||
* devices currently available. However if you only have one icon in one size, make it 57x57 in size and
|
||||
* specify it as a string value. This same icon will be used on all supported devices.
|
||||
*
|
||||
* Ext.application({
|
||||
* icon: 'resources/icons/Icon.png',
|
||||
* launch: function() {
|
||||
* // ...
|
||||
* }
|
||||
* });
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {Object} startupImage
|
||||
* Specifies a set of URLs to the application startup images for different device form factors. This image is
|
||||
* displayed when the application is being launched from the Home Screen icon. Note that this currently only applies
|
||||
* to iOS devices.
|
||||
*
|
||||
* Ext.application({
|
||||
* startupImage: {
|
||||
* '320x460': 'resources/startup/320x460.jpg',
|
||||
* '640x920': 'resources/startup/640x920.png',
|
||||
* '640x1096': 'resources/startup/640x1096.png',
|
||||
* '768x1004': 'resources/startup/768x1004.png',
|
||||
* '748x1024': 'resources/startup/748x1024.png',
|
||||
* '1536x2008': 'resources/startup/1536x2008.png',
|
||||
* '1496x2048': 'resources/startup/1496x2048.png'
|
||||
* },
|
||||
* launch: function() {
|
||||
* // ...
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* Each key represents the dimension of the image. For example: '320x460' is the key for a 320px x 460px image.
|
||||
* Here is the breakdown of each dimension and its device target:
|
||||
*
|
||||
* - 320x460: Non-retina iPhone, iPod touch, and all Android devices
|
||||
* - 640x920: Retina iPhone and iPod touch
|
||||
* - 640x1096: iPhone 5 and iPod touch (fifth generation)
|
||||
* - 768x1004: Non-retina iPad (first and second generation) in portrait orientation
|
||||
* - 748x1024: Non-retina iPad (first and second generation) in landscape orientation
|
||||
* - 1536x2008: Retina iPad (third generation) in portrait orientation
|
||||
* - 1496x2048: Retina iPad (third generation) in landscape orientation
|
||||
*
|
||||
* Please note that there's no automatic fallback mechanism for the startup images. In other words, if you don't specify
|
||||
* a valid image for a certain device, nothing will be displayed while the application is being launched on that device.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} isIconPrecomposed
|
||||
* `true` to not having a glossy effect added to the icon by the OS, which will preserve its exact look. This currently
|
||||
* only applies to iOS devices.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {String} [statusBarStyle='black'] Allows you to set the style of the status bar when your app is added to the
|
||||
* home screen on iOS devices. Alternative is to set to 'black-translucent', which turns
|
||||
* the status bar semi-transparent and overlaps the app content. This is usually not a good option for web apps
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {String} tabletIcon Path to the _.png_ image file to use when your app is added to the home screen on an
|
||||
* iOS **tablet** device (iPad).
|
||||
* @deprecated 2.0.0 Please use the {@link #icon} configuration instead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {String} phoneIcon Path to the _.png_ image file to use when your app is added to the home screen on an
|
||||
* iOS **phone** device (iPhone or iPod).
|
||||
* @deprecated 2.0.0 Please use the {@link #icon} configuration instead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} glossOnIcon If set to `false`, the 'gloss' effect added to home screen {@link #icon icons} on
|
||||
* iOS devices will be removed.
|
||||
* @deprecated 2.0.0 Please use the {@link #isIconPrecomposed} configuration instead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {String} phoneStartupScreen Path to the _.png_ image file that will be displayed while the app is
|
||||
* starting up once it has been added to the home screen of an iOS phone device (iPhone or iPod). This _.png_
|
||||
* file should be 320px wide and 460px high.
|
||||
* @deprecated 2.0.0 Please use the {@link #startupImage} configuration instead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {String} tabletStartupScreen Path to the _.png_ image file that will be displayed while the app is
|
||||
* starting up once it has been added to the home screen of an iOS tablet device (iPad). This _.png_ file should
|
||||
* be 768px wide and 1004px high.
|
||||
* @deprecated 2.0.0 Please use the {@link #startupImage} configuration instead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {Array} profiles The set of profiles to load for this Application. Each profile is expected to
|
||||
* exist inside the *app/profile* directory and define a class following the convention
|
||||
* AppName.profile.ProfileName. For example, in the code below, the classes *AppName.profile.Phone*
|
||||
* and *AppName.profile.Tablet* will be loaded. Note that we are able to specify
|
||||
* either the full class name (as with *AppName.profile.Tablet*) or just the final part of the class name
|
||||
* and leave Application to automatically prepend *AppName.profile.'* to each:
|
||||
*
|
||||
* profiles: [
|
||||
* 'Phone',
|
||||
* 'AppName.profile.Tablet',
|
||||
* 'SomeCustomNamespace.profile.Desktop'
|
||||
* ]
|
||||
* @accessor
|
||||
*/
|
||||
profiles: [],
|
||||
|
||||
/**
|
||||
* @cfg {Array} controllers The set of controllers to load for this Application. Each controller is expected to
|
||||
* exist inside the *app/controller* directory and define a class following the convention
|
||||
* AppName.controller.ControllerName. For example, in the code below, the classes *AppName.controller.Users*,
|
||||
* *AppName.controller.Groups* and *AppName.controller.Products* will be loaded. Note that we are able to specify
|
||||
* either the full class name (as with *AppName.controller.Products*) or just the final part of the class name
|
||||
* and leave Application to automatically prepend *AppName.controller.'* to each:
|
||||
*
|
||||
* controllers: [
|
||||
* 'Users',
|
||||
* 'Groups',
|
||||
* 'AppName.controller.Products',
|
||||
* 'SomeCustomNamespace.controller.Orders'
|
||||
* ]
|
||||
* @accessor
|
||||
*/
|
||||
controllers: [],
|
||||
|
||||
/**
|
||||
* @cfg {Ext.app.History} history The global {@link Ext.app.History History} instance attached to this
|
||||
* Application.
|
||||
* @accessor
|
||||
* @readonly
|
||||
*/
|
||||
history: {},
|
||||
|
||||
/**
|
||||
* @cfg {String} name The name of the Application. This should be a single word without spaces or periods
|
||||
* because it is used as the Application's global namespace. All classes in your application should be
|
||||
* namespaced undef the Application's name - for example if your application name is 'MyApp', your classes
|
||||
* should be named 'MyApp.model.User', 'MyApp.controller.Users', 'MyApp.view.Main' etc
|
||||
* @accessor
|
||||
*/
|
||||
name: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} appFolder The path to the directory which contains all application's classes.
|
||||
* This path will be registered via {@link Ext.Loader#setPath} for the namespace specified in the {@link #name name} config.
|
||||
* @accessor
|
||||
*/
|
||||
appFolder : 'app',
|
||||
|
||||
/**
|
||||
* @cfg {Ext.app.Router} router The global {@link Ext.app.Router Router} instance attached to this Application.
|
||||
* @accessor
|
||||
* @readonly
|
||||
*/
|
||||
router: {},
|
||||
|
||||
/**
|
||||
* @cfg {Array} controllerInstances Used internally as the collection of instantiated controllers. Use {@link #getController} instead.
|
||||
* @private
|
||||
* @accessor
|
||||
*/
|
||||
controllerInstances: [],
|
||||
|
||||
/**
|
||||
* @cfg {Array} profileInstances Used internally as the collection of instantiated profiles.
|
||||
* @private
|
||||
* @accessor
|
||||
*/
|
||||
profileInstances: [],
|
||||
|
||||
/**
|
||||
* @cfg {Ext.app.Profile} currentProfile The {@link Ext.app.Profile Profile} that is currently active for the
|
||||
* Application. This is set once, automatically by the Application before launch.
|
||||
* @accessor
|
||||
* @readonly
|
||||
*/
|
||||
currentProfile: null,
|
||||
|
||||
/**
|
||||
* @cfg {Function} launch An optional function that will be called when the Application is ready to be
|
||||
* launched. This is normally used to render any initial UI required by your application
|
||||
* @accessor
|
||||
*/
|
||||
launch: Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Boolean} enableLoader Private config to disable loading of Profiles at application construct time.
|
||||
* This is used by Sencha's unit test suite to test _Application.js_ in isolation and is likely to be removed
|
||||
* in favor of a more pleasing solution by the time you use it.
|
||||
* @accessor
|
||||
*/
|
||||
enableLoader: true,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {String[]} requires An array of extra dependencies, to be required after this application's {@link #name} config
|
||||
* has been processed properly, but before anything else to ensure overrides get executed first.
|
||||
* @accessor
|
||||
*/
|
||||
requires: []
|
||||
},
|
||||
|
||||
/**
|
||||
* Constructs a new Application instance.
|
||||
*/
|
||||
constructor: function(config) {
|
||||
config = config || {};
|
||||
|
||||
Ext.applyIf(config, {
|
||||
application: this
|
||||
});
|
||||
|
||||
this.initConfig(config);
|
||||
|
||||
//it's common to pass in functions to an application but because they are not predictable config names they
|
||||
//aren't ordinarily placed onto this so we need to do it manually
|
||||
for (var key in config) {
|
||||
this[key] = config[key];
|
||||
}
|
||||
|
||||
// <deprecated product=touch since=2.0>
|
||||
if (config.autoCreateViewport) {
|
||||
Ext.Logger.deprecate(
|
||||
'[Ext.app.Application] autoCreateViewport has been deprecated in Sencha Touch 2. Please implement a ' +
|
||||
'launch function on your Application instead and use Ext.create("MyApp.view.Main") to create your initial UI.'
|
||||
);
|
||||
}
|
||||
// </deprecated>
|
||||
|
||||
//<debug>
|
||||
Ext.Loader.setConfig({ enabled: true });
|
||||
//</debug>
|
||||
|
||||
Ext.require(this.getRequires(), function() {
|
||||
if (this.getEnableLoader() !== false) {
|
||||
Ext.require(this.getProfiles(), this.onProfilesLoaded, this);
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Dispatches a given {@link Ext.app.Action} to the relevant Controller instance. This is not usually called
|
||||
* directly by the developer, instead Sencha Touch's History support picks up on changes to the browser's url
|
||||
* and calls dispatch automatically.
|
||||
* @param {Ext.app.Action} action The action to dispatch.
|
||||
* @param {Boolean} [addToHistory=true] Sets the browser's url to the action's url.
|
||||
*/
|
||||
dispatch: function(action, addToHistory) {
|
||||
action = action || {};
|
||||
Ext.applyIf(action, {
|
||||
application: this
|
||||
});
|
||||
|
||||
action = Ext.factory(action, Ext.app.Action);
|
||||
|
||||
if (action) {
|
||||
var profile = this.getCurrentProfile(),
|
||||
profileNS = profile ? profile.getNamespace() : undefined,
|
||||
controller = this.getController(action.getController(), profileNS);
|
||||
|
||||
if (controller) {
|
||||
if (addToHistory !== false) {
|
||||
this.getHistory().add(action, true);
|
||||
}
|
||||
|
||||
controller.execute(action);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Redirects the browser to the given url. This only affects the url after the '#'. You can pass in either a String
|
||||
* or a Model instance - if a Model instance is defined its {@link Ext.data.Model#toUrl toUrl} function is called,
|
||||
* which returns a string representing the url for that model. Internally, this uses your application's
|
||||
* {@link Ext.app.Router Router} to decode the url into a matching controller action and then calls
|
||||
* {@link #dispatch}.
|
||||
* @param {String/Ext.data.Model} url The String url to redirect to.
|
||||
*/
|
||||
redirectTo: function(url) {
|
||||
if (Ext.data && Ext.data.Model && url instanceof Ext.data.Model) {
|
||||
var record = url;
|
||||
|
||||
url = record.toUrl();
|
||||
}
|
||||
|
||||
var decoded = this.getRouter().recognize(url);
|
||||
|
||||
if (decoded) {
|
||||
decoded.url = url;
|
||||
if (record) {
|
||||
decoded.data = {};
|
||||
decoded.data.record = record;
|
||||
}
|
||||
return this.dispatch(decoded);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* (documented on Controller's control config)
|
||||
*/
|
||||
control: function(selectors, controller) {
|
||||
//if the controller is not defined, use this instead (the application instance)
|
||||
controller = controller || this;
|
||||
|
||||
var dispatcher = this.getEventDispatcher(),
|
||||
refs = (controller) ? controller.getRefs() : {},
|
||||
selector, eventName, listener, listeners, ref;
|
||||
|
||||
for (selector in selectors) {
|
||||
if (selectors.hasOwnProperty(selector)) {
|
||||
listeners = selectors[selector];
|
||||
ref = refs[selector];
|
||||
|
||||
//refs can be used in place of selectors
|
||||
if (ref) {
|
||||
selector = ref.selector || ref;
|
||||
}
|
||||
for (eventName in listeners) {
|
||||
listener = listeners[eventName];
|
||||
|
||||
if (Ext.isString(listener)) {
|
||||
listener = controller[listener];
|
||||
}
|
||||
|
||||
dispatcher.addListener('component', selector, eventName, listener, controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the Controller instance for the given controller name.
|
||||
* @param {String} name The name of the Controller.
|
||||
* @param {String} [profileName] Optional profile name. If passed, this is the same as calling
|
||||
* `getController('profileName.controllerName')`.
|
||||
*/
|
||||
getController: function(name, profileName) {
|
||||
var instances = this.getControllerInstances(),
|
||||
appName = this.getName(),
|
||||
format = Ext.String.format,
|
||||
topLevelName;
|
||||
|
||||
if (name instanceof Ext.app.Controller) {
|
||||
return name;
|
||||
}
|
||||
|
||||
if (instances[name]) {
|
||||
return instances[name];
|
||||
} else {
|
||||
topLevelName = format("{0}.controller.{1}", appName, name);
|
||||
profileName = format("{0}.controller.{1}.{2}", appName, profileName, name);
|
||||
|
||||
return instances[profileName] || instances[topLevelName];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Callback that is invoked when all of the configured Profiles have been loaded. Detects the current profile and
|
||||
* gathers any additional dependencies from that profile, then loads all of those dependencies.
|
||||
*/
|
||||
onProfilesLoaded: function() {
|
||||
var profiles = this.getProfiles(),
|
||||
length = profiles.length,
|
||||
instances = [],
|
||||
requires = this.gatherDependencies(),
|
||||
current, i, profileDeps;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
instances[i] = Ext.create(profiles[i], {
|
||||
application: this
|
||||
});
|
||||
|
||||
/*
|
||||
* Note that we actually require all of the dependencies for all Profiles - this is so that we can produce
|
||||
* a single build file that will work on all defined Profiles. Although the other classes will be loaded,
|
||||
* the correct Profile will still be identified and the other classes ignored. While this feels somewhat
|
||||
* inefficient, the majority of the bulk of an application is likely to be the framework itself. The bigger
|
||||
* the app though, the bigger the effect of this inefficiency so ideally we will create a way to create and
|
||||
* load Profile-specific builds in a future release.
|
||||
*/
|
||||
profileDeps = instances[i].getDependencies();
|
||||
requires = requires.concat(profileDeps.all);
|
||||
|
||||
if (instances[i].isActive() && !current) {
|
||||
current = instances[i];
|
||||
|
||||
this.setCurrentProfile(current);
|
||||
|
||||
this.setControllers(this.getControllers().concat(profileDeps.controller));
|
||||
this.setModels(this.getModels().concat(profileDeps.model));
|
||||
this.setViews(this.getViews().concat(profileDeps.view));
|
||||
this.setStores(this.getStores().concat(profileDeps.store));
|
||||
}
|
||||
}
|
||||
|
||||
this.setProfileInstances(instances);
|
||||
Ext.require(requires, this.loadControllerDependencies, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Controllers can also specify dependencies, so we grab them all here and require them.
|
||||
*/
|
||||
loadControllerDependencies: function() {
|
||||
this.instantiateControllers();
|
||||
|
||||
var controllers = this.getControllerInstances(),
|
||||
classes = [],
|
||||
stores = [],
|
||||
i, controller, controllerStores, name;
|
||||
|
||||
for (name in controllers) {
|
||||
controller = controllers[name];
|
||||
controllerStores = controller.getStores();
|
||||
stores = stores.concat(controllerStores);
|
||||
|
||||
classes = classes.concat(controller.getModels().concat(controller.getViews()).concat(controllerStores));
|
||||
}
|
||||
|
||||
this.setStores(this.getStores().concat(stores));
|
||||
|
||||
Ext.require(classes, this.onDependenciesLoaded, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Callback that is invoked when all of the Application, Controller and Profile dependencies have been loaded.
|
||||
* Launches the controllers, then the profile and application.
|
||||
*/
|
||||
onDependenciesLoaded: function() {
|
||||
var me = this,
|
||||
profile = this.getCurrentProfile(),
|
||||
launcher = this.getLaunch(),
|
||||
controllers, name;
|
||||
|
||||
this.instantiateStores();
|
||||
|
||||
//<deprecated product=touch since=2.0>
|
||||
Ext.app.Application.appInstance = this;
|
||||
|
||||
if (Ext.Router) {
|
||||
Ext.Router.setAppInstance(this);
|
||||
}
|
||||
//</deprecated>
|
||||
|
||||
controllers = this.getControllerInstances();
|
||||
|
||||
for (name in controllers) {
|
||||
controllers[name].init(this);
|
||||
}
|
||||
|
||||
if (profile) {
|
||||
profile.launch();
|
||||
}
|
||||
|
||||
launcher.call(me);
|
||||
|
||||
for (name in controllers) {
|
||||
//<debug warn>
|
||||
if (controllers[name] && !(controllers[name] instanceof Ext.app.Controller)) {
|
||||
Ext.Logger.warn("The controller '" + name + "' doesn't have a launch method. Are you sure it extends from Ext.app.Controller?");
|
||||
} else {
|
||||
//</debug>
|
||||
controllers[name].launch(this);
|
||||
//<debug warn>
|
||||
}
|
||||
//</debug>
|
||||
}
|
||||
|
||||
me.redirectTo(window.location.hash.substr(1));
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Gathers up all of the previously computed MVCS dependencies into a single array that we can pass to {@link Ext#require}.
|
||||
*/
|
||||
gatherDependencies: function() {
|
||||
var classes = this.getModels().concat(this.getViews()).concat(this.getControllers());
|
||||
|
||||
Ext.each(this.getStores(), function(storeName) {
|
||||
if (Ext.isString(storeName)) {
|
||||
classes.push(storeName);
|
||||
}
|
||||
}, this);
|
||||
|
||||
return classes;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Should be called after dependencies are loaded, instantiates all of the Stores specified in the {@link #stores}
|
||||
* config. For each item in the stores array we make sure the Store is instantiated. When strings are specified,
|
||||
* the corresponding _app/store/StoreName.js_ was loaded so we now instantiate a `MyApp.store.StoreName`, giving it the
|
||||
* id `StoreName`.
|
||||
*/
|
||||
instantiateStores: function() {
|
||||
var stores = this.getStores(),
|
||||
length = stores.length,
|
||||
store, storeClass, storeName, splits, i;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
store = stores[i];
|
||||
|
||||
if (Ext.data && Ext.data.Store && !(store instanceof Ext.data.Store)) {
|
||||
if (Ext.isString(store)) {
|
||||
storeName = store;
|
||||
storeClass = Ext.ClassManager.classes[store];
|
||||
|
||||
store = {
|
||||
xclass: store
|
||||
};
|
||||
|
||||
//we don't want to wipe out a configured storeId in the app's Store subclass so need
|
||||
//to check for this first
|
||||
if (storeClass.prototype.defaultConfig.storeId === undefined) {
|
||||
splits = storeName.split('.');
|
||||
store.id = splits[splits.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
stores[i] = Ext.factory(store, Ext.data.Store);
|
||||
}
|
||||
}
|
||||
|
||||
this.setStores(stores);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Called once all of our controllers have been loaded
|
||||
*/
|
||||
instantiateControllers: function() {
|
||||
var controllerNames = this.getControllers(),
|
||||
instances = {},
|
||||
length = controllerNames.length,
|
||||
name, i;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
name = controllerNames[i];
|
||||
|
||||
instances[name] = Ext.create(name, {
|
||||
application: this
|
||||
});
|
||||
}
|
||||
|
||||
return this.setControllerInstances(instances);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* As a convenience developers can locally qualify controller names (e.g. 'MyController' vs
|
||||
* 'MyApp.controller.MyController'). This just makes sure everything ends up fully qualified
|
||||
*/
|
||||
applyControllers: function(controllers) {
|
||||
return this.getFullyQualified(controllers, 'controller');
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* As a convenience developers can locally qualify profile names (e.g. 'MyProfile' vs
|
||||
* 'MyApp.profile.MyProfile'). This just makes sure everything ends up fully qualified
|
||||
*/
|
||||
applyProfiles: function(profiles) {
|
||||
return this.getFullyQualified(profiles, 'profile');
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Checks that the name configuration has any whitespace, and trims them if found.
|
||||
*/
|
||||
applyName: function(name) {
|
||||
var oldName;
|
||||
if (name && name.match(/ /g)) {
|
||||
oldName = name;
|
||||
name = name.replace(/ /g, "");
|
||||
|
||||
// <debug>
|
||||
Ext.Logger.warn('Attempting to create an application with a name which contains whitespace ("' + oldName + '"). Renamed to "' + name + '".');
|
||||
// </debug>
|
||||
}
|
||||
|
||||
return name;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Makes sure the app namespace exists, sets the `app` property of the namespace to this application and sets its
|
||||
* loading path (checks to make sure the path hadn't already been set via Ext.Loader.setPath)
|
||||
*/
|
||||
updateName: function(newName) {
|
||||
Ext.ClassManager.setNamespace(newName + '.app', this);
|
||||
|
||||
if (!Ext.Loader.config.paths[newName]) {
|
||||
Ext.Loader.setPath(newName, this.getAppFolder());
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyRouter: function(config) {
|
||||
return Ext.factory(config, Ext.app.Router, this.getRouter());
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyHistory: function(config) {
|
||||
var history = Ext.factory(config, Ext.app.History, this.getHistory());
|
||||
|
||||
history.on('change', this.onHistoryChange, this);
|
||||
|
||||
return history;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onHistoryChange: function(url) {
|
||||
this.dispatch(this.getRouter().recognize(url), false);
|
||||
}
|
||||
}, function() {
|
||||
// <deprecated product=touch since=2.0>
|
||||
Ext.regApplication = function(config) {
|
||||
Ext.Logger.deprecate(
|
||||
'[Ext.app.Application] Ext.regApplication() is deprecated, please replace it with Ext.application()'
|
||||
);
|
||||
|
||||
var appName = config.name,
|
||||
format = Ext.String.format;
|
||||
|
||||
Ext.ns(
|
||||
appName,
|
||||
format("{0}.controllers", appName),
|
||||
format("{0}.models", appName),
|
||||
format("{0}.views", appName)
|
||||
);
|
||||
|
||||
Ext.application(config);
|
||||
};
|
||||
|
||||
Ext.define('Ext.data.ProxyMgr', {
|
||||
singleton: true,
|
||||
|
||||
registerType: function(name, cls) {
|
||||
Ext.Logger.deprecate(
|
||||
'Ext.data.ProxyMgr no longer exists - instead of calling Ext.data.ProxyMgr.registerType just update ' +
|
||||
'your custom Proxy class to set alias: "proxy.' + name + '"'
|
||||
);
|
||||
|
||||
Ext.ClassManager.setAlias(cls, "proxy." + name);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.reg = function(alias, cls) {
|
||||
Ext.Logger.deprecate(
|
||||
'Ext.reg is deprecated, please set xtype: "' + alias + '" directly in your subclass instead'
|
||||
);
|
||||
|
||||
Ext.ClassManager.setAlias(cls, alias);
|
||||
};
|
||||
|
||||
Ext.redirect = function() {
|
||||
var app = Ext.app.Application.appInstance;
|
||||
|
||||
Ext.Logger.deprecate('[Ext.app.Application] Ext.redirect is deprecated, please use YourApp.redirectTo instead');
|
||||
|
||||
if (app) {
|
||||
app.redirectTo.apply(app, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
Ext.dispatch = function() {
|
||||
var app = Ext.app.Application.appInstance;
|
||||
|
||||
Ext.Logger.deprecate('[Ext.app.Application] Ext.dispatch is deprecated, please use YourApp.dispatch instead');
|
||||
|
||||
if (app) {
|
||||
app.dispatch.apply(app, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
// </deprecated>
|
||||
});
|
||||
747
OfficeWeb/3rdparty/touch/src/app/Controller.js
vendored
Normal file
747
OfficeWeb/3rdparty/touch/src/app/Controller.js
vendored
Normal file
@@ -0,0 +1,747 @@
|
||||
/**
|
||||
* @author Ed Spencer
|
||||
*
|
||||
* @aside guide controllers
|
||||
* @aside guide apps_intro
|
||||
* @aside guide history_support
|
||||
* @aside video mvc-part-1
|
||||
* @aside video mvc-part-2
|
||||
*
|
||||
* Controllers are responsible for responding to events that occur within your app. If your app contains a Logout
|
||||
* {@link Ext.Button button} that your user can tap on, a Controller would listen to the Button's tap event and take
|
||||
* the appropriate action. It allows the View classes to handle the display of data and the Model classes to handle the
|
||||
* loading and saving of data - the Controller is the glue that binds them together.
|
||||
*
|
||||
* ## Relation to Ext.app.Application
|
||||
*
|
||||
* Controllers exist within the context of an {@link Ext.app.Application Application}. An Application usually consists
|
||||
* of a number of Controllers, each of which handle a specific part of the app. For example, an Application that
|
||||
* handles the orders for an online shopping site might have controllers for Orders, Customers and Products.
|
||||
*
|
||||
* All of the Controllers that an Application uses are specified in the Application's
|
||||
* {@link Ext.app.Application#controllers} config. The Application automatically instantiates each Controller and keeps
|
||||
* references to each, so it is unusual to need to instantiate Controllers directly. By convention each Controller is
|
||||
* named after the thing (usually the Model) that it deals with primarily, usually in the plural - for example if your
|
||||
* app is called 'MyApp' and you have a Controller that manages Products, convention is to create a
|
||||
* MyApp.controller.Products class in the file app/controller/Products.js.
|
||||
*
|
||||
* ## Refs and Control
|
||||
*
|
||||
* The centerpiece of Controllers is the twin configurations {@link #refs} and {@link #cfg-control}. These are used to
|
||||
* easily gain references to Components inside your app and to take action on them based on events that they fire.
|
||||
* Let's look at {@link #refs} first:
|
||||
*
|
||||
* ### Refs
|
||||
*
|
||||
* Refs leverage the powerful {@link Ext.ComponentQuery ComponentQuery} syntax to easily locate Components on your
|
||||
* page. We can define as many refs as we like for each Controller, for example here we define a ref called 'nav' that
|
||||
* finds a Component on the page with the ID 'mainNav'. We then use that ref in the addLogoutButton beneath it:
|
||||
*
|
||||
* Ext.define('MyApp.controller.Main', {
|
||||
* extend: 'Ext.app.Controller',
|
||||
*
|
||||
* config: {
|
||||
* refs: {
|
||||
* nav: '#mainNav'
|
||||
* }
|
||||
* },
|
||||
*
|
||||
* addLogoutButton: function() {
|
||||
* this.getNav().add({
|
||||
* text: 'Logout'
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* Usually, a ref is just a key/value pair - the key ('nav' in this case) is the name of the reference that will be
|
||||
* generated, the value ('#mainNav' in this case) is the {@link Ext.ComponentQuery ComponentQuery} selector that will
|
||||
* be used to find the Component.
|
||||
*
|
||||
* Underneath that, we have created a simple function called addLogoutButton which uses this ref via its generated
|
||||
* 'getNav' function. These getter functions are generated based on the refs you define and always follow the same
|
||||
* format - 'get' followed by the capitalized ref name. In this case we're treating the nav reference as though it's a
|
||||
* {@link Ext.Toolbar Toolbar}, and adding a Logout button to it when our function is called. This ref would recognize
|
||||
* a Toolbar like this:
|
||||
*
|
||||
* Ext.create('Ext.Toolbar', {
|
||||
* id: 'mainNav',
|
||||
*
|
||||
* items: [
|
||||
* {
|
||||
* text: 'Some Button'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* Assuming this Toolbar has already been created by the time we run our 'addLogoutButton' function (we'll see how that
|
||||
* is invoked later), it will get the second button added to it.
|
||||
*
|
||||
* ### Advanced Refs
|
||||
*
|
||||
* Refs can also be passed a couple of additional options, beyond name and selector. These are autoCreate and xtype,
|
||||
* which are almost always used together:
|
||||
*
|
||||
* Ext.define('MyApp.controller.Main', {
|
||||
* extend: 'Ext.app.Controller',
|
||||
*
|
||||
* config: {
|
||||
* refs: {
|
||||
* nav: '#mainNav',
|
||||
*
|
||||
* infoPanel: {
|
||||
* selector: 'tabpanel panel[name=fish] infopanel',
|
||||
* xtype: 'infopanel',
|
||||
* autoCreate: true
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* We've added a second ref to our Controller. Again the name is the key, 'infoPanel' in this case, but this time we've
|
||||
* passed an object as the value instead. This time we've used a slightly more complex selector query - in this example
|
||||
* imagine that your app contains a {@link Ext.tab.Panel tab panel} and that one of the items in the tab panel has been
|
||||
* given the name 'fish'. Our selector matches any Component with the xtype 'infopanel' inside that tab panel item.
|
||||
*
|
||||
* The difference here is that if that infopanel does not exist already inside the 'fish' panel, it will be
|
||||
* automatically created when you call this.getInfoPanel inside your Controller. The Controller is able to do this
|
||||
* because we provided the xtype to instantiate with in the event that the selector did not return anything.
|
||||
*
|
||||
* ### Control
|
||||
*
|
||||
* The sister config to {@link #refs} is {@link #cfg-control}. {@link #cfg-control Control} is the means by which your listen
|
||||
* to events fired by Components and have your Controller react in some way. Control accepts both ComponentQuery
|
||||
* selectors and refs as its keys, and listener objects as values - for example:
|
||||
*
|
||||
* Ext.define('MyApp.controller.Main', {
|
||||
* extend: 'Ext.app.Controller',
|
||||
*
|
||||
* config: {
|
||||
* control: {
|
||||
* loginButton: {
|
||||
* tap: 'doLogin'
|
||||
* },
|
||||
* 'button[action=logout]': {
|
||||
* tap: 'doLogout'
|
||||
* }
|
||||
* },
|
||||
*
|
||||
* refs: {
|
||||
* loginButton: 'button[action=login]'
|
||||
* }
|
||||
* },
|
||||
*
|
||||
* doLogin: function() {
|
||||
* //called whenever the Login button is tapped
|
||||
* },
|
||||
*
|
||||
* doLogout: function() {
|
||||
* //called whenever any Button with action=logout is tapped
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* Here we have set up two control declarations - one for our loginButton ref and the other for any Button on the page
|
||||
* that has been given the action 'logout'. For each declaration we passed in a single event handler - in each case
|
||||
* listening for the 'tap' event, specifying the action that should be called when that Button fires the tap event.
|
||||
* Note that we specified the 'doLogin' and 'doLogout' methods as strings inside the control block - this is important.
|
||||
*
|
||||
* You can listen to as many events as you like in each control declaration, and mix and match ComponentQuery selectors
|
||||
* and refs as the keys.
|
||||
*
|
||||
* ## Routes
|
||||
*
|
||||
* As of Sencha Touch 2, Controllers can now directly specify which routes they are interested in. This enables us to
|
||||
* provide history support within our app, as well as the ability to deeply link to any part of the application that we
|
||||
* provide a route for.
|
||||
*
|
||||
* For example, let's say we have a Controller responsible for logging in and viewing user profiles, and want to make
|
||||
* those screens accessible via urls. We could achieve that like this:
|
||||
*
|
||||
* Ext.define('MyApp.controller.Users', {
|
||||
* extend: 'Ext.app.Controller',
|
||||
*
|
||||
* config: {
|
||||
* routes: {
|
||||
* 'login': 'showLogin',
|
||||
* 'user/:id': 'showUserById'
|
||||
* },
|
||||
*
|
||||
* refs: {
|
||||
* main: '#mainTabPanel'
|
||||
* }
|
||||
* },
|
||||
*
|
||||
* //uses our 'main' ref above to add a loginpanel to our main TabPanel (note that
|
||||
* //'loginpanel' is a custom xtype created for this application)
|
||||
* showLogin: function() {
|
||||
* this.getMain().add({
|
||||
* xtype: 'loginpanel'
|
||||
* });
|
||||
* },
|
||||
*
|
||||
* //Loads the User then adds a 'userprofile' view to the main TabPanel
|
||||
* showUserById: function(id) {
|
||||
* MyApp.model.User.load(id, {
|
||||
* scope: this,
|
||||
* success: function(user) {
|
||||
* this.getMain().add({
|
||||
* xtype: 'userprofile',
|
||||
* user: user
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* The routes we specified above simply map the contents of the browser address bar to a Controller function to call
|
||||
* when that route is matched. The routes can be simple text like the login route, which matches against
|
||||
* http://myapp.com/#login, or contain wildcards like the 'user/:id' route, which matches urls like
|
||||
* http://myapp.com/#user/123. Whenever the address changes the Controller automatically calls the function specified.
|
||||
*
|
||||
* Note that in the showUserById function we had to first load the User instance. Whenever you use a route, the
|
||||
* function that is called by that route is completely responsible for loading its data and restoring state. This is
|
||||
* because your user could either send that url to another person or simply refresh the page, which we wipe clear any
|
||||
* cached data you had already loaded. There is a more thorough discussion of restoring state with routes in the
|
||||
* application architecture guides.
|
||||
*
|
||||
* ## Advanced Usage
|
||||
*
|
||||
* See [the Controllers guide](#!/guide/controllers) for advanced Controller usage including before filters
|
||||
* and customizing for different devices.
|
||||
*/
|
||||
Ext.define('Ext.app.Controller', {
|
||||
mixins: {
|
||||
observable: "Ext.mixin.Observable"
|
||||
},
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Object} refs A collection of named {@link Ext.ComponentQuery ComponentQuery} selectors that makes it
|
||||
* easy to get references to key Components on your page. Example usage:
|
||||
*
|
||||
* refs: {
|
||||
* main: '#mainTabPanel',
|
||||
* loginButton: '#loginWindow button[action=login]',
|
||||
*
|
||||
* infoPanel: {
|
||||
* selector: 'infopanel',
|
||||
* xtype: 'infopanel',
|
||||
* autoCreate: true
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* The first two are simple ComponentQuery selectors, the third (infoPanel) also passes in the autoCreate and
|
||||
* xtype options, which will first run the ComponentQuery to see if a Component matching that selector exists
|
||||
* on the page. If not, it will automatically create one using the xtype provided:
|
||||
*
|
||||
* someControllerFunction: function() {
|
||||
* //if the info panel didn't exist before, calling its getter will instantiate
|
||||
* //it automatically and return the new instance
|
||||
* this.getInfoPanel().show();
|
||||
* }
|
||||
*
|
||||
* @accessor
|
||||
*/
|
||||
refs: {},
|
||||
|
||||
/**
|
||||
* @cfg {Object} routes Provides a mapping of urls to Controller actions. Whenever the specified url is matched
|
||||
* in the address bar, the specified Controller action is called. Example usage:
|
||||
*
|
||||
* routes: {
|
||||
* 'login': 'showLogin',
|
||||
* 'users/:id': 'showUserById'
|
||||
* }
|
||||
*
|
||||
* The first route will match against http://myapp.com/#login and call the Controller's showLogin function. The
|
||||
* second route contains a wildcard (':id') and will match all urls like http://myapp.com/#users/123, calling
|
||||
* the showUserById function with the matched ID as the first argument.
|
||||
*
|
||||
* @accessor
|
||||
*/
|
||||
routes: {},
|
||||
|
||||
/**
|
||||
* @cfg {Object} control Provides a mapping of Controller functions that should be called whenever certain
|
||||
* Component events are fired. The Components can be specified using {@link Ext.ComponentQuery ComponentQuery}
|
||||
* selectors or {@link #refs}. Example usage:
|
||||
*
|
||||
* control: {
|
||||
* 'button[action=logout]': {
|
||||
* tap: 'doLogout'
|
||||
* },
|
||||
* main: {
|
||||
* activeitemchange: 'doUpdate'
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* The first item uses a ComponentQuery selector to run the Controller's doLogout function whenever any Button
|
||||
* with action=logout is tapped on. The second calls the Controller's doUpdate function whenever the
|
||||
* activeitemchange event is fired by the Component referenced by our 'main' ref. In this case main is a tab
|
||||
* panel (see {@link #refs} for how to set that reference up).
|
||||
*
|
||||
* @accessor
|
||||
*/
|
||||
control: {},
|
||||
|
||||
/**
|
||||
* @cfg {Object} before Provides a mapping of Controller functions to filter functions that are run before them
|
||||
* when dispatched to from a route. These are usually used to run pre-processing functions like authentication
|
||||
* before a certain function is executed. They are only called when dispatching from a route. Example usage:
|
||||
*
|
||||
* Ext.define('MyApp.controller.Products', {
|
||||
* config: {
|
||||
* before: {
|
||||
* editProduct: 'authenticate'
|
||||
* },
|
||||
*
|
||||
* routes: {
|
||||
* 'product/edit/:id': 'editProduct'
|
||||
* }
|
||||
* },
|
||||
*
|
||||
* //this is not directly because our before filter is called first
|
||||
* editProduct: function() {
|
||||
* //... performs the product editing logic
|
||||
* },
|
||||
*
|
||||
* //this is run before editProduct
|
||||
* authenticate: function(action) {
|
||||
* MyApp.authenticate({
|
||||
* success: function() {
|
||||
* action.resume();
|
||||
* },
|
||||
* failure: function() {
|
||||
* Ext.Msg.alert('Not Logged In', "You can't do that, you're not logged in");
|
||||
* }
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* @accessor
|
||||
*/
|
||||
before: {},
|
||||
|
||||
/**
|
||||
* @cfg {Ext.app.Application} application The Application instance this Controller is attached to. This is
|
||||
* automatically provided when using the MVC architecture so should rarely need to be set directly.
|
||||
* @accessor
|
||||
*/
|
||||
application: {},
|
||||
|
||||
/**
|
||||
* @cfg {String[]} stores The set of stores to load for this Application. Each store is expected to
|
||||
* exist inside the *app/store* directory and define a class following the convention
|
||||
* AppName.store.StoreName. For example, in the code below, the *AppName.store.Users* class will be loaded.
|
||||
* Note that we are able to specify either the full class name (as with *AppName.store.Groups*) or just the
|
||||
* final part of the class name and leave Application to automatically prepend *AppName.store.'* to each:
|
||||
*
|
||||
* stores: [
|
||||
* 'Users',
|
||||
* 'AppName.store.Groups',
|
||||
* 'SomeCustomNamespace.store.Orders'
|
||||
* ]
|
||||
* @accessor
|
||||
*/
|
||||
stores: [],
|
||||
|
||||
/**
|
||||
* @cfg {String[]} models The set of models to load for this Application. Each model is expected to exist inside the
|
||||
* *app/model* directory and define a class following the convention AppName.model.ModelName. For example, in the
|
||||
* code below, the classes *AppName.model.User*, *AppName.model.Group* and *AppName.model.Product* will be loaded.
|
||||
* Note that we are able to specify either the full class name (as with *AppName.model.Product*) or just the
|
||||
* final part of the class name and leave Application to automatically prepend *AppName.model.* to each:
|
||||
*
|
||||
* models: [
|
||||
* 'User',
|
||||
* 'Group',
|
||||
* 'AppName.model.Product',
|
||||
* 'SomeCustomNamespace.model.Order'
|
||||
* ]
|
||||
* @accessor
|
||||
*/
|
||||
models: [],
|
||||
|
||||
/**
|
||||
* @cfg {Array} views The set of views to load for this Application. Each view is expected to exist inside the
|
||||
* *app/view* directory and define a class following the convention AppName.view.ViewName. For example, in the
|
||||
* code below, the classes *AppName.view.Users*, *AppName.view.Groups* and *AppName.view.Products* will be loaded.
|
||||
* Note that we are able to specify either the full class name (as with *AppName.view.Products*) or just the
|
||||
* final part of the class name and leave Application to automatically prepend *AppName.view.* to each:
|
||||
*
|
||||
* views: [
|
||||
* 'Users',
|
||||
* 'Groups',
|
||||
* 'AppName.view.Products',
|
||||
* 'SomeCustomNamespace.view.Orders'
|
||||
* ]
|
||||
* @accessor
|
||||
*/
|
||||
views: []
|
||||
},
|
||||
|
||||
/**
|
||||
* Constructs a new Controller instance
|
||||
*/
|
||||
constructor: function(config) {
|
||||
this.initConfig(config);
|
||||
|
||||
this.mixins.observable.constructor.call(this, config);
|
||||
},
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* Called by the Controller's {@link #application} to initialize the Controller. This is always called before the
|
||||
* {@link Ext.app.Application Application} launches, giving the Controller a chance to run any pre-launch logic.
|
||||
* See also {@link #launch}, which is called after the {@link Ext.app.Application#launch Application's launch function}
|
||||
*/
|
||||
init: Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* Called by the Controller's {@link #application} immediately after the Application's own
|
||||
* {@link Ext.app.Application#launch launch function} has been called. This is usually a good place to run any
|
||||
* logic that has to run after the app UI is initialized. See also {@link #init}, which is called before the
|
||||
* {@link Ext.app.Application#launch Application's launch function}.
|
||||
*/
|
||||
launch: Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* Convenient way to redirect to a new url. See {@link Ext.app.Application#redirectTo} for full usage information.
|
||||
* @return {Object}
|
||||
*/
|
||||
redirectTo: function(place) {
|
||||
return this.getApplication().redirectTo(place);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Executes an Ext.app.Action by giving it the correct before filters and kicking off execution
|
||||
*/
|
||||
execute: function(action, skipFilters) {
|
||||
action.setBeforeFilters(this.getBefore()[action.getAction()]);
|
||||
action.execute();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Massages the before filters into an array of function references for each controller action
|
||||
*/
|
||||
applyBefore: function(before) {
|
||||
var filters, name, length, i;
|
||||
|
||||
for (name in before) {
|
||||
filters = Ext.Array.from(before[name]);
|
||||
length = filters.length;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
filters[i] = this[filters[i]];
|
||||
}
|
||||
|
||||
before[name] = filters;
|
||||
}
|
||||
|
||||
return before;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyControl: function(config) {
|
||||
this.control(config, this);
|
||||
|
||||
return config;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyRefs: function(refs) {
|
||||
//<debug>
|
||||
if (Ext.isArray(refs)) {
|
||||
Ext.Logger.deprecate("In Sencha Touch 2 the refs config accepts an object but you have passed it an array.");
|
||||
}
|
||||
//</debug>
|
||||
|
||||
this.ref(refs);
|
||||
|
||||
return refs;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Adds any routes specified in this Controller to the global Application router
|
||||
*/
|
||||
applyRoutes: function(routes) {
|
||||
var app = this instanceof Ext.app.Application ? this : this.getApplication(),
|
||||
router = app.getRouter(),
|
||||
route, url, config;
|
||||
|
||||
for (url in routes) {
|
||||
route = routes[url];
|
||||
|
||||
config = {
|
||||
controller: this.$className
|
||||
};
|
||||
|
||||
if (Ext.isString(route)) {
|
||||
config.action = route;
|
||||
} else {
|
||||
Ext.apply(config, route);
|
||||
}
|
||||
|
||||
router.connect(url, config);
|
||||
}
|
||||
|
||||
return routes;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* As a convenience developers can locally qualify store names (e.g. 'MyStore' vs
|
||||
* 'MyApp.store.MyStore'). This just makes sure everything ends up fully qualified
|
||||
*/
|
||||
applyStores: function(stores) {
|
||||
return this.getFullyQualified(stores, 'store');
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* As a convenience developers can locally qualify model names (e.g. 'MyModel' vs
|
||||
* 'MyApp.model.MyModel'). This just makes sure everything ends up fully qualified
|
||||
*/
|
||||
applyModels: function(models) {
|
||||
return this.getFullyQualified(models, 'model');
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* As a convenience developers can locally qualify view names (e.g. 'MyView' vs
|
||||
* 'MyApp.view.MyView'). This just makes sure everything ends up fully qualified
|
||||
*/
|
||||
applyViews: function(views) {
|
||||
return this.getFullyQualified(views, 'view');
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Returns the fully qualified name for any class name variant. This is used to find the FQ name for the model,
|
||||
* view, controller, store and profiles listed in a Controller or Application.
|
||||
* @param {String[]} items The array of strings to get the FQ name for
|
||||
* @param {String} namespace If the name happens to be an application class, add it to this namespace
|
||||
* @return {String} The fully-qualified name of the class
|
||||
*/
|
||||
getFullyQualified: function(items, namespace) {
|
||||
var length = items.length,
|
||||
appName = this.getApplication().getName(),
|
||||
name, i;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
name = items[i];
|
||||
|
||||
//we check name === appName to allow MyApp.profile.MyApp to exist
|
||||
if (Ext.isString(name) && (Ext.Loader.getPrefix(name) === "" || name === appName)) {
|
||||
items[i] = appName + '.' + namespace + '.' + name;
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
control: function(selectors) {
|
||||
this.getApplication().control(selectors, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* 1.x-inspired ref implementation
|
||||
*/
|
||||
ref: function(refs) {
|
||||
var me = this,
|
||||
refName, getterName, selector, info;
|
||||
|
||||
for (refName in refs) {
|
||||
selector = refs[refName];
|
||||
getterName = "get" + Ext.String.capitalize(refName);
|
||||
|
||||
if (!this[getterName]) {
|
||||
if (Ext.isString(refs[refName])) {
|
||||
info = {
|
||||
ref: refName,
|
||||
selector: selector
|
||||
};
|
||||
} else {
|
||||
info = refs[refName];
|
||||
}
|
||||
|
||||
this[getterName] = function(refName, info) {
|
||||
var args = [refName, info];
|
||||
return function() {
|
||||
return me.getRef.apply(me, args.concat.apply(args, arguments));
|
||||
};
|
||||
}(refName, info);
|
||||
}
|
||||
|
||||
this.references = this.references || [];
|
||||
this.references.push(refName.toLowerCase());
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
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,
|
||||
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('destroy', function() {
|
||||
me.refCache[ref] = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return cached;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
hasRef: function(ref) {
|
||||
return this.references && this.references.indexOf(ref.toLowerCase()) !== -1;
|
||||
}
|
||||
|
||||
// <deprecated product=touch since=2.0>
|
||||
,onClassExtended: function(cls, members) {
|
||||
var prototype = this.prototype,
|
||||
defaultConfig = prototype.config,
|
||||
config = members.config || {},
|
||||
arrayRefs = members.refs,
|
||||
objectRefs = {},
|
||||
stores = members.stores,
|
||||
views = members.views,
|
||||
format = Ext.String.format,
|
||||
refItem, key, length, i, functionName;
|
||||
|
||||
// Convert deprecated properties in application into a config object
|
||||
for (key in defaultConfig) {
|
||||
if (key in members && key != "control") {
|
||||
if (key == "refs") {
|
||||
//we need to convert refs from the 1.x array-style to 2.x object-style
|
||||
for (i = 0; i < arrayRefs.length; i++) {
|
||||
refItem = arrayRefs[i];
|
||||
|
||||
objectRefs[refItem.ref] = refItem;
|
||||
}
|
||||
|
||||
config.refs = objectRefs;
|
||||
} else {
|
||||
config[key] = members[key];
|
||||
}
|
||||
|
||||
delete members[key];
|
||||
// <debug warn>
|
||||
Ext.Logger.deprecate(key + ' is deprecated as a property directly on the ' + this.$className + ' prototype. Please put it inside the config object.');
|
||||
// </debug>
|
||||
}
|
||||
}
|
||||
|
||||
if (stores) {
|
||||
length = stores.length;
|
||||
config.stores = stores;
|
||||
for (i = 0; i < length; i++) {
|
||||
functionName = format("get{0}Store", Ext.String.capitalize(stores[i]));
|
||||
|
||||
prototype[functionName] = function(name) {
|
||||
return function() {
|
||||
return Ext.StoreManager.lookup(name);
|
||||
};
|
||||
}(stores[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (views) {
|
||||
length = views.length;
|
||||
config.views = views;
|
||||
for (i = 0; i < length; i++) {
|
||||
functionName = format("get{0}View", views[i]);
|
||||
|
||||
prototype[functionName] = function(name) {
|
||||
return function() {
|
||||
return Ext.ClassManager.classes[format("{0}.view.{1}", this.getApplication().getName(), name)];
|
||||
};
|
||||
}(views[i]);
|
||||
}
|
||||
}
|
||||
|
||||
members.config = config;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a reference to a Model.
|
||||
* @param modelName
|
||||
* @return {Object}
|
||||
* @deprecated 2.0.0 Considered bad practice - please just use the Model name instead
|
||||
* (e.g. `MyApp.model.User` vs `this.getModel('User')`).
|
||||
*/
|
||||
getModel: function(modelName) {
|
||||
//<debug warn>
|
||||
Ext.Logger.deprecate("getModel() is deprecated and considered bad practice - please just use the Model " +
|
||||
"name instead (e.g. MyApp.model.User vs this.getModel('User'))");
|
||||
//</debug>
|
||||
|
||||
var appName = this.getApplication().getName(),
|
||||
classes = Ext.ClassManager.classes;
|
||||
|
||||
return classes[appName + '.model.' + modelName];
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a reference to another Controller.
|
||||
* @param controllerName
|
||||
* @param profile
|
||||
* @return {Object}
|
||||
* @deprecated 2.0.0 Considered bad practice - if you need to do this
|
||||
* please use this.getApplication().getController() instead
|
||||
*/
|
||||
getController: function(controllerName, profile) {
|
||||
//<debug warn>
|
||||
Ext.Logger.deprecate("Ext.app.Controller#getController is deprecated and considered bad practice - " +
|
||||
"please use this.getApplication().getController('someController') instead");
|
||||
//</debug>
|
||||
|
||||
return this.getApplication().getController(controllerName, profile);
|
||||
}
|
||||
// </deprecated>
|
||||
}, function() {
|
||||
// <deprecated product=touch since=2.0>
|
||||
Ext.regController = function(name, config) {
|
||||
Ext.apply(config, {
|
||||
extend: 'Ext.app.Controller'
|
||||
});
|
||||
|
||||
Ext.Logger.deprecate(
|
||||
'[Ext.app.Controller] Ext.regController is deprecated, please use Ext.define to define a Controller as ' +
|
||||
'with any other class. For more information see the Touch 1.x -> 2.x migration guide'
|
||||
);
|
||||
Ext.define('controller.' + name, config);
|
||||
};
|
||||
// </deprecated>
|
||||
});
|
||||
112
OfficeWeb/3rdparty/touch/src/app/History.js
vendored
Normal file
112
OfficeWeb/3rdparty/touch/src/app/History.js
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* @author Ed Spencer
|
||||
* @private
|
||||
*
|
||||
* Manages the stack of {@link Ext.app.Action} instances that have been decoded, pushes new urls into the browser's
|
||||
* location object and listens for changes in url, firing the {@link #change} event when a change is detected.
|
||||
*
|
||||
* This is tied to an {@link Ext.app.Application Application} instance. The Application performs all of the
|
||||
* interactions with the History object, no additional integration should be required.
|
||||
*/
|
||||
Ext.define('Ext.app.History', {
|
||||
mixins: ['Ext.mixin.Observable'],
|
||||
|
||||
/**
|
||||
* @event change
|
||||
* Fires when a change in browser url is detected
|
||||
* @param {String} url The new url, after the hash (e.g. http://myapp.com/#someUrl returns 'someUrl')
|
||||
*/
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Array} actions The stack of {@link Ext.app.Action action} instances that have occurred so far
|
||||
*/
|
||||
actions: [],
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} updateUrl `true` to automatically update the browser's url when {@link #add} is called.
|
||||
*/
|
||||
updateUrl: true,
|
||||
|
||||
/**
|
||||
* @cfg {String} token The current token as read from the browser's location object.
|
||||
*/
|
||||
token: ''
|
||||
},
|
||||
|
||||
constructor: function(config) {
|
||||
if (Ext.feature.has.History) {
|
||||
window.addEventListener('hashchange', Ext.bind(this.detectStateChange, this));
|
||||
}
|
||||
else {
|
||||
this.setToken(window.location.hash.substr(1));
|
||||
setInterval(Ext.bind(this.detectStateChange, this), 100);
|
||||
}
|
||||
|
||||
this.initConfig(config);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an {@link Ext.app.Action Action} to the stack, optionally updating the browser's url and firing the
|
||||
* {@link #change} event.
|
||||
* @param {Ext.app.Action} action The Action to add to the stack.
|
||||
* @param {Boolean} silent Cancels the firing of the {@link #change} event if `true`.
|
||||
*/
|
||||
add: function(action, silent) {
|
||||
this.getActions().push(Ext.factory(action, Ext.app.Action));
|
||||
|
||||
var url = action.getUrl();
|
||||
|
||||
if (this.getUpdateUrl()) {
|
||||
// history.pushState({}, action.getTitle(), "#" + action.getUrl());
|
||||
this.setToken(url);
|
||||
window.location.hash = url;
|
||||
}
|
||||
|
||||
if (silent !== true) {
|
||||
this.fireEvent('change', url);
|
||||
}
|
||||
|
||||
this.setToken(url);
|
||||
},
|
||||
|
||||
/**
|
||||
* Navigate to the previous active action. This changes the page url.
|
||||
*/
|
||||
back: function() {
|
||||
var actions = this.getActions(),
|
||||
previousAction = actions[actions.length - 2],
|
||||
app = previousAction.getController().getApplication();
|
||||
|
||||
actions.pop();
|
||||
|
||||
app.redirectTo(previousAction.getUrl());
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyToken: function(token) {
|
||||
return token[0] == '#' ? token.substr(1) : token;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
detectStateChange: function() {
|
||||
var newToken = this.applyToken(window.location.hash),
|
||||
oldToken = this.getToken();
|
||||
|
||||
if (newToken != oldToken) {
|
||||
this.onStateChange();
|
||||
this.setToken(newToken);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
onStateChange: function() {
|
||||
this.fireEvent('change', window.location.hash.substr(1));
|
||||
}
|
||||
});
|
||||
251
OfficeWeb/3rdparty/touch/src/app/Profile.js
vendored
Normal file
251
OfficeWeb/3rdparty/touch/src/app/Profile.js
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
/**
|
||||
* @author Ed Spencer
|
||||
*
|
||||
* A Profile represents a range of devices that fall under a common category. For the vast majority of apps that use
|
||||
* device profiles, the app defines a Phone profile and a Tablet profile. Doing this enables you to easily customize
|
||||
* the experience for the different sized screens offered by those device types.
|
||||
*
|
||||
* Only one Profile can be active at a time, and each Profile defines a simple {@link #isActive} function that should
|
||||
* return either true or false. The first Profile to return true from its isActive function is set as your Application's
|
||||
* {@link Ext.app.Application#currentProfile current profile}.
|
||||
*
|
||||
* A Profile can define any number of {@link #models}, {@link #views}, {@link #controllers} and {@link #stores} which
|
||||
* will be loaded if the Profile is activated. It can also define a {@link #launch} function that will be called after
|
||||
* all of its dependencies have been loaded, just before the {@link Ext.app.Application#launch application launch}
|
||||
* function is called.
|
||||
*
|
||||
* ## Sample Usage
|
||||
*
|
||||
* First you need to tell your Application about your Profile(s):
|
||||
*
|
||||
* Ext.application({
|
||||
* name: 'MyApp',
|
||||
* profiles: ['Phone', 'Tablet']
|
||||
* });
|
||||
*
|
||||
* This will load app/profile/Phone.js and app/profile/Tablet.js. Here's how we might define the Phone profile:
|
||||
*
|
||||
* Ext.define('MyApp.profile.Phone', {
|
||||
* extend: 'Ext.app.Profile',
|
||||
*
|
||||
* views: ['Main'],
|
||||
*
|
||||
* isActive: function() {
|
||||
* return Ext.os.is.Phone;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* The isActive function returns true if we detect that we are running on a phone device. If that is the case the
|
||||
* Application will set this Profile active and load the 'Main' view specified in the Profile's {@link #views} config.
|
||||
*
|
||||
* ## Class Specializations
|
||||
*
|
||||
* Because Profiles are specializations of an application, all of the models, views, controllers and stores defined
|
||||
* in a Profile are expected to be namespaced under the name of the Profile. Here's an expanded form of the example
|
||||
* above:
|
||||
*
|
||||
* Ext.define('MyApp.profile.Phone', {
|
||||
* extend: 'Ext.app.Profile',
|
||||
*
|
||||
* views: ['Main'],
|
||||
* controllers: ['Signup'],
|
||||
* models: ['MyApp.model.Group'],
|
||||
*
|
||||
* isActive: function() {
|
||||
* return Ext.os.is.Phone;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* In this case, the Profile is going to load *app/view/phone/Main.js*, *app/controller/phone/Signup.js* and
|
||||
* *app/model/Group.js*. Notice that in each of the first two cases the name of the profile ('phone' in this case) was
|
||||
* injected into the class names. In the third case we specified the full Model name (for Group) so the Profile name
|
||||
* was not injected.
|
||||
*
|
||||
* For a fuller understanding of the ideas behind Profiles and how best to use them in your app, we suggest you read
|
||||
* the [device profiles guide](#!/guide/profiles).
|
||||
*
|
||||
* @aside guide profiles
|
||||
*/
|
||||
Ext.define('Ext.app.Profile', {
|
||||
mixins: {
|
||||
observable: "Ext.mixin.Observable"
|
||||
},
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} namespace The namespace that this Profile's classes can be found in. Defaults to the lowercased
|
||||
* Profile {@link #name}, for example a Profile called MyApp.profile.Phone will by default have a 'phone'
|
||||
* namespace, which means that this Profile's additional models, stores, views and controllers will be loaded
|
||||
* from the MyApp.model.phone.*, MyApp.store.phone.*, MyApp.view.phone.* and MyApp.controller.phone.* namespaces
|
||||
* respectively.
|
||||
* @accessor
|
||||
*/
|
||||
namespace: 'auto',
|
||||
|
||||
/**
|
||||
* @cfg {String} name The name of this Profile. Defaults to the last section of the class name (e.g. a profile
|
||||
* called MyApp.profile.Phone will default the name to 'Phone').
|
||||
* @accessor
|
||||
*/
|
||||
name: 'auto',
|
||||
|
||||
/**
|
||||
* @cfg {Array} controllers Any additional {@link Ext.app.Application#controllers Controllers} to load for this
|
||||
* profile. Note that each item here will be prepended with the Profile namespace when loaded. Example usage:
|
||||
*
|
||||
* controllers: [
|
||||
* 'Users',
|
||||
* 'MyApp.controller.Products'
|
||||
* ]
|
||||
*
|
||||
* This will load *MyApp.controller.tablet.Users* and *MyApp.controller.Products*.
|
||||
* @accessor
|
||||
*/
|
||||
controllers: [],
|
||||
|
||||
/**
|
||||
* @cfg {Array} models Any additional {@link Ext.app.Application#models Models} to load for this profile. Note
|
||||
* that each item here will be prepended with the Profile namespace when loaded. Example usage:
|
||||
*
|
||||
* models: [
|
||||
* 'Group',
|
||||
* 'MyApp.model.User'
|
||||
* ]
|
||||
*
|
||||
* This will load *MyApp.model.tablet.Group* and *MyApp.model.User*.
|
||||
* @accessor
|
||||
*/
|
||||
models: [],
|
||||
|
||||
/**
|
||||
* @cfg {Array} views Any additional {@link Ext.app.Application#views views} to load for this profile. Note
|
||||
* that each item here will be prepended with the Profile namespace when loaded. Example usage:
|
||||
*
|
||||
* views: [
|
||||
* 'Main',
|
||||
* 'MyApp.view.Login'
|
||||
* ]
|
||||
*
|
||||
* This will load *MyApp.view.tablet.Main* and *MyApp.view.Login*.
|
||||
* @accessor
|
||||
*/
|
||||
views: [],
|
||||
|
||||
/**
|
||||
* @cfg {Array} stores Any additional {@link Ext.app.Application#stores Stores} to load for this profile. Note
|
||||
* that each item here will be prepended with the Profile namespace when loaded. Example usage:
|
||||
*
|
||||
* stores: [
|
||||
* 'Users',
|
||||
* 'MyApp.store.Products'
|
||||
* ]
|
||||
*
|
||||
* This will load *MyApp.store.tablet.Users* and *MyApp.store.Products*.
|
||||
* @accessor
|
||||
*/
|
||||
stores: [],
|
||||
|
||||
/**
|
||||
* @cfg {Ext.app.Application} application The {@link Ext.app.Application Application} instance that this
|
||||
* Profile is bound to. This is set automatically.
|
||||
* @accessor
|
||||
* @readonly
|
||||
*/
|
||||
application: null
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a new Profile instance
|
||||
*/
|
||||
constructor: function(config) {
|
||||
this.initConfig(config);
|
||||
|
||||
this.mixins.observable.constructor.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether or not this Profile is active on the device isActive is executed on. Should return true if
|
||||
* this profile is meant to be active on this device, false otherwise. Each Profile should implement this function
|
||||
* (the default implementation just returns false).
|
||||
* @return {Boolean} True if this Profile should be activated on the device it is running on, false otherwise
|
||||
*/
|
||||
isActive: function() {
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* @method
|
||||
* The launch function is called by the {@link Ext.app.Application Application} if this Profile's {@link #isActive}
|
||||
* function returned true. This is typically the best place to run any profile-specific app launch code. Example
|
||||
* usage:
|
||||
*
|
||||
* launch: function() {
|
||||
* Ext.create('MyApp.view.tablet.Main');
|
||||
* }
|
||||
*/
|
||||
launch: Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyNamespace: function(name) {
|
||||
if (name == 'auto') {
|
||||
name = this.getName();
|
||||
}
|
||||
|
||||
return name.toLowerCase();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
applyName: function(name) {
|
||||
if (name == 'auto') {
|
||||
var pieces = this.$className.split('.');
|
||||
name = pieces[pieces.length - 1];
|
||||
}
|
||||
|
||||
return name;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Computes the full class names of any specified model, view, controller and store dependencies, returns them in
|
||||
* an object map for easy loading
|
||||
*/
|
||||
getDependencies: function() {
|
||||
var allClasses = [],
|
||||
format = Ext.String.format,
|
||||
appName = this.getApplication().getName(),
|
||||
namespace = this.getNamespace(),
|
||||
map = {
|
||||
model: this.getModels(),
|
||||
view: this.getViews(),
|
||||
controller: this.getControllers(),
|
||||
store: this.getStores()
|
||||
},
|
||||
classType, classNames, fullyQualified;
|
||||
|
||||
for (classType in map) {
|
||||
classNames = [];
|
||||
|
||||
Ext.each(map[classType], function(className) {
|
||||
if (Ext.isString(className)) {
|
||||
//we check name === appName to allow MyApp.profile.MyApp to exist
|
||||
if (Ext.isString(className) && (Ext.Loader.getPrefix(className) === "" || className === appName)) {
|
||||
className = appName + '.' + classType + '.' + namespace + '.' + className;
|
||||
}
|
||||
|
||||
classNames.push(className);
|
||||
allClasses.push(className);
|
||||
}
|
||||
}, this);
|
||||
|
||||
map[classType] = classNames;
|
||||
}
|
||||
|
||||
map.all = allClasses;
|
||||
|
||||
return map;
|
||||
}
|
||||
});
|
||||
208
OfficeWeb/3rdparty/touch/src/app/Route.js
vendored
Normal file
208
OfficeWeb/3rdparty/touch/src/app/Route.js
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* @author Ed Spencer
|
||||
* @private
|
||||
*
|
||||
* Represents a mapping between a url and a controller/action pair. May also contain additional params. This is a
|
||||
* private internal class that should not need to be used by end-developer code. Its API and existence are subject to
|
||||
* change so use at your own risk.
|
||||
*
|
||||
* For information on how to use routes we suggest reading the following guides:
|
||||
*
|
||||
* - [Using History Support](#!/guide/history_support)
|
||||
* - [Intro to Applications](#!/guide/apps_intro)
|
||||
* - [Using Controllers](#!/guide/controllers)
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.app.Route', {
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Object} conditions Optional set of conditions for each token in the url string. Each key should be one
|
||||
* of the tokens, each value should be a regex that the token should accept. For example, if you have a Route
|
||||
* with a url like "files/:fileName" and you want it to match urls like "files/someImage.jpg" then you can set
|
||||
* these conditions to allow the :fileName token to accept strings containing a period ("."):
|
||||
*
|
||||
* conditions: {
|
||||
* ':fileName': "[0-9a-zA-Z\.]+"
|
||||
* }
|
||||
*
|
||||
*/
|
||||
conditions: {},
|
||||
|
||||
/**
|
||||
* @cfg {String} url (required) The url regex to match against.
|
||||
*/
|
||||
url: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} controller The name of the Controller whose {@link #action} will be called if this route is
|
||||
* matched.
|
||||
*/
|
||||
controller: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} action The name of the action that will be called on the {@link #controller} if this route is
|
||||
* matched.
|
||||
*/
|
||||
action: null,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Boolean} initialized Indicates whether or not this Route has been initialized. We don't initialize
|
||||
* straight away so as to save unnecessary processing.
|
||||
*/
|
||||
initialized: false
|
||||
},
|
||||
|
||||
constructor: function(config) {
|
||||
this.initConfig(config);
|
||||
},
|
||||
|
||||
/**
|
||||
* Attempts to recognize a given url string and return controller/action pair for it.
|
||||
* @param {String} url The url to recognize.
|
||||
* @return {Object/Boolean} The matched data, or `false` if no match.
|
||||
*/
|
||||
recognize: function(url) {
|
||||
if (!this.getInitialized()) {
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
if (this.recognizes(url)) {
|
||||
var matches = this.matchesFor(url),
|
||||
args = url.match(this.matcherRegex);
|
||||
|
||||
args.shift();
|
||||
|
||||
return Ext.applyIf(matches, {
|
||||
controller: this.getController(),
|
||||
action : this.getAction(),
|
||||
historyUrl: url,
|
||||
args : args
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Sets up the relevant regular expressions used to match against this route.
|
||||
*/
|
||||
initialize: function() {
|
||||
/*
|
||||
* The regular expression we use to match a segment of a route mapping
|
||||
* this will recognize segments starting with a colon,
|
||||
* e.g. on 'namespace/:controller/:action', :controller and :action will be recognized
|
||||
*/
|
||||
this.paramMatchingRegex = new RegExp(/:([0-9A-Za-z\_]*)/g);
|
||||
|
||||
/*
|
||||
* Converts a route string into an array of symbols starting with a colon. e.g.
|
||||
* ":controller/:action/:id" => [':controller', ':action', ':id']
|
||||
*/
|
||||
this.paramsInMatchString = this.getUrl().match(this.paramMatchingRegex) || [];
|
||||
|
||||
this.matcherRegex = this.createMatcherRegex(this.getUrl());
|
||||
|
||||
this.setInitialized(true);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Returns true if this Route matches the given url string
|
||||
* @param {String} url The url to test
|
||||
* @return {Boolean} True if this Route recognizes the url
|
||||
*/
|
||||
recognizes: function(url) {
|
||||
return this.matcherRegex.test(url);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Returns a hash of matching url segments for the given url.
|
||||
* @param {String} url The url to extract matches for
|
||||
* @return {Object} matching url segments
|
||||
*/
|
||||
matchesFor: function(url) {
|
||||
var params = {},
|
||||
keys = this.paramsInMatchString,
|
||||
values = url.match(this.matcherRegex),
|
||||
length = keys.length,
|
||||
i;
|
||||
|
||||
//first value is the entire match so reject
|
||||
values.shift();
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
params[keys[i].replace(":", "")] = values[i];
|
||||
}
|
||||
|
||||
return params;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Returns an array of matching url segments for the given url.
|
||||
* @param {String} url The url to extract matches for
|
||||
* @return {Array} matching url segments
|
||||
*/
|
||||
argsFor: function(url) {
|
||||
var args = [],
|
||||
keys = this.paramsInMatchString,
|
||||
values = url.match(this.matcherRegex),
|
||||
length = keys.length,
|
||||
i;
|
||||
|
||||
//first value is the entire match so reject
|
||||
values.shift();
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
args.push(keys[i].replace(':', ""));
|
||||
params[keys[i].replace(":", "")] = values[i];
|
||||
}
|
||||
|
||||
return params;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Constructs a url for the given config object by replacing wildcard placeholders in the Route's url
|
||||
* @param {Object} config The config object
|
||||
* @return {String} The constructed url
|
||||
*/
|
||||
urlFor: function(config) {
|
||||
var url = this.getUrl();
|
||||
|
||||
for (var key in config) {
|
||||
url = url.replace(":" + key, config[key]);
|
||||
}
|
||||
|
||||
return url;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Takes the configured url string including wildcards and returns a regex that can be used to match
|
||||
* against a url
|
||||
* @param {String} url The url string
|
||||
* @return {RegExp} The matcher regex
|
||||
*/
|
||||
createMatcherRegex: function(url) {
|
||||
/**
|
||||
* Converts a route string into an array of symbols starting with a colon. e.g.
|
||||
* ":controller/:action/:id" => [':controller', ':action', ':id']
|
||||
*/
|
||||
var paramsInMatchString = this.paramsInMatchString,
|
||||
length = paramsInMatchString.length,
|
||||
i, cond, matcher;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
cond = this.getConditions()[paramsInMatchString[i]];
|
||||
matcher = Ext.util.Format.format("({0})", cond || "[%a-zA-Z0-9\-\\_\\s,]+");
|
||||
|
||||
url = url.replace(new RegExp(paramsInMatchString[i]), matcher);
|
||||
}
|
||||
|
||||
//we want to match the whole string, so include the anchors
|
||||
return new RegExp("^" + url + "$");
|
||||
}
|
||||
});
|
||||
137
OfficeWeb/3rdparty/touch/src/app/Router.js
vendored
Normal file
137
OfficeWeb/3rdparty/touch/src/app/Router.js
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @author Ed Spencer
|
||||
* @private
|
||||
*
|
||||
* The Router is an ordered set of route definitions that decode a url into a controller function to execute. Each
|
||||
* route defines a type of url to match, along with the controller function to call if it is matched. The Router is
|
||||
* usually managed exclusively by an {@link Ext.app.Application Application}, which also uses a
|
||||
* {@link Ext.app.History History} instance to find out when the browser's url has changed.
|
||||
*
|
||||
* Routes are almost always defined inside a {@link Ext.app.Controller Controller}, as opposed to on the Router itself.
|
||||
* End-developers should not usually need to interact directly with the Router as the Application and Controller
|
||||
* classes manage everything automatically. See the {@link Ext.app.Controller Controller documentation} for more
|
||||
* information on specifying routes.
|
||||
*/
|
||||
Ext.define('Ext.app.Router', {
|
||||
requires: ['Ext.app.Route'],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Array} routes The set of routes contained within this Router.
|
||||
* @readonly
|
||||
*/
|
||||
routes: [],
|
||||
|
||||
/**
|
||||
* @cfg {Object} defaults Default configuration options for each Route connected to this Router.
|
||||
*/
|
||||
defaults: {
|
||||
action: 'index'
|
||||
}
|
||||
},
|
||||
|
||||
constructor: function(config) {
|
||||
this.initConfig(config);
|
||||
},
|
||||
|
||||
/**
|
||||
* Connects a url-based route to a controller/action pair plus additional params.
|
||||
* @param {String} url The url to recognize.
|
||||
*/
|
||||
connect: function(url, params) {
|
||||
params = Ext.apply({url: url}, params || {}, this.getDefaults());
|
||||
var route = Ext.create('Ext.app.Route', params);
|
||||
|
||||
this.getRoutes().push(route);
|
||||
|
||||
return route;
|
||||
},
|
||||
|
||||
/**
|
||||
* Recognizes a url string connected to the Router, return the controller/action pair plus any additional
|
||||
* config associated with it.
|
||||
* @param {String} url The url to recognize.
|
||||
* @return {Object/undefined} If the url was recognized, the controller and action to call, else `undefined`.
|
||||
*/
|
||||
recognize: function(url) {
|
||||
var routes = this.getRoutes(),
|
||||
length = routes.length,
|
||||
i, result;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
result = routes[i].recognize(url);
|
||||
|
||||
if (result !== undefined) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Convenience method which just calls the supplied function with the Router instance. Example usage:
|
||||
*
|
||||
* Ext.Router.draw(function(map) {
|
||||
* map.connect('activate/:token', {controller: 'users', action: 'activate'});
|
||||
* map.connect('home', {controller: 'index', action: 'home'});
|
||||
* });
|
||||
*
|
||||
* @param {Function} fn The fn to call
|
||||
*/
|
||||
draw: function(fn) {
|
||||
fn.call(this, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
clear: function() {
|
||||
this.setRoutes([]);
|
||||
}
|
||||
}, function() {
|
||||
//<deprecated product=touch since=2.0>
|
||||
/**
|
||||
* Restores compatibility for the old `Ext.Router.draw` syntax. This needs to be here because apps often include
|
||||
* _routes.js_ just after _app.js_, so this is our only opportunity to hook this in. There is a small piece of code
|
||||
* inside Application's {@link Ext.app.Application#onDependenciesLoaded onDependenciesLoaded} that sets up the other end of this.
|
||||
* @singleton
|
||||
* @private
|
||||
*/
|
||||
Ext.Router = {};
|
||||
|
||||
var drawStack = [];
|
||||
|
||||
/**
|
||||
* Application's {@link Ext.app.Application#onDependenciesLoaded onDependenciesLoaded} has a deprecated-wrapped line that calls this. Basic idea is that once an
|
||||
* app has been instantiated we set that at Ext.Router's `appInstance` and then redirect any calls to
|
||||
* {@link Ext.app.Router#draw Ext.Router.draw} to that app's Router. We keep a `drawStack` above so that we can call {@link Ext.app.Router#draw Ext.Router.draw} one or
|
||||
* more times before the application is even instantiated and it will simply link it up once everything is
|
||||
* present.
|
||||
*/
|
||||
Ext.Router.setAppInstance = function(app) {
|
||||
Ext.Router.appInstance = app;
|
||||
|
||||
if (drawStack.length > 0) {
|
||||
Ext.each(drawStack, Ext.Router.draw);
|
||||
}
|
||||
};
|
||||
|
||||
Ext.Router.draw = function(mapperFn) {
|
||||
Ext.Logger.deprecate(
|
||||
'Ext.Router.map is deprecated, please define your routes inline inside each Controller. ' +
|
||||
'Please see the 1.x -> 2.x migration guide for more details.'
|
||||
);
|
||||
|
||||
var app = Ext.Router.appInstance,
|
||||
router;
|
||||
|
||||
if (app) {
|
||||
router = app.getRouter();
|
||||
mapperFn(router);
|
||||
} else {
|
||||
drawStack.push(mapperFn);
|
||||
}
|
||||
};
|
||||
//</deprecated>
|
||||
});
|
||||
112
OfficeWeb/3rdparty/touch/src/bb/CrossCut.js
vendored
Normal file
112
OfficeWeb/3rdparty/touch/src/bb/CrossCut.js
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* A class to replicate the behavior of the Contextual menu in BlackBerry 10.
|
||||
*
|
||||
* More information: http://docs.blackberry.com/en/developers/deliverables/41577/contextual_menus.jsp
|
||||
*
|
||||
* var menu = Ext.create('Ext.bb.CrossCut', {
|
||||
* items: [
|
||||
* {
|
||||
* text: 'New',
|
||||
* iconMask: true,
|
||||
* iconCls: 'compose'
|
||||
* },
|
||||
* {
|
||||
* text: 'Reply',
|
||||
* iconMask: true,
|
||||
* iconCls: 'reply'
|
||||
* },
|
||||
* {
|
||||
* text: 'Settings',
|
||||
* iconMask: true,
|
||||
* iconCls: 'settings'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*/
|
||||
Ext.define('Ext.bb.CrossCut', {
|
||||
extend: 'Ext.Sheet',
|
||||
xtype: 'crosscut',
|
||||
|
||||
requires: [
|
||||
'Ext.Button'
|
||||
],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
top: 0,
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
right: 0,
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
bottom: 0,
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
left: null,
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
enter: 'right',
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
exit: 'right',
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
hideOnMaskTap: true,
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
baseCls: 'bb-crosscut',
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
layout: {
|
||||
type: 'vbox',
|
||||
pack: 'middle'
|
||||
},
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
defaultType: 'button',
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
showAnimation: {
|
||||
preserveEndState: true,
|
||||
to: {
|
||||
width: 275
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
hideAnimation: {
|
||||
preserveEndState: true,
|
||||
to: {
|
||||
width: 68
|
||||
}
|
||||
},
|
||||
|
||||
defaults: {
|
||||
baseCls: 'bb-crosscut-item'
|
||||
}
|
||||
}
|
||||
});
|
||||
12
OfficeWeb/3rdparty/touch/src/behavior/Behavior.js
vendored
Normal file
12
OfficeWeb/3rdparty/touch/src/behavior/Behavior.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.behavior.Behavior', {
|
||||
constructor: function(component) {
|
||||
this.component = component;
|
||||
|
||||
component.on('destroy', 'onComponentDestroy', this);
|
||||
},
|
||||
|
||||
onComponentDestroy: Ext.emptyFn
|
||||
});
|
||||
52
OfficeWeb/3rdparty/touch/src/behavior/Draggable.js
vendored
Normal file
52
OfficeWeb/3rdparty/touch/src/behavior/Draggable.js
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.behavior.Draggable', {
|
||||
|
||||
extend: 'Ext.behavior.Behavior',
|
||||
|
||||
requires: [
|
||||
'Ext.util.Draggable'
|
||||
],
|
||||
|
||||
setConfig: function(config) {
|
||||
var draggable = this.draggable,
|
||||
component = this.component;
|
||||
|
||||
if (config) {
|
||||
if (!draggable) {
|
||||
component.setTranslatable(true);
|
||||
this.draggable = draggable = new Ext.util.Draggable(config);
|
||||
draggable.setTranslatable(component.getTranslatable());
|
||||
draggable.setElement(component.renderElement);
|
||||
draggable.on('destroy', 'onDraggableDestroy', this);
|
||||
|
||||
component.on(this.listeners);
|
||||
}
|
||||
else if (Ext.isObject(config)) {
|
||||
draggable.setConfig(config);
|
||||
}
|
||||
}
|
||||
else if (draggable) {
|
||||
draggable.destroy();
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
getDraggable: function() {
|
||||
return this.draggable;
|
||||
},
|
||||
|
||||
onDraggableDestroy: function() {
|
||||
delete this.draggable;
|
||||
},
|
||||
|
||||
onComponentDestroy: function() {
|
||||
var draggable = this.draggable;
|
||||
|
||||
if (draggable) {
|
||||
draggable.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
0
OfficeWeb/3rdparty/touch/src/behavior/Droppable.js
vendored
Normal file
0
OfficeWeb/3rdparty/touch/src/behavior/Droppable.js
vendored
Normal file
89
OfficeWeb/3rdparty/touch/src/behavior/Scrollable.js
vendored
Normal file
89
OfficeWeb/3rdparty/touch/src/behavior/Scrollable.js
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.behavior.Scrollable', {
|
||||
|
||||
extend: 'Ext.behavior.Behavior',
|
||||
|
||||
requires: [
|
||||
'Ext.scroll.View'
|
||||
],
|
||||
|
||||
constructor: function() {
|
||||
this.listeners = {
|
||||
painted: 'onComponentPainted',
|
||||
scope: this
|
||||
};
|
||||
|
||||
this.callParent(arguments);
|
||||
},
|
||||
|
||||
onComponentPainted: function() {
|
||||
this.scrollView.refresh();
|
||||
},
|
||||
|
||||
setConfig: function(config) {
|
||||
var scrollView = this.scrollView,
|
||||
component = this.component,
|
||||
scrollerElement;
|
||||
|
||||
if (config) {
|
||||
if (!scrollView) {
|
||||
this.scrollView = scrollView = new Ext.scroll.View(config);
|
||||
scrollView.on('destroy', 'onScrollViewDestroy', this);
|
||||
|
||||
component.setUseBodyElement(true);
|
||||
|
||||
this.scrollerElement = scrollerElement = component.innerElement;
|
||||
this.scrollContainer = scrollerElement.wrap();
|
||||
|
||||
scrollView.setElement(component.bodyElement);
|
||||
|
||||
if (component.isPainted()) {
|
||||
this.onComponentPainted(component);
|
||||
}
|
||||
|
||||
component.on(this.listeners);
|
||||
}
|
||||
else if (Ext.isString(config) || Ext.isObject(config)) {
|
||||
scrollView.setConfig(config);
|
||||
}
|
||||
}
|
||||
else if (scrollView) {
|
||||
scrollView.destroy();
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
getScrollView: function() {
|
||||
return this.scrollView;
|
||||
},
|
||||
|
||||
onScrollViewDestroy: function() {
|
||||
var component = this.component,
|
||||
scrollerElement = this.scrollerElement;
|
||||
|
||||
if (!scrollerElement.isDestroyed) {
|
||||
this.scrollerElement.unwrap();
|
||||
}
|
||||
|
||||
this.scrollContainer.destroy();
|
||||
|
||||
if (!component.isDestroyed) {
|
||||
component.un(this.listeners);
|
||||
}
|
||||
|
||||
delete this.scrollerElement;
|
||||
delete this.scrollView;
|
||||
delete this.scrollContainer;
|
||||
},
|
||||
|
||||
onComponentDestroy: function() {
|
||||
var scrollView = this.scrollView;
|
||||
|
||||
if (scrollView) {
|
||||
scrollView.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
0
OfficeWeb/3rdparty/touch/src/behavior/Sortable.js
vendored
Normal file
0
OfficeWeb/3rdparty/touch/src/behavior/Sortable.js
vendored
Normal file
48
OfficeWeb/3rdparty/touch/src/behavior/Translatable.js
vendored
Normal file
48
OfficeWeb/3rdparty/touch/src/behavior/Translatable.js
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.behavior.Translatable', {
|
||||
|
||||
extend: 'Ext.behavior.Behavior',
|
||||
|
||||
requires: [
|
||||
'Ext.util.Translatable'
|
||||
],
|
||||
|
||||
setConfig: function(config) {
|
||||
var translatable = this.translatable,
|
||||
component = this.component;
|
||||
|
||||
if (config) {
|
||||
if (!translatable) {
|
||||
this.translatable = translatable = new Ext.util.Translatable(config);
|
||||
translatable.setElement(component.renderElement);
|
||||
translatable.on('destroy', 'onTranslatableDestroy', this);
|
||||
}
|
||||
else if (Ext.isObject(config)) {
|
||||
translatable.setConfig(config);
|
||||
}
|
||||
}
|
||||
else if (translatable) {
|
||||
translatable.destroy();
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
getTranslatable: function() {
|
||||
return this.translatable;
|
||||
},
|
||||
|
||||
onTranslatableDestroy: function() {
|
||||
delete this.translatable;
|
||||
},
|
||||
|
||||
onComponentDestroy: function() {
|
||||
var translatable = this.translatable;
|
||||
|
||||
if (translatable) {
|
||||
translatable.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
843
OfficeWeb/3rdparty/touch/src/carousel/Carousel.js
vendored
Normal file
843
OfficeWeb/3rdparty/touch/src/carousel/Carousel.js
vendored
Normal file
@@ -0,0 +1,843 @@
|
||||
/**
|
||||
* @class Ext.carousel.Carousel
|
||||
* @author Jacky Nguyen <jacky@sencha.com>
|
||||
*
|
||||
* Carousels, like [tabs](#!/guide/tabs), are a great way to allow the user to swipe through multiple full-screen pages.
|
||||
* A Carousel shows only one of its pages at a time but allows you to swipe through with your finger.
|
||||
*
|
||||
* Carousels can be oriented either horizontally or vertically and are easy to configure - they just work like any other
|
||||
* Container. Here's how to set up a simple horizontal Carousel:
|
||||
*
|
||||
* @example
|
||||
* Ext.create('Ext.Carousel', {
|
||||
* fullscreen: true,
|
||||
*
|
||||
* defaults: {
|
||||
* styleHtmlContent: true
|
||||
* },
|
||||
*
|
||||
* items: [
|
||||
* {
|
||||
* html : 'Item 1',
|
||||
* style: 'background-color: #5E99CC'
|
||||
* },
|
||||
* {
|
||||
* html : 'Item 2',
|
||||
* style: 'background-color: #759E60'
|
||||
* },
|
||||
* {
|
||||
* html : 'Item 3'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* We can also make Carousels orient themselves vertically:
|
||||
*
|
||||
* @example preview
|
||||
* Ext.create('Ext.Carousel', {
|
||||
* fullscreen: true,
|
||||
* direction: 'vertical',
|
||||
*
|
||||
* defaults: {
|
||||
* styleHtmlContent: true
|
||||
* },
|
||||
*
|
||||
* items: [
|
||||
* {
|
||||
* html : 'Item 1',
|
||||
* style: 'background-color: #759E60'
|
||||
* },
|
||||
* {
|
||||
* html : 'Item 2',
|
||||
* style: 'background-color: #5E99CC'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* ### Common Configurations
|
||||
* * {@link #ui} defines the style of the carousel
|
||||
* * {@link #direction} defines the direction of the carousel
|
||||
* * {@link #indicator} defines if the indicator show be shown
|
||||
*
|
||||
* ### Useful Methods
|
||||
* * {@link #next} moves to the next card
|
||||
* * {@link #previous} moves to the previous card
|
||||
* * {@link #setActiveItem} moves to the passed card
|
||||
*
|
||||
* ## Further Reading
|
||||
*
|
||||
* For more information about Carousels see the [Carousel guide](#!/guide/carousel).
|
||||
*
|
||||
* @aside guide carousel
|
||||
* @aside example carousel
|
||||
*/
|
||||
Ext.define('Ext.carousel.Carousel', {
|
||||
extend: 'Ext.Container',
|
||||
|
||||
alternateClassName: 'Ext.Carousel',
|
||||
|
||||
xtype: 'carousel',
|
||||
|
||||
requires: [
|
||||
'Ext.fx.easing.EaseOut',
|
||||
'Ext.carousel.Item',
|
||||
'Ext.carousel.Indicator',
|
||||
'Ext.util.TranslatableGroup'
|
||||
],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg layout
|
||||
* Hide layout config in Carousel. It only causes confusion.
|
||||
* @accessor
|
||||
* @private
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: 'x-carousel',
|
||||
|
||||
/**
|
||||
* @cfg {String} direction
|
||||
* The direction of the Carousel, either 'horizontal' or 'vertical'.
|
||||
* @accessor
|
||||
*/
|
||||
direction: 'horizontal',
|
||||
|
||||
directionLock: false,
|
||||
|
||||
animation: {
|
||||
duration: 250,
|
||||
easing: {
|
||||
type: 'ease-out'
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} indicator
|
||||
* Provides an indicator while toggling between child items to let the user
|
||||
* know where they are in the card stack.
|
||||
* @accessor
|
||||
*/
|
||||
indicator: true,
|
||||
|
||||
/**
|
||||
* @cfg {String} ui
|
||||
* Style options for Carousel. Default is 'dark'. 'light' is also available.
|
||||
* @accessor
|
||||
*/
|
||||
ui: 'dark',
|
||||
|
||||
itemConfig: {},
|
||||
|
||||
bufferSize: 1,
|
||||
|
||||
itemLength: null
|
||||
},
|
||||
|
||||
itemLength: 0,
|
||||
|
||||
offset: 0,
|
||||
|
||||
flickStartOffset: 0,
|
||||
|
||||
flickStartTime: 0,
|
||||
|
||||
dragDirection: 0,
|
||||
|
||||
count: 0,
|
||||
|
||||
painted: false,
|
||||
|
||||
activeIndex: -1,
|
||||
|
||||
beforeInitialize: function() {
|
||||
this.element.on({
|
||||
dragstart: 'onDragStart',
|
||||
drag: 'onDrag',
|
||||
dragend: 'onDragEnd',
|
||||
scope: this
|
||||
});
|
||||
|
||||
this.element.on('resize', 'onSizeChange', this);
|
||||
|
||||
this.carouselItems = [];
|
||||
|
||||
this.orderedCarouselItems = [];
|
||||
|
||||
this.inactiveCarouselItems = [];
|
||||
|
||||
this.hiddenTranslation = 0;
|
||||
},
|
||||
|
||||
updateBufferSize: function(size) {
|
||||
var ItemClass = Ext.carousel.Item,
|
||||
total = size * 2 + 1,
|
||||
isRendered = this.isRendered(),
|
||||
innerElement = this.innerElement,
|
||||
items = this.carouselItems,
|
||||
ln = items.length,
|
||||
itemConfig = this.getItemConfig(),
|
||||
itemLength = this.getItemLength(),
|
||||
direction = this.getDirection(),
|
||||
setterName = direction === 'horizontal' ? 'setWidth' : 'setHeight',
|
||||
i, item;
|
||||
|
||||
for (i = ln; i < total; i++) {
|
||||
item = Ext.factory(itemConfig, ItemClass);
|
||||
|
||||
if (itemLength) {
|
||||
item[setterName].call(item, itemLength);
|
||||
}
|
||||
item.setLayoutSizeFlags(this.LAYOUT_BOTH);
|
||||
items.push(item);
|
||||
innerElement.append(item.renderElement);
|
||||
|
||||
if (isRendered && item.setRendered(true)) {
|
||||
item.fireEvent('renderedchange', this, item, true);
|
||||
}
|
||||
}
|
||||
|
||||
this.getTranslatable().setActiveIndex(size);
|
||||
},
|
||||
|
||||
setRendered: function(rendered) {
|
||||
var wasRendered = this.rendered;
|
||||
|
||||
if (rendered !== wasRendered) {
|
||||
this.rendered = rendered;
|
||||
|
||||
var items = this.items.items,
|
||||
carouselItems = this.carouselItems,
|
||||
i, ln, item;
|
||||
|
||||
for (i = 0,ln = items.length; i < ln; i++) {
|
||||
item = items[i];
|
||||
|
||||
if (!item.isInnerItem()) {
|
||||
item.setRendered(rendered);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0,ln = carouselItems.length; i < ln; i++) {
|
||||
carouselItems[i].setRendered(rendered);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
onSizeChange: function() {
|
||||
this.refreshSizing();
|
||||
this.refreshCarouselItems();
|
||||
this.refreshActiveItem();
|
||||
},
|
||||
|
||||
onItemAdd: function(item, index) {
|
||||
this.callParent(arguments);
|
||||
|
||||
var innerIndex = this.getInnerItems().indexOf(item),
|
||||
indicator = this.getIndicator();
|
||||
|
||||
if (indicator && item.isInnerItem()) {
|
||||
indicator.addIndicator();
|
||||
}
|
||||
|
||||
if (innerIndex <= this.getActiveIndex()) {
|
||||
this.refreshActiveIndex();
|
||||
}
|
||||
|
||||
if (this.isIndexDirty(innerIndex) && !this.isItemsInitializing) {
|
||||
this.refreshActiveItem();
|
||||
}
|
||||
},
|
||||
|
||||
doItemLayoutAdd: function(item) {
|
||||
if (item.isInnerItem()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.callParent(arguments);
|
||||
},
|
||||
|
||||
onItemRemove: function(item, index) {
|
||||
this.callParent(arguments);
|
||||
|
||||
var innerIndex = this.getInnerItems().indexOf(item),
|
||||
indicator = this.getIndicator(),
|
||||
carouselItems = this.carouselItems,
|
||||
i, ln, carouselItem;
|
||||
|
||||
if (item.isInnerItem() && indicator) {
|
||||
indicator.removeIndicator();
|
||||
}
|
||||
|
||||
if (innerIndex <= this.getActiveIndex()) {
|
||||
this.refreshActiveIndex();
|
||||
}
|
||||
|
||||
if (this.isIndexDirty(innerIndex)) {
|
||||
for (i = 0,ln = carouselItems.length; i < ln; i++) {
|
||||
carouselItem = carouselItems[i];
|
||||
|
||||
if (carouselItem.getComponent() === item) {
|
||||
carouselItem.setComponent(null);
|
||||
}
|
||||
}
|
||||
|
||||
this.refreshActiveItem();
|
||||
}
|
||||
},
|
||||
|
||||
doItemLayoutRemove: function(item) {
|
||||
if (item.isInnerItem()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.callParent(arguments);
|
||||
},
|
||||
|
||||
onInnerItemMove: function(item, toIndex, fromIndex) {
|
||||
if ((this.isIndexDirty(toIndex) || this.isIndexDirty(fromIndex))) {
|
||||
this.refreshActiveItem();
|
||||
}
|
||||
},
|
||||
|
||||
doItemLayoutMove: function(item) {
|
||||
if (item.isInnerItem()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.callParent(arguments);
|
||||
},
|
||||
|
||||
isIndexDirty: function(index) {
|
||||
var activeIndex = this.getActiveIndex(),
|
||||
bufferSize = this.getBufferSize();
|
||||
|
||||
return (index >= activeIndex - bufferSize && index <= activeIndex + bufferSize);
|
||||
},
|
||||
|
||||
getTranslatable: function() {
|
||||
var translatable = this.translatable;
|
||||
|
||||
if (!translatable) {
|
||||
this.translatable = translatable = new Ext.util.TranslatableGroup;
|
||||
translatable.setItems(this.orderedCarouselItems);
|
||||
translatable.on('animationend', 'onAnimationEnd', this);
|
||||
}
|
||||
|
||||
return translatable;
|
||||
},
|
||||
|
||||
onDragStart: function(e) {
|
||||
var direction = this.getDirection(),
|
||||
absDeltaX = e.absDeltaX,
|
||||
absDeltaY = e.absDeltaY,
|
||||
directionLock = this.getDirectionLock();
|
||||
|
||||
this.isDragging = true;
|
||||
|
||||
if (directionLock) {
|
||||
if ((direction === 'horizontal' && absDeltaX > absDeltaY)
|
||||
|| (direction === 'vertical' && absDeltaY > absDeltaX)) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
else {
|
||||
this.isDragging = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.getTranslatable().stopAnimation();
|
||||
|
||||
this.dragStartOffset = this.offset;
|
||||
this.dragDirection = 0;
|
||||
},
|
||||
|
||||
onDrag: function(e) {
|
||||
if (!this.isDragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
var startOffset = this.dragStartOffset,
|
||||
direction = this.getDirection(),
|
||||
delta = direction === 'horizontal' ? e.deltaX : e.deltaY,
|
||||
lastOffset = this.offset,
|
||||
flickStartTime = this.flickStartTime,
|
||||
dragDirection = this.dragDirection,
|
||||
now = Ext.Date.now(),
|
||||
currentActiveIndex = this.getActiveIndex(),
|
||||
maxIndex = this.getMaxItemIndex(),
|
||||
lastDragDirection = dragDirection,
|
||||
offset;
|
||||
|
||||
if ((currentActiveIndex === 0 && delta > 0) || (currentActiveIndex === maxIndex && delta < 0)) {
|
||||
delta *= 0.5;
|
||||
}
|
||||
|
||||
offset = startOffset + delta;
|
||||
|
||||
if (offset > lastOffset) {
|
||||
dragDirection = 1;
|
||||
}
|
||||
else if (offset < lastOffset) {
|
||||
dragDirection = -1;
|
||||
}
|
||||
|
||||
if (dragDirection !== lastDragDirection || (now - flickStartTime) > 300) {
|
||||
this.flickStartOffset = lastOffset;
|
||||
this.flickStartTime = now;
|
||||
}
|
||||
|
||||
this.dragDirection = dragDirection;
|
||||
|
||||
this.setOffset(offset);
|
||||
},
|
||||
|
||||
onDragEnd: function(e) {
|
||||
if (!this.isDragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.onDrag(e);
|
||||
|
||||
this.isDragging = false;
|
||||
|
||||
var now = Ext.Date.now(),
|
||||
itemLength = this.itemLength,
|
||||
threshold = itemLength / 2,
|
||||
offset = this.offset,
|
||||
activeIndex = this.getActiveIndex(),
|
||||
maxIndex = this.getMaxItemIndex(),
|
||||
animationDirection = 0,
|
||||
flickDistance = offset - this.flickStartOffset,
|
||||
flickDuration = now - this.flickStartTime,
|
||||
indicator = this.getIndicator(),
|
||||
velocity;
|
||||
|
||||
if (flickDuration > 0 && Math.abs(flickDistance) >= 10) {
|
||||
velocity = flickDistance / flickDuration;
|
||||
|
||||
if (Math.abs(velocity) >= 1) {
|
||||
if (velocity < 0 && activeIndex < maxIndex) {
|
||||
animationDirection = -1;
|
||||
}
|
||||
else if (velocity > 0 && activeIndex > 0) {
|
||||
animationDirection = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (animationDirection === 0) {
|
||||
if (activeIndex < maxIndex && offset < -threshold) {
|
||||
animationDirection = -1;
|
||||
}
|
||||
else if (activeIndex > 0 && offset > threshold) {
|
||||
animationDirection = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (indicator) {
|
||||
indicator.setActiveIndex(activeIndex - animationDirection);
|
||||
}
|
||||
|
||||
this.animationDirection = animationDirection;
|
||||
|
||||
this.setOffsetAnimated(animationDirection * itemLength);
|
||||
},
|
||||
|
||||
applyAnimation: function(animation) {
|
||||
animation.easing = Ext.factory(animation.easing, Ext.fx.easing.EaseOut);
|
||||
|
||||
return animation;
|
||||
},
|
||||
|
||||
updateDirection: function(direction) {
|
||||
var indicator = this.getIndicator();
|
||||
|
||||
this.currentAxis = (direction === 'horizontal') ? 'x' : 'y';
|
||||
|
||||
if (indicator) {
|
||||
indicator.setDirection(direction);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @chainable
|
||||
*/
|
||||
setOffset: function(offset) {
|
||||
this.offset = offset;
|
||||
|
||||
this.getTranslatable().translateAxis(this.currentAxis, offset + this.itemOffset);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {Ext.carousel.Carousel} this
|
||||
* @chainable
|
||||
*/
|
||||
setOffsetAnimated: function(offset) {
|
||||
var indicator = this.getIndicator();
|
||||
|
||||
if (indicator) {
|
||||
indicator.setActiveIndex(this.getActiveIndex() - this.animationDirection);
|
||||
}
|
||||
|
||||
this.offset = offset;
|
||||
|
||||
this.getTranslatable().translateAxis(this.currentAxis, offset + this.itemOffset, this.getAnimation());
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
onAnimationEnd: function(translatable) {
|
||||
var currentActiveIndex = this.getActiveIndex(),
|
||||
animationDirection = this.animationDirection,
|
||||
axis = this.currentAxis,
|
||||
currentOffset = translatable[axis],
|
||||
itemLength = this.itemLength,
|
||||
offset;
|
||||
|
||||
if (animationDirection === -1) {
|
||||
offset = itemLength + currentOffset;
|
||||
}
|
||||
else if (animationDirection === 1) {
|
||||
offset = currentOffset - itemLength;
|
||||
}
|
||||
else {
|
||||
offset = currentOffset;
|
||||
}
|
||||
|
||||
offset -= this.itemOffset;
|
||||
this.offset = offset;
|
||||
this.setActiveItem(currentActiveIndex - animationDirection);
|
||||
},
|
||||
|
||||
refresh: function() {
|
||||
this.refreshSizing();
|
||||
this.refreshActiveItem();
|
||||
},
|
||||
|
||||
refreshSizing: function() {
|
||||
var element = this.element,
|
||||
itemLength = this.getItemLength(),
|
||||
translatableItemLength = {
|
||||
x: 0,
|
||||
y: 0
|
||||
},
|
||||
itemOffset, containerSize;
|
||||
|
||||
if (this.getDirection() === 'horizontal') {
|
||||
containerSize = element.getWidth();
|
||||
}
|
||||
else {
|
||||
containerSize = element.getHeight();
|
||||
}
|
||||
|
||||
this.hiddenTranslation = -containerSize;
|
||||
|
||||
if (itemLength === null) {
|
||||
itemLength = containerSize;
|
||||
itemOffset = 0;
|
||||
}
|
||||
else {
|
||||
itemOffset = (containerSize - itemLength) / 2;
|
||||
}
|
||||
|
||||
this.itemLength = itemLength;
|
||||
this.itemOffset = itemOffset;
|
||||
translatableItemLength[this.currentAxis] = itemLength;
|
||||
this.getTranslatable().setItemLength(translatableItemLength);
|
||||
},
|
||||
|
||||
refreshOffset: function() {
|
||||
this.setOffset(this.offset);
|
||||
},
|
||||
|
||||
refreshActiveItem: function() {
|
||||
this.doSetActiveItem(this.getActiveItem());
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the index of the currently active card.
|
||||
* @return {Number} The index of the currently active card.
|
||||
*/
|
||||
getActiveIndex: function() {
|
||||
return this.activeIndex;
|
||||
},
|
||||
|
||||
refreshActiveIndex: function() {
|
||||
this.activeIndex = this.getInnerItemIndex(this.getActiveItem());
|
||||
},
|
||||
|
||||
refreshCarouselItems: function() {
|
||||
var items = this.carouselItems,
|
||||
i, ln, item;
|
||||
|
||||
for (i = 0,ln = items.length; i < ln; i++) {
|
||||
item = items[i];
|
||||
item.getTranslatable().refresh();
|
||||
}
|
||||
|
||||
this.refreshInactiveCarouselItems();
|
||||
},
|
||||
|
||||
refreshInactiveCarouselItems: function() {
|
||||
var items = this.inactiveCarouselItems,
|
||||
hiddenTranslation = this.hiddenTranslation,
|
||||
axis = this.currentAxis,
|
||||
i, ln, item;
|
||||
|
||||
for (i = 0,ln = items.length; i < ln; i++) {
|
||||
item = items[i];
|
||||
item.translateAxis(axis, hiddenTranslation);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {Number}
|
||||
*/
|
||||
getMaxItemIndex: function() {
|
||||
return this.innerItems.length - 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {Number}
|
||||
*/
|
||||
getInnerItemIndex: function(item) {
|
||||
return this.innerItems.indexOf(item);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {Object}
|
||||
*/
|
||||
getInnerItemAt: function(index) {
|
||||
return this.innerItems[index];
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {Object}
|
||||
*/
|
||||
applyActiveItem: function() {
|
||||
var activeItem = this.callParent(arguments),
|
||||
activeIndex;
|
||||
|
||||
if (activeItem) {
|
||||
activeIndex = this.getInnerItemIndex(activeItem);
|
||||
|
||||
if (activeIndex !== -1) {
|
||||
this.activeIndex = activeIndex;
|
||||
return activeItem;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
doSetActiveItem: function(activeItem) {
|
||||
var activeIndex = this.getActiveIndex(),
|
||||
maxIndex = this.getMaxItemIndex(),
|
||||
indicator = this.getIndicator(),
|
||||
bufferSize = this.getBufferSize(),
|
||||
carouselItems = this.carouselItems.slice(),
|
||||
orderedCarouselItems = this.orderedCarouselItems,
|
||||
visibleIndexes = {},
|
||||
visibleItems = {},
|
||||
visibleItem, component, id, i, index, ln, carouselItem;
|
||||
|
||||
if (carouselItems.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.callParent(arguments);
|
||||
|
||||
orderedCarouselItems.length = 0;
|
||||
|
||||
if (activeItem) {
|
||||
id = activeItem.getId();
|
||||
visibleItems[id] = activeItem;
|
||||
visibleIndexes[id] = bufferSize;
|
||||
|
||||
if (activeIndex > 0) {
|
||||
for (i = 1; i <= bufferSize; i++) {
|
||||
index = activeIndex - i;
|
||||
if (index >= 0) {
|
||||
visibleItem = this.getInnerItemAt(index);
|
||||
id = visibleItem.getId();
|
||||
visibleItems[id] = visibleItem;
|
||||
visibleIndexes[id] = bufferSize - i;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (activeIndex < maxIndex) {
|
||||
for (i = 1; i <= bufferSize; i++) {
|
||||
index = activeIndex + i;
|
||||
if (index <= maxIndex) {
|
||||
visibleItem = this.getInnerItemAt(index);
|
||||
id = visibleItem.getId();
|
||||
visibleItems[id] = visibleItem;
|
||||
visibleIndexes[id] = bufferSize + i;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0,ln = carouselItems.length; i < ln; i++) {
|
||||
carouselItem = carouselItems[i];
|
||||
component = carouselItem.getComponent();
|
||||
|
||||
if (component) {
|
||||
id = component.getId();
|
||||
|
||||
if (visibleIndexes.hasOwnProperty(id)) {
|
||||
carouselItems.splice(i, 1);
|
||||
i--;
|
||||
ln--;
|
||||
delete visibleItems[id];
|
||||
orderedCarouselItems[visibleIndexes[id]] = carouselItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (id in visibleItems) {
|
||||
if (visibleItems.hasOwnProperty(id)) {
|
||||
visibleItem = visibleItems[id];
|
||||
carouselItem = carouselItems.pop();
|
||||
carouselItem.setComponent(visibleItem);
|
||||
orderedCarouselItems[visibleIndexes[id]] = carouselItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.inactiveCarouselItems.length = 0;
|
||||
this.inactiveCarouselItems = carouselItems;
|
||||
this.refreshOffset();
|
||||
this.refreshInactiveCarouselItems();
|
||||
|
||||
if (indicator) {
|
||||
indicator.setActiveIndex(activeIndex);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Switches to the next card.
|
||||
* @return {Ext.carousel.Carousel} this
|
||||
* @chainable
|
||||
*/
|
||||
next: function() {
|
||||
this.setOffset(0);
|
||||
|
||||
if (this.activeIndex === this.getMaxItemIndex()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.animationDirection = -1;
|
||||
this.setOffsetAnimated(-this.itemLength);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Switches to the previous card.
|
||||
* @return {Ext.carousel.Carousel} this
|
||||
* @chainable
|
||||
*/
|
||||
previous: function() {
|
||||
this.setOffset(0);
|
||||
|
||||
if (this.activeIndex === 0) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.animationDirection = 1;
|
||||
this.setOffsetAnimated(this.itemLength);
|
||||
return this;
|
||||
},
|
||||
|
||||
// @private
|
||||
applyIndicator: function(indicator, currentIndicator) {
|
||||
return Ext.factory(indicator, Ext.carousel.Indicator, currentIndicator);
|
||||
},
|
||||
|
||||
// @private
|
||||
updateIndicator: function(indicator) {
|
||||
if (indicator) {
|
||||
this.insertFirst(indicator);
|
||||
|
||||
indicator.setUi(this.getUi());
|
||||
indicator.on({
|
||||
next: 'next',
|
||||
previous: 'previous',
|
||||
scope: this
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
var carouselItems = this.carouselItems.slice();
|
||||
|
||||
this.carouselItems.length = 0;
|
||||
|
||||
Ext.destroy(carouselItems, this.getIndicator(), this.translatable);
|
||||
|
||||
this.callParent();
|
||||
delete this.carouselItems;
|
||||
}
|
||||
|
||||
}, function() {
|
||||
//<deprecated product=touch since=2.0>
|
||||
this.override({
|
||||
constructor: function(config) {
|
||||
if (config && 'activeIndex' in config) {
|
||||
//<debug warn>
|
||||
Ext.Logger.deprecate("'activeIndex' config is deprecated, please use 'activeItem' config instead }");
|
||||
//</debug>
|
||||
|
||||
config.activeItem = config.activeIndex;
|
||||
}
|
||||
|
||||
this.callParent([config]);
|
||||
}
|
||||
});
|
||||
|
||||
Ext.deprecateClassMethod(this, {
|
||||
/**
|
||||
* Returns `true` when {@link #direction} is 'vertical'.
|
||||
* @return {Boolean}
|
||||
* @deprecated 2.0.0 Use `getDirection() === 'vertical'` instead.
|
||||
*/
|
||||
isVertical: function getDirection() {
|
||||
return this.getDirection() === 'vertical';
|
||||
},
|
||||
/**
|
||||
* Returns `true` when {@link #direction} is 'horizontal'.
|
||||
* @return {Boolean}
|
||||
* @deprecated 2.0.0 Use `getDirection() === 'horizontal'` instead.
|
||||
*/
|
||||
isHorizontal: function getDirection() {
|
||||
return this.getDirection() === 'horizontal';
|
||||
},
|
||||
/**
|
||||
* @method
|
||||
* @inheritdoc Ext.carousel.Carousel#previous
|
||||
* @deprecated 2.0.0 Use {@link Ext.carousel.Carousel#previous} instead.
|
||||
*/
|
||||
prev: 'previous'
|
||||
});
|
||||
//</deprecated>
|
||||
});
|
||||
121
OfficeWeb/3rdparty/touch/src/carousel/Indicator.js
vendored
Normal file
121
OfficeWeb/3rdparty/touch/src/carousel/Indicator.js
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* A private utility class used by Ext.Carousel to create indicators.
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.carousel.Indicator', {
|
||||
extend: 'Ext.Component',
|
||||
xtype : 'carouselindicator',
|
||||
alternateClassName: 'Ext.Carousel.Indicator',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg
|
||||
* @inheritdoc
|
||||
*/
|
||||
baseCls: Ext.baseCSSPrefix + 'carousel-indicator',
|
||||
|
||||
direction: 'horizontal'
|
||||
},
|
||||
|
||||
/**
|
||||
* @event previous
|
||||
* Fires when this indicator is tapped on the left half
|
||||
* @param {Ext.carousel.Indicator} this
|
||||
*/
|
||||
|
||||
/**
|
||||
* @event next
|
||||
* Fires when this indicator is tapped on the right half
|
||||
* @param {Ext.carousel.Indicator} this
|
||||
*/
|
||||
|
||||
initialize: function() {
|
||||
this.callParent();
|
||||
|
||||
this.indicators = [];
|
||||
|
||||
this.element.on({
|
||||
tap: 'onTap',
|
||||
scope: this
|
||||
});
|
||||
},
|
||||
|
||||
updateDirection: function(newDirection, oldDirection) {
|
||||
var baseCls = this.getBaseCls();
|
||||
|
||||
this.element.replaceCls(oldDirection, newDirection, baseCls);
|
||||
|
||||
if (newDirection === 'horizontal') {
|
||||
this.setBottom(0);
|
||||
this.setRight(null);
|
||||
}
|
||||
else {
|
||||
this.setRight(0);
|
||||
this.setBottom(null);
|
||||
}
|
||||
},
|
||||
|
||||
addIndicator: function() {
|
||||
this.indicators.push(this.element.createChild({
|
||||
tag: 'span'
|
||||
}));
|
||||
},
|
||||
|
||||
removeIndicator: function() {
|
||||
var indicators = this.indicators;
|
||||
|
||||
if (indicators.length > 0) {
|
||||
indicators.pop().destroy();
|
||||
}
|
||||
},
|
||||
|
||||
setActiveIndex: function(index) {
|
||||
var indicators = this.indicators,
|
||||
currentActiveIndex = this.activeIndex,
|
||||
currentActiveItem = indicators[currentActiveIndex],
|
||||
activeItem = indicators[index],
|
||||
baseCls = this.getBaseCls();
|
||||
|
||||
if (currentActiveItem) {
|
||||
currentActiveItem.removeCls(baseCls, null, 'active');
|
||||
}
|
||||
|
||||
if (activeItem) {
|
||||
activeItem.addCls(baseCls, null, 'active');
|
||||
}
|
||||
|
||||
this.activeIndex = index;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
// @private
|
||||
onTap: function(e) {
|
||||
var touch = e.touch,
|
||||
box = this.element.getPageBox(),
|
||||
centerX = box.left + (box.width / 2),
|
||||
centerY = box.top + (box.height / 2),
|
||||
direction = this.getDirection();
|
||||
|
||||
if ((direction === 'horizontal' && touch.pageX >= centerX) || (direction === 'vertical' && touch.pageY >= centerY)) {
|
||||
this.fireEvent('next', this);
|
||||
}
|
||||
else {
|
||||
this.fireEvent('previous', this);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
var indicators = this.indicators,
|
||||
i, ln, indicator;
|
||||
|
||||
for (i = 0,ln = indicators.length; i < ln; i++) {
|
||||
indicator = indicators[i];
|
||||
indicator.destroy();
|
||||
}
|
||||
|
||||
indicators.length = 0;
|
||||
|
||||
this.callParent();
|
||||
}
|
||||
});
|
||||
164
OfficeWeb/3rdparty/touch/src/carousel/Infinite.js
vendored
Normal file
164
OfficeWeb/3rdparty/touch/src/carousel/Infinite.js
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @class Ext.carousel.Infinite
|
||||
* @author Jacky Nguyen <jacky@sencha.com>
|
||||
* @private
|
||||
*
|
||||
* The true infinite implementation of Carousel, private for now until it's stable to be public
|
||||
*/
|
||||
Ext.define('Ext.carousel.Infinite', {
|
||||
extend: 'Ext.carousel.Carousel',
|
||||
|
||||
config: {
|
||||
indicator: null,
|
||||
|
||||
maxItemIndex: Infinity,
|
||||
|
||||
innerItemConfig: {}
|
||||
},
|
||||
|
||||
applyIndicator: function(indicator) {
|
||||
//<debug error>
|
||||
if (indicator) {
|
||||
Ext.Logger.error("'indicator' in Infinite Carousel implementation is not currently supported", this);
|
||||
}
|
||||
//</debug>
|
||||
return;
|
||||
},
|
||||
|
||||
updateBufferSize: function(size) {
|
||||
this.callParent(arguments);
|
||||
|
||||
var total = size * 2 + 1,
|
||||
ln = this.innerItems.length,
|
||||
innerItemConfig = this.getInnerItemConfig(),
|
||||
i;
|
||||
|
||||
this.isItemsInitializing = true;
|
||||
|
||||
for (i = ln; i < total; i++) {
|
||||
this.doAdd(this.factoryItem(innerItemConfig));
|
||||
}
|
||||
|
||||
this.isItemsInitializing = false;
|
||||
|
||||
this.rebuildInnerIndexes();
|
||||
this.refreshActiveItem();
|
||||
},
|
||||
|
||||
updateMaxItemIndex: function(maxIndex, oldMaxIndex) {
|
||||
if (oldMaxIndex !== undefined) {
|
||||
var activeIndex = this.getActiveIndex();
|
||||
|
||||
if (activeIndex > maxIndex) {
|
||||
this.setActiveItem(maxIndex);
|
||||
}
|
||||
else {
|
||||
this.rebuildInnerIndexes(activeIndex);
|
||||
this.refreshActiveItem();
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
rebuildInnerIndexes: function(activeIndex) {
|
||||
var indexToItem = this.innerIndexToItem,
|
||||
idToIndex = this.innerIdToIndex,
|
||||
items = this.innerItems.slice(),
|
||||
ln = items.length,
|
||||
bufferSize = this.getBufferSize(),
|
||||
maxIndex = this.getMaxItemIndex(),
|
||||
changedIndexes = [],
|
||||
i, oldIndex, index, id, item;
|
||||
|
||||
|
||||
if (activeIndex === undefined) {
|
||||
this.innerIndexToItem = indexToItem = {};
|
||||
this.innerIdToIndex = idToIndex = {};
|
||||
|
||||
for (i = 0; i < ln; i++) {
|
||||
item = items[i];
|
||||
id = item.getId();
|
||||
idToIndex[id] = i;
|
||||
indexToItem[i] = item;
|
||||
this.fireEvent('itemindexchange', this, item, i, -1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = activeIndex - bufferSize; i <= activeIndex + bufferSize; i++) {
|
||||
if (i >= 0 && i <= maxIndex) {
|
||||
if (indexToItem.hasOwnProperty(i)) {
|
||||
Ext.Array.remove(items, indexToItem[i]);
|
||||
continue;
|
||||
}
|
||||
changedIndexes.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0,ln = changedIndexes.length; i < ln; i++) {
|
||||
item = items[i];
|
||||
id = item.getId();
|
||||
index = changedIndexes[i];
|
||||
oldIndex = idToIndex[id];
|
||||
|
||||
delete indexToItem[oldIndex];
|
||||
|
||||
idToIndex[id] = index;
|
||||
indexToItem[index] = item;
|
||||
this.fireEvent('itemindexchange', this, item, index, oldIndex);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.rebuildInnerIndexes();
|
||||
this.setActiveItem(0);
|
||||
},
|
||||
|
||||
refreshItems: function() {
|
||||
var items = this.innerItems,
|
||||
idToIndex = this.innerIdToIndex,
|
||||
index, item, i, ln;
|
||||
|
||||
for (i = 0,ln = items.length; i < ln; i++) {
|
||||
item = items[i];
|
||||
index = idToIndex[item.getId()];
|
||||
this.fireEvent('itemindexchange', this, item, index, -1);
|
||||
}
|
||||
},
|
||||
|
||||
getInnerItemIndex: function(item) {
|
||||
var index = this.innerIdToIndex[item.getId()];
|
||||
|
||||
return (typeof index == 'number') ? index : -1;
|
||||
},
|
||||
|
||||
getInnerItemAt: function(index) {
|
||||
return this.innerIndexToItem[index];
|
||||
},
|
||||
|
||||
applyActiveItem: function(activeItem) {
|
||||
this.getItems();
|
||||
this.getBufferSize();
|
||||
|
||||
var maxIndex = this.getMaxItemIndex(),
|
||||
currentActiveIndex = this.getActiveIndex();
|
||||
|
||||
if (typeof activeItem == 'number') {
|
||||
activeItem = Math.max(0, Math.min(activeItem, maxIndex));
|
||||
|
||||
if (activeItem === currentActiveIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.activeIndex = activeItem;
|
||||
|
||||
this.rebuildInnerIndexes(activeItem);
|
||||
|
||||
activeItem = this.getInnerItemAt(activeItem);
|
||||
}
|
||||
|
||||
if (activeItem) {
|
||||
return this.callParent([activeItem]);
|
||||
}
|
||||
}
|
||||
});
|
||||
12
OfficeWeb/3rdparty/touch/src/carousel/Item.js
vendored
Normal file
12
OfficeWeb/3rdparty/touch/src/carousel/Item.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.carousel.Item', {
|
||||
extend: 'Ext.Decorator',
|
||||
|
||||
config: {
|
||||
baseCls: 'x-carousel-item',
|
||||
component: null,
|
||||
translatable: true
|
||||
}
|
||||
});
|
||||
1160
OfficeWeb/3rdparty/touch/src/chart/AbstractChart.js
vendored
Normal file
1160
OfficeWeb/3rdparty/touch/src/chart/AbstractChart.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
272
OfficeWeb/3rdparty/touch/src/chart/CartesianChart.js
vendored
Normal file
272
OfficeWeb/3rdparty/touch/src/chart/CartesianChart.js
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* @class Ext.chart.CartesianChart
|
||||
* @extends Ext.chart.AbstractChart
|
||||
*
|
||||
* Represents a chart that uses cartesian coordinates.
|
||||
* A cartesian chart have two directions, X direction and Y direction.
|
||||
* The series and axes are coordinated along these directions.
|
||||
* By default the x direction is horizontal and y direction is vertical,
|
||||
* You can swap the by setting {@link #flipXY} config to `true`.
|
||||
*
|
||||
* Cartesian series often treats x direction an y direction differently.
|
||||
* In most cases, data on x direction are assumed to be monotonically increasing.
|
||||
* Based on this property, cartesian series can be trimmed and summarized properly
|
||||
* to gain a better performance.
|
||||
*
|
||||
* @xtype chart
|
||||
*/
|
||||
|
||||
Ext.define('Ext.chart.CartesianChart', {
|
||||
extend: 'Ext.chart.AbstractChart',
|
||||
alternateClassName: 'Ext.chart.Chart',
|
||||
requires: ['Ext.chart.grid.HorizontalGrid', 'Ext.chart.grid.VerticalGrid'],
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Boolean} flipXY Flip the direction of X and Y axis.
|
||||
* If flipXY is true, the X axes will be vertical and Y axes will be horizontal.
|
||||
*/
|
||||
flipXY: false,
|
||||
|
||||
innerRegion: [0, 0, 1, 1]
|
||||
},
|
||||
xtype: 'chart',
|
||||
alias: 'Ext.chart.Chart',
|
||||
|
||||
getDirectionForAxis: function (position) {
|
||||
var flipXY = this.getFlipXY();
|
||||
if (position === 'left' || position === 'right') {
|
||||
if (flipXY) {
|
||||
return 'X';
|
||||
} else {
|
||||
return 'Y';
|
||||
}
|
||||
} else {
|
||||
if (flipXY) {
|
||||
return 'Y';
|
||||
} else {
|
||||
return 'X';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Layout the axes and series.
|
||||
*/
|
||||
performLayout: function () {
|
||||
try {
|
||||
this.resizing++;
|
||||
this.suspendThicknessChanged();
|
||||
var me = this,
|
||||
axes = me.getAxes(), axis,
|
||||
serieses = me.getSeries(), series,
|
||||
axisSurface, thickness,
|
||||
size = me.element.getSize(),
|
||||
width = size.width,
|
||||
height = size.height,
|
||||
insetPadding = me.getInsetPadding(),
|
||||
innerPadding = me.getInnerPadding(),
|
||||
surface,
|
||||
shrinkBox = {
|
||||
top: insetPadding.top,
|
||||
left: insetPadding.left,
|
||||
right: insetPadding.right,
|
||||
bottom: insetPadding.bottom
|
||||
},
|
||||
gridSurface,
|
||||
mainRegion, innerWidth, innerHeight,
|
||||
elements, floating, matrix, i, ln,
|
||||
flipXY = me.getFlipXY();
|
||||
|
||||
if (width <= 0 || height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < axes.length; i++) {
|
||||
axis = axes[i];
|
||||
axisSurface = axis.getSurface();
|
||||
floating = axis.getStyle && axis.getStyle() && axis.getStyle().floating;
|
||||
thickness = axis.getThickness();
|
||||
switch (axis.getPosition()) {
|
||||
case 'top':
|
||||
axisSurface.setRegion([0, shrinkBox.top, width, thickness]);
|
||||
break;
|
||||
case 'bottom':
|
||||
axisSurface.setRegion([0, height - (shrinkBox.bottom + thickness), width, thickness]);
|
||||
break;
|
||||
case 'left':
|
||||
axisSurface.setRegion([shrinkBox.left, 0, thickness, height]);
|
||||
break;
|
||||
case 'right':
|
||||
axisSurface.setRegion([width - (shrinkBox.right + thickness), 0, thickness, height]);
|
||||
break;
|
||||
}
|
||||
if (!floating) {
|
||||
shrinkBox[axis.getPosition()] += thickness;
|
||||
}
|
||||
}
|
||||
|
||||
width -= shrinkBox.left + shrinkBox.right;
|
||||
height -= shrinkBox.top + shrinkBox.bottom;
|
||||
|
||||
mainRegion = [shrinkBox.left, shrinkBox.top, width, height];
|
||||
|
||||
shrinkBox.left += innerPadding.left;
|
||||
shrinkBox.top += innerPadding.top;
|
||||
shrinkBox.right += innerPadding.right;
|
||||
shrinkBox.bottom += innerPadding.bottom;
|
||||
|
||||
innerWidth = width - innerPadding.left - innerPadding.right;
|
||||
innerHeight = height - innerPadding.top - innerPadding.bottom;
|
||||
|
||||
me.setInnerRegion([shrinkBox.left, shrinkBox.top, innerWidth, innerHeight]);
|
||||
|
||||
if (innerWidth <= 0 || innerHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
me.setMainRegion(mainRegion);
|
||||
me.getSurface('main').setRegion(mainRegion);
|
||||
|
||||
for (i = 0, ln = me.surfaceMap.grid && me.surfaceMap.grid.length; i < ln; i++) {
|
||||
gridSurface = me.surfaceMap.grid[i];
|
||||
gridSurface.setRegion(mainRegion);
|
||||
gridSurface.matrix.set(1, 0, 0, 1, innerPadding.left, innerPadding.top);
|
||||
gridSurface.matrix.inverse(gridSurface.inverseMatrix);
|
||||
}
|
||||
|
||||
for (i = 0; i < axes.length; i++) {
|
||||
axis = axes[i];
|
||||
axisSurface = axis.getSurface();
|
||||
matrix = axisSurface.matrix;
|
||||
elements = matrix.elements;
|
||||
switch (axis.getPosition()) {
|
||||
case 'top':
|
||||
case 'bottom':
|
||||
elements[4] = shrinkBox.left;
|
||||
axis.setLength(innerWidth);
|
||||
break;
|
||||
case 'left':
|
||||
case 'right':
|
||||
elements[5] = shrinkBox.top;
|
||||
axis.setLength(innerHeight);
|
||||
break;
|
||||
}
|
||||
axis.updateTitleSprite();
|
||||
matrix.inverse(axisSurface.inverseMatrix);
|
||||
}
|
||||
|
||||
for (i = 0, ln = serieses.length; i < ln; i++) {
|
||||
series = serieses[i];
|
||||
surface = series.getSurface();
|
||||
surface.setRegion(mainRegion);
|
||||
if (flipXY) {
|
||||
surface.matrix.set(0, -1, 1, 0, innerPadding.left, innerHeight + innerPadding.top);
|
||||
} else {
|
||||
surface.matrix.set(1, 0, 0, -1, innerPadding.left, innerHeight + innerPadding.top);
|
||||
}
|
||||
surface.matrix.inverse(surface.inverseMatrix);
|
||||
series.getOverlaySurface().setRegion(mainRegion);
|
||||
}
|
||||
me.redraw();
|
||||
me.onPlaceWatermark();
|
||||
} finally {
|
||||
this.resizing--;
|
||||
this.resumeThicknessChanged();
|
||||
}
|
||||
},
|
||||
|
||||
redraw: function () {
|
||||
var me = this,
|
||||
series = me.getSeries(),
|
||||
axes = me.getAxes(),
|
||||
region = me.getMainRegion(),
|
||||
innerWidth, innerHeight,
|
||||
innerPadding = me.getInnerPadding(),
|
||||
left, right, top, bottom, i, j,
|
||||
sprites, xRange, yRange, isSide, attr,
|
||||
axisX, axisY, range, visibleRange,
|
||||
flipXY = me.getFlipXY();
|
||||
|
||||
if (!region) {
|
||||
return;
|
||||
}
|
||||
|
||||
innerWidth = region[2] - innerPadding.left - innerPadding.right;
|
||||
innerHeight = region[3] - innerPadding.top - innerPadding.bottom;
|
||||
for (i = 0; i < series.length; i++) {
|
||||
if ((axisX = series[i].getXAxis())) {
|
||||
visibleRange = axisX.getVisibleRange();
|
||||
xRange = axisX.getRange();
|
||||
xRange = [xRange[0] + (xRange[1] - xRange[0]) * visibleRange[0], xRange[0] + (xRange[1] - xRange[0]) * visibleRange[1]];
|
||||
} else {
|
||||
xRange = series[i].getXRange();
|
||||
}
|
||||
|
||||
if ((axisY = series[i].getYAxis())) {
|
||||
visibleRange = axisY.getVisibleRange();
|
||||
yRange = axisY.getRange();
|
||||
yRange = [yRange[0] + (yRange[1] - yRange[0]) * visibleRange[0], yRange[0] + (yRange[1] - yRange[0]) * visibleRange[1]];
|
||||
} else {
|
||||
yRange = series[i].getYRange();
|
||||
}
|
||||
|
||||
left = xRange[0];
|
||||
right = xRange[1];
|
||||
top = yRange[0];
|
||||
bottom = yRange[1];
|
||||
|
||||
attr = {
|
||||
visibleMinX: xRange[0],
|
||||
visibleMaxX: xRange[1],
|
||||
visibleMinY: yRange[0],
|
||||
visibleMaxY: yRange[1],
|
||||
innerWidth: innerWidth,
|
||||
innerHeight: innerHeight,
|
||||
flipXY: flipXY
|
||||
};
|
||||
|
||||
sprites = series[i].getSprites();
|
||||
for (j = 0; j < sprites.length; j++) {
|
||||
sprites[j].setAttributes(attr, true);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < axes.length; i++) {
|
||||
isSide = axes[i].isSide();
|
||||
sprites = axes[i].getSprites();
|
||||
range = axes[i].getRange();
|
||||
visibleRange = axes[i].getVisibleRange();
|
||||
attr = {
|
||||
dataMin: range[0],
|
||||
dataMax: range[1],
|
||||
visibleMin: visibleRange[0],
|
||||
visibleMax: visibleRange[1]
|
||||
};
|
||||
if (isSide) {
|
||||
attr.length = innerHeight;
|
||||
attr.startGap = innerPadding.bottom;
|
||||
attr.endGap = innerPadding.top;
|
||||
} else {
|
||||
attr.length = innerWidth;
|
||||
attr.startGap = innerPadding.left;
|
||||
attr.endGap = innerPadding.right;
|
||||
}
|
||||
for (j = 0; j < sprites.length; j++) {
|
||||
sprites[j].setAttributes(attr, true);
|
||||
}
|
||||
}
|
||||
me.renderFrame();
|
||||
me.callSuper(arguments);
|
||||
},
|
||||
|
||||
onPlaceWatermark: function () {
|
||||
var region0 = this.element.getBox(),
|
||||
region = this.getSurface ? this.getSurface('main').getRegion() : this.getItems().get(0).getRegion();
|
||||
if (region) {
|
||||
this.watermarkElement.setStyle({
|
||||
right: Math.round(region0.width - (region[2] + region[0])) + 'px',
|
||||
bottom: Math.round(region0.height - (region[3] + region[1])) + 'px'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
120
OfficeWeb/3rdparty/touch/src/chart/Legend.js
vendored
Normal file
120
OfficeWeb/3rdparty/touch/src/chart/Legend.js
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @class Ext.chart.Legend
|
||||
* @extends Ext.dataview.DataView
|
||||
*
|
||||
* A default legend for charts.
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.Chart({
|
||||
* animate: true,
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* legend: {
|
||||
* position: 'bottom'
|
||||
* },
|
||||
* axes: [{
|
||||
* type: 'numeric',
|
||||
* position: 'left',
|
||||
* fields: ['data1'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* grid: true,
|
||||
* minimum: 0
|
||||
* }, {
|
||||
* type: 'category',
|
||||
* position: 'bottom',
|
||||
* fields: ['name'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* }
|
||||
* }],
|
||||
* series: [{
|
||||
* type: 'area',
|
||||
* title: ['Data1', 'Data2', 'Data3'],
|
||||
* subStyle: {
|
||||
* fill: ['blue', 'green', 'red']
|
||||
* },
|
||||
* xField: 'name',
|
||||
* yField: ['data1', 'data2', 'data3']
|
||||
*
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*/
|
||||
Ext.define("Ext.chart.Legend", {
|
||||
xtype: 'legend',
|
||||
extend: "Ext.dataview.DataView",
|
||||
config: {
|
||||
itemTpl: [
|
||||
"<span class=\"x-legend-item-marker {[values.disabled?\'x-legend-inactive\':\'\']}\" style=\"background:{mark};\"></span>{name}"
|
||||
],
|
||||
baseCls: 'x-legend',
|
||||
padding: 5,
|
||||
disableSelection: true,
|
||||
inline: true,
|
||||
/**
|
||||
* @cfg {String} position
|
||||
* @deprecated Use `docked` instead.
|
||||
* Delegates to `docked`
|
||||
*/
|
||||
position: 'top',
|
||||
horizontalHeight: 48,
|
||||
verticalWidth: 150
|
||||
},
|
||||
|
||||
constructor: function () {
|
||||
this.callSuper(arguments);
|
||||
|
||||
var scroller = this.getScrollable().getScroller(),
|
||||
onDrag = scroller.onDrag;
|
||||
scroller.onDrag = function (e) {
|
||||
e.stopPropagation();
|
||||
onDrag.call(this, e);
|
||||
};
|
||||
},
|
||||
|
||||
doSetDocked: function (docked) {
|
||||
this.callSuper(arguments);
|
||||
if (docked === 'top' || docked === 'bottom') {
|
||||
this.setLayout({type: 'hbox', pack: 'center'});
|
||||
this.setInline(true);
|
||||
// TODO: Remove this when possible
|
||||
this.setWidth(null);
|
||||
this.setHeight(this.getHorizontalHeight());
|
||||
this.setScrollable({direction: 'horizontal' });
|
||||
} else {
|
||||
this.setLayout({pack: 'center'});
|
||||
this.setInline(false);
|
||||
// TODO: Remove this when possible
|
||||
this.setWidth(this.getVerticalWidth());
|
||||
this.setHeight(null);
|
||||
this.setScrollable({direction: 'vertical' });
|
||||
}
|
||||
},
|
||||
|
||||
updatePosition: function (position) {
|
||||
this.setDocked(position);
|
||||
},
|
||||
|
||||
onItemTap: function (container, target, index, e) {
|
||||
this.callSuper(arguments);
|
||||
var me = this,
|
||||
store = me.getStore(),
|
||||
record = store && store.getAt(index);
|
||||
record.beginEdit();
|
||||
record.set('disabled', !record.get('disabled'));
|
||||
record.commit();
|
||||
}
|
||||
});
|
||||
85
OfficeWeb/3rdparty/touch/src/chart/MarkerHolder.js
vendored
Normal file
85
OfficeWeb/3rdparty/touch/src/chart/MarkerHolder.js
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @class Ext.chart.MarkerHolder
|
||||
* @extends Ext.mixin.Mixin
|
||||
*
|
||||
* Mixin that provides the functionality to place markers.
|
||||
*/
|
||||
Ext.define("Ext.chart.MarkerHolder", {
|
||||
extend: 'Ext.mixin.Mixin',
|
||||
mixinConfig: {
|
||||
id: 'markerHolder',
|
||||
hooks: {
|
||||
constructor: 'constructor',
|
||||
preRender: 'preRender'
|
||||
}
|
||||
},
|
||||
|
||||
isMarkerHolder: true,
|
||||
|
||||
constructor: function () {
|
||||
this.boundMarkers = {};
|
||||
this.cleanRedraw = false;
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name {String}
|
||||
* @param marker {Ext.chart.Markers}
|
||||
*/
|
||||
bindMarker: function (name, marker) {
|
||||
if (marker) {
|
||||
if (!this.boundMarkers[name]) {
|
||||
this.boundMarkers[name] = [];
|
||||
}
|
||||
Ext.Array.include(this.boundMarkers[name], marker);
|
||||
}
|
||||
},
|
||||
|
||||
getBoundMarker: function (name) {
|
||||
return this.boundMarkers[name];
|
||||
},
|
||||
|
||||
preRender: function () {
|
||||
var boundMarkers = this.boundMarkers, boundMarkersItem,
|
||||
name, i, ln, id = this.getId(),
|
||||
parent = this.getParent(),
|
||||
matrix = this.surfaceMatrix ? this.surfaceMatrix.set(1, 0, 0, 1, 0, 0) : (this.surfaceMatrix = new Ext.draw.Matrix());
|
||||
|
||||
this.cleanRedraw = !this.attr.dirty;
|
||||
if (!this.cleanRedraw) {
|
||||
for (name in this.boundMarkers) {
|
||||
if (boundMarkers[name]) {
|
||||
for (boundMarkersItem = boundMarkers[name], i = 0, ln = boundMarkersItem.length; i < ln; i++) {
|
||||
boundMarkersItem[i].clear(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (parent && parent.attr && parent.attr.matrix) {
|
||||
matrix.prependMatrix(parent.attr.matrix);
|
||||
parent = parent.getParent();
|
||||
}
|
||||
matrix.prependMatrix(parent.matrix);
|
||||
this.surfaceMatrix = matrix;
|
||||
this.inverseSurfaceMatrix = matrix.inverse(this.inverseSurfaceMatrix);
|
||||
},
|
||||
|
||||
putMarker: function (name, markerAttr, index, canonical, keepRevision) {
|
||||
var boundMarkersItem, i, ln, id = this.getId();
|
||||
if (this.boundMarkers[name]) {
|
||||
for (boundMarkersItem = this.boundMarkers[name], i = 0, ln = boundMarkersItem.length; i < ln; i++) {
|
||||
boundMarkersItem[i].putMarkerFor(id, markerAttr, index, canonical);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getMarkerBBox: function (name, index, isWithoutTransform) {
|
||||
var boundMarkersItem, i, ln, id = this.getId();
|
||||
if (this.boundMarkers[name]) {
|
||||
for (boundMarkersItem = this.boundMarkers[name], i = 0, ln = boundMarkersItem.length; i < ln; i++) {
|
||||
return boundMarkersItem[i].getMarkerBBoxFor(id, index, isWithoutTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
97
OfficeWeb/3rdparty/touch/src/chart/Markers.js
vendored
Normal file
97
OfficeWeb/3rdparty/touch/src/chart/Markers.js
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @class Ext.chart.Markers
|
||||
* @extends Ext.draw.sprite.Instancing
|
||||
*
|
||||
* Marker sprite. A specialized version of instancing sprite that groups instances.
|
||||
* Putting a marker is grouped by its category id. Clearing removes that category.
|
||||
*/
|
||||
Ext.define("Ext.chart.Markers", {
|
||||
extend: 'Ext.draw.sprite.Instancing',
|
||||
revisions: 0,
|
||||
|
||||
constructor: function () {
|
||||
this.callSuper(arguments);
|
||||
this.map = {};
|
||||
this.revisions = {};
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the markers in the category
|
||||
* @param {String} category
|
||||
*/
|
||||
clear: function (category) {
|
||||
category = category || 'default';
|
||||
if (!(category in this.revisions)) {
|
||||
this.revisions[category] = 1;
|
||||
} else {
|
||||
this.revisions[category]++;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Put a marker in the category with additional
|
||||
* attributes.
|
||||
* @param {String} category
|
||||
* @param {Object} markerAttr
|
||||
* @param {String|Number} index
|
||||
* @param {Boolean} [canonical]
|
||||
* @param {Boolean} [keepRevision]
|
||||
*/
|
||||
putMarkerFor: function (category, markerAttr, index, canonical, keepRevision) {
|
||||
category = category || 'default';
|
||||
|
||||
var me = this,
|
||||
map = me.map[category] || (me.map[category] = {});
|
||||
if (index in map) {
|
||||
me.setAttributesFor(map[index], markerAttr, canonical);
|
||||
} else {
|
||||
map[index] = me.instances.length;
|
||||
me.createInstance(markerAttr, null, canonical);
|
||||
}
|
||||
me.instances[map[index]].category = category;
|
||||
if (!keepRevision) {
|
||||
me.instances[map[index]].revision = me.revisions[category] || (me.revisions[category] = 1);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String} id
|
||||
* @param {Mixed} index
|
||||
* @param {Boolean} [isWithoutTransform]
|
||||
*/
|
||||
getMarkerBBoxFor: function (category, index, isWithoutTransform) {
|
||||
if (category in this.map) {
|
||||
if (index in this.map[category]) {
|
||||
return this.getBBoxFor(this.map[category][index], isWithoutTransform);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getBBox: function () { return null; },
|
||||
|
||||
render: function (surface, ctx, clipRegion) {
|
||||
var me = this,
|
||||
revisions = me.revisions,
|
||||
mat = me.attr.matrix,
|
||||
template = me.getTemplate(),
|
||||
originalAttr = template.attr,
|
||||
instances = me.instances,
|
||||
i, ln = me.instances.length;
|
||||
mat.toContext(ctx);
|
||||
template.preRender(surface, ctx, clipRegion);
|
||||
template.useAttributes(ctx);
|
||||
for (i = 0; i < ln; i++) {
|
||||
if (instances[i].hidden || instances[i].revision !== revisions[instances[i].category]) {
|
||||
continue;
|
||||
}
|
||||
ctx.save();
|
||||
template.attr = instances[i];
|
||||
template.applyTransformations();
|
||||
template.useAttributes(ctx);
|
||||
template.render(surface, ctx, clipRegion);
|
||||
ctx.restore();
|
||||
}
|
||||
template.attr = originalAttr;
|
||||
}
|
||||
});
|
||||
161
OfficeWeb/3rdparty/touch/src/chart/PolarChart.js
vendored
Normal file
161
OfficeWeb/3rdparty/touch/src/chart/PolarChart.js
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* @class Ext.chart.PolarChart
|
||||
* @extends Ext.chart.AbstractChart
|
||||
*
|
||||
* Creates a chart that uses polar coordinates.
|
||||
*/
|
||||
Ext.define('Ext.chart.PolarChart', {
|
||||
|
||||
requires: [
|
||||
'Ext.chart.grid.CircularGrid',
|
||||
'Ext.chart.grid.RadialGrid'
|
||||
],
|
||||
|
||||
extend: 'Ext.chart.AbstractChart',
|
||||
xtype: 'polar',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Array} center Determines the center of the polar chart.
|
||||
* Updated when the chart performs layout.
|
||||
*/
|
||||
center: [0, 0],
|
||||
/**
|
||||
* @cfg {Number} radius Determines the radius of the polar chart.
|
||||
* Updated when the chart performs layout.
|
||||
*/
|
||||
radius: 0
|
||||
},
|
||||
|
||||
getDirectionForAxis: function (position) {
|
||||
if (position === 'radial') {
|
||||
return 'Y';
|
||||
} else {
|
||||
return 'X';
|
||||
}
|
||||
},
|
||||
|
||||
applyCenter: function (center, oldCenter) {
|
||||
if (oldCenter && center[0] === oldCenter[0] && center[1] === oldCenter[1]) {
|
||||
return;
|
||||
}
|
||||
return [+center[0], +center[1]];
|
||||
},
|
||||
|
||||
updateCenter: function (center) {
|
||||
var me = this,
|
||||
axes = me.getAxes(), axis,
|
||||
series = me.getSeries(), seriesItem,
|
||||
i, ln;
|
||||
for (i = 0, ln = axes.length; i < ln; i++) {
|
||||
axis = axes[i];
|
||||
axis.setCenter(center);
|
||||
}
|
||||
|
||||
for (i = 0, ln = series.length; i < ln; i++) {
|
||||
seriesItem = series[i];
|
||||
seriesItem.setCenter(center);
|
||||
}
|
||||
},
|
||||
|
||||
updateRadius: function (radius) {
|
||||
var me = this,
|
||||
axes = me.getAxes(), axis,
|
||||
series = me.getSeries(), seriesItem,
|
||||
i, ln;
|
||||
for (i = 0, ln = axes.length; i < ln; i++) {
|
||||
axis = axes[i];
|
||||
axis.setMinimum(0);
|
||||
axis.setLength(radius);
|
||||
axis.getSprites();
|
||||
}
|
||||
|
||||
for (i = 0, ln = series.length; i < ln; i++) {
|
||||
seriesItem = series[i];
|
||||
seriesItem.setRadius(radius);
|
||||
}
|
||||
},
|
||||
|
||||
doSetSurfaceRegion: function (surface, region) {
|
||||
var mainRegion = this.getMainRegion();
|
||||
surface.setRegion(region);
|
||||
surface.matrix.set(1, 0, 0, 1, mainRegion[0] - region[0], mainRegion[1] - region[1]);
|
||||
surface.inverseMatrix.set(1, 0, 0, 1, region[0] - mainRegion[0], region[1] - mainRegion[1]);
|
||||
},
|
||||
|
||||
performLayout: function () {
|
||||
try {
|
||||
this.resizing++;
|
||||
var me = this,
|
||||
size = me.element.getSize(),
|
||||
fullRegion = [0, 0, size.width, size.height],
|
||||
|
||||
inset = me.getInsetPadding(),
|
||||
inner = me.getInnerPadding(),
|
||||
|
||||
left = inset.left,
|
||||
top = inset.top,
|
||||
width = size.width - left - inset.right,
|
||||
height = size.height - top - inset.bottom,
|
||||
region = [inset.left, inset.top, width, height],
|
||||
|
||||
innerWidth = width - inner.left - inner.right,
|
||||
innerHeight = height - inner.top - inner.bottom,
|
||||
|
||||
center = [innerWidth * 0.5 + inner.left, innerHeight * 0.5 + inner.top],
|
||||
radius = Math.min(innerWidth, innerHeight) * 0.5,
|
||||
axes = me.getAxes(), axis,
|
||||
series = me.getSeries(), seriesItem,
|
||||
i, ln;
|
||||
|
||||
me.setMainRegion(region);
|
||||
|
||||
for (i = 0, ln = series.length; i < ln; i++) {
|
||||
seriesItem = series[i];
|
||||
me.doSetSurfaceRegion(seriesItem.getSurface(), region);
|
||||
me.doSetSurfaceRegion(seriesItem.getOverlaySurface(), fullRegion);
|
||||
}
|
||||
|
||||
me.doSetSurfaceRegion(me.getSurface(), fullRegion);
|
||||
for (i = 0, ln = me.surfaceMap.grid && me.surfaceMap.grid.length; i < ln; i++) {
|
||||
me.doSetSurfaceRegion(me.surfaceMap.grid[i], fullRegion);
|
||||
}
|
||||
for (i = 0, ln = axes.length; i < ln; i++) {
|
||||
axis = axes[i];
|
||||
me.doSetSurfaceRegion(axis.getSurface(), fullRegion);
|
||||
}
|
||||
|
||||
me.setRadius(radius);
|
||||
me.setCenter(center);
|
||||
me.redraw();
|
||||
} finally {
|
||||
this.resizing--;
|
||||
}
|
||||
},
|
||||
|
||||
getEventXY: function (e) {
|
||||
e = (e.changedTouches && e.changedTouches[0]) || e.event || e.browserEvent || e;
|
||||
var me = this,
|
||||
xy = me.element.getXY(),
|
||||
padding = me.getInsetPadding();
|
||||
return [e.pageX - xy[0] - padding.left, e.pageY - xy[1] - padding.top];
|
||||
},
|
||||
|
||||
redraw: function () {
|
||||
var me = this,
|
||||
axes = me.getAxes(), axis,
|
||||
series = me.getSeries(), seriesItem,
|
||||
i, ln;
|
||||
|
||||
for (i = 0, ln = axes.length; i < ln; i++) {
|
||||
axis = axes[i];
|
||||
axis.getSprites();
|
||||
}
|
||||
|
||||
for (i = 0, ln = series.length; i < ln; i++) {
|
||||
seriesItem = series[i];
|
||||
seriesItem.getSprites();
|
||||
}
|
||||
this.renderFrame();
|
||||
}
|
||||
});
|
||||
52
OfficeWeb/3rdparty/touch/src/chart/SpaceFillingChart.js
vendored
Normal file
52
OfficeWeb/3rdparty/touch/src/chart/SpaceFillingChart.js
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @class Ext.chart.SpaceFillingChart
|
||||
* @extends Ext.chart.AbstractChart
|
||||
*
|
||||
* Creates a chart that fills the entire area of the chart.
|
||||
* e.g. Treemap
|
||||
*/
|
||||
Ext.define('Ext.chart.SpaceFillingChart', {
|
||||
|
||||
extend: 'Ext.chart.AbstractChart',
|
||||
xtype: 'spacefilling',
|
||||
|
||||
config: {
|
||||
|
||||
},
|
||||
|
||||
performLayout: function () {
|
||||
try {
|
||||
this.resizing++;
|
||||
var me = this,
|
||||
size = me.element.getSize(),
|
||||
series = me.getSeries(), seriesItem,
|
||||
padding = me.getInsetPadding(),
|
||||
width = size.width - padding.left - padding.right,
|
||||
height = size.height - padding.top - padding.bottom,
|
||||
region = [padding.left, padding.top, width, height],
|
||||
i, ln;
|
||||
me.getSurface().setRegion(region);
|
||||
me.setMainRegion(region);
|
||||
for (i = 0, ln = series.length; i < ln; i++) {
|
||||
seriesItem = series[i];
|
||||
seriesItem.getSurface().setRegion(region);
|
||||
seriesItem.setRegion(region);
|
||||
}
|
||||
me.redraw();
|
||||
} finally {
|
||||
this.resizing--;
|
||||
}
|
||||
},
|
||||
|
||||
redraw: function () {
|
||||
var me = this,
|
||||
series = me.getSeries(), seriesItem,
|
||||
i, ln;
|
||||
|
||||
for (i = 0, ln = series.length; i < ln; i++) {
|
||||
seriesItem = series[i];
|
||||
seriesItem.getSprites();
|
||||
}
|
||||
this.renderFrame();
|
||||
}
|
||||
});
|
||||
894
OfficeWeb/3rdparty/touch/src/chart/axis/Axis.js
vendored
Normal file
894
OfficeWeb/3rdparty/touch/src/chart/axis/Axis.js
vendored
Normal file
@@ -0,0 +1,894 @@
|
||||
/**
|
||||
* @class Ext.chart.axis.Axis
|
||||
*
|
||||
* Defines axis for charts.
|
||||
*
|
||||
* Using the current model, the type of axis can be easily extended. By default, Sencha Touch provides three different
|
||||
* type of axis:
|
||||
*
|
||||
* * **Numeric**: the data attached with this axes are considered to be numeric and continuous.
|
||||
* * **Time**: the data attached with this axes are considered (or get converted into) date/time and they are continuous.
|
||||
* * **Category**: the data attached with this axes conforms a finite set. They be evenly placed on the axis and displayed in the same form they were provided.
|
||||
*
|
||||
* The behavior of axis can be easily changed by setting different types of axis layout and axis segmenter to the axis.
|
||||
*
|
||||
* Axis layout defines how the data points are places. Using continuous layout, the data points will be distributed by
|
||||
* there numeric value. Using discrete layout the data points will be spaced evenly, Furthermore, if you want to combine
|
||||
* the data points with the duplicate values in a discrete layout, you should use combinedDuplicate layout.
|
||||
*
|
||||
* Segmenter defines the way to segment data range. For example, if you have a Date-type data range from Jan 1, 1997 to
|
||||
* Jan 1, 2017, the segmenter will segement the data range into years, months or days based on the current zooming
|
||||
* level.
|
||||
*
|
||||
* It is possible to write custom axis layouts and segmenters to extends this behavior by simply implement interfaces
|
||||
* {@link Ext.chart.axis.layout.Layout} and {@link Ext.chart.axis.segmenter.Segmenter}.
|
||||
*
|
||||
* Here's an example for the axes part of a chart definition:
|
||||
* An example of axis for a series (in this case for an area chart that has multiple layers of yFields) could be:
|
||||
*
|
||||
* axes: [{
|
||||
* type: 'Numeric',
|
||||
* position: 'left',
|
||||
* title: 'Number of Hits',
|
||||
* grid: {
|
||||
* odd: {
|
||||
* opacity: 1,
|
||||
* fill: '#ddd',
|
||||
* stroke: '#bbb',
|
||||
* lineWidth: 1
|
||||
* }
|
||||
* },
|
||||
* minimum: 0
|
||||
* }, {
|
||||
* type: 'Category',
|
||||
* position: 'bottom',
|
||||
* title: 'Month of the Year',
|
||||
* grid: true,
|
||||
* label: {
|
||||
* rotate: {
|
||||
* degrees: 315
|
||||
* }
|
||||
* }
|
||||
* }]
|
||||
*
|
||||
* In this case we use a `Numeric` axis for displaying the values of the Area series and a `Category` axis for displaying the names of
|
||||
* the store elements. The numeric axis is placed on the left of the screen, while the category axis is placed at the bottom of the chart.
|
||||
* Both the category and numeric axes have `grid` set, which means that horizontal and vertical lines will cover the chart background. In the
|
||||
* category axis the labels will be rotated so they can fit the space better.
|
||||
*/
|
||||
Ext.define('Ext.chart.axis.Axis', {
|
||||
xtype: 'axis',
|
||||
|
||||
mixins: {
|
||||
observable: 'Ext.mixin.Observable'
|
||||
},
|
||||
|
||||
requires: [
|
||||
'Ext.chart.axis.sprite.Axis',
|
||||
'Ext.chart.axis.segmenter.*',
|
||||
'Ext.chart.axis.layout.*'
|
||||
],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} position
|
||||
* Where to set the axis. Available options are `left`, `bottom`, `right`, `top`, `radial` and `angular`.
|
||||
*/
|
||||
position: 'bottom',
|
||||
|
||||
/**
|
||||
* @cfg {Array} fields
|
||||
* An array containing the names of the record fields which should be mapped along the axis.
|
||||
* This is optional if the binding between series and fields is clear.
|
||||
*/
|
||||
fields: [],
|
||||
|
||||
/**
|
||||
* @cfg {Object} label
|
||||
*
|
||||
* The label configuration object for the Axis. This object may include style attributes
|
||||
* like `spacing`, `padding`, `font` that receives a string or number and
|
||||
* returns a new string with the modified values.
|
||||
*/
|
||||
label: { x: 0, y: 0, textBaseline: 'middle', textAlign: 'center', fontSize: 12, fontFamily: 'Helvetica' },
|
||||
|
||||
/**
|
||||
* @cfg {Object} grid
|
||||
* The grid configuration object for the Axis style. Can contain `stroke` or `fill` attributes.
|
||||
* Also may contain an `odd` or `even` property in which you only style things on odd or even rows.
|
||||
* For example:
|
||||
*
|
||||
*
|
||||
* grid {
|
||||
* odd: {
|
||||
* stroke: '#555'
|
||||
* },
|
||||
* even: {
|
||||
* stroke: '#ccc'
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
grid: false,
|
||||
|
||||
/**
|
||||
* @cfg {Function} renderer Allows direct customisation of rendered axis sprites.
|
||||
*/
|
||||
renderer: null,
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @cfg {Ext.chart.AbstractChart} chart The Chart that the Axis is bound.
|
||||
*/
|
||||
chart: null,
|
||||
|
||||
/**
|
||||
* @cfg {Object} style
|
||||
* The style for the axis line and ticks.
|
||||
* Refer to the {@link Ext.chart.axis.sprite.Axis}
|
||||
*/
|
||||
style: null,
|
||||
|
||||
/**
|
||||
* @cfg {Number} titleMargin
|
||||
* The margin between axis title and axis.
|
||||
*/
|
||||
titleMargin: 4,
|
||||
|
||||
/**
|
||||
* @cfg {Object} background
|
||||
* The background config for the axis surface.
|
||||
*/
|
||||
background: null,
|
||||
|
||||
/**
|
||||
* @cfg {Number} minimum
|
||||
* The minimum value drawn by the axis. If not set explicitly, the axis
|
||||
* minimum will be calculated automatically.
|
||||
*/
|
||||
minimum: NaN,
|
||||
|
||||
/**
|
||||
* @cfg {Number} maximum
|
||||
* The maximum value drawn by the axis. If not set explicitly, the axis
|
||||
* maximum will be calculated automatically.
|
||||
*/
|
||||
maximum: NaN,
|
||||
|
||||
/**
|
||||
* @cfg {Number} minZoom
|
||||
* The minimum zooming level for axis.
|
||||
*/
|
||||
minZoom: 1,
|
||||
|
||||
/**
|
||||
* @cfg {Number} maxZoom
|
||||
* The maximum zooming level for axis
|
||||
*/
|
||||
maxZoom: 10000,
|
||||
|
||||
/**
|
||||
* @cfg {Object|Ext.chart.axis.layout.Layout} layout
|
||||
* The axis layout config. See {@link Ext.chart.axis.layout.Layout}
|
||||
*/
|
||||
layout: 'continuous',
|
||||
|
||||
/**
|
||||
* @cfg {Object|Ext.chart.axis.segmenter.Segmenter} segmenter
|
||||
* The segmenter config. See {@link Ext.chart.axis.segmenter.Segmenter}
|
||||
*/
|
||||
segmenter: 'numeric',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} hidden
|
||||
* Indicate whether to hide the axis.
|
||||
* If the axis is hidden, one of the axis line, ticks, labels or the title will be shown and
|
||||
* no margin will be taken.
|
||||
* The coordination mechanism works fine no matter if the axis is hidden.
|
||||
*/
|
||||
hidden: false,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Number} majorTickSteps
|
||||
* Will be supported soon.
|
||||
* If `minimum` and `maximum` are specified it forces the number of major ticks to the specified value.
|
||||
*/
|
||||
majorTickSteps: false,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Number} [minorTickSteps=0]
|
||||
* Will be supported soon.
|
||||
* The number of small ticks between two major ticks.
|
||||
*/
|
||||
minorTickSteps: false,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Boolean} adjustMaximumByMajorUnit
|
||||
* Will be supported soon.
|
||||
*/
|
||||
adjustMaximumByMajorUnit: false,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Boolean} adjustMinimumByMajorUnit
|
||||
* Will be supported soon.
|
||||
*
|
||||
*/
|
||||
adjustMinimumByMajorUnit: false,
|
||||
|
||||
/**
|
||||
* @cfg {String|Object} title
|
||||
* The title for the Axis.
|
||||
* If given a String, the text style of the title sprite will be set,
|
||||
* otherwise the style will be set.
|
||||
*/
|
||||
title: { fontSize: 18, fontFamily: 'Helvetica'},
|
||||
|
||||
/**
|
||||
* @cfg {Number} increment
|
||||
* Given a minimum and maximum bound for the series to be rendered (that can be obtained
|
||||
* automatically or by manually setting `minimum` and `maximum`) tick marks will be added
|
||||
* on each `increment` from the minimum value to the maximum one.
|
||||
*/
|
||||
increment: 0.5,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Number} length
|
||||
* Length of the axis position. Equals to the size of inner region on the docking side of this axis.
|
||||
* WARNING: Meant to be set automatically by chart. Do not set it manually.
|
||||
*/
|
||||
length: 0,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Array} center
|
||||
* Center of the polar axis.
|
||||
* WARNING: Meant to be set automatically by chart. Do not set it manually.
|
||||
*/
|
||||
center: null,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Number} radius
|
||||
* Radius of the polar axis.
|
||||
* WARNING: Meant to be set automatically by chart. Do not set it manually.
|
||||
*/
|
||||
radius: null,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Number} rotation
|
||||
* Rotation of the polar axis.
|
||||
* WARNING: Meant to be set automatically by chart. Do not set it manually.
|
||||
*/
|
||||
rotation: null,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} [labelInSpan]
|
||||
* Draws the labels in the middle of the spans.
|
||||
*/
|
||||
labelInSpan: null,
|
||||
|
||||
/**
|
||||
* @cfg {Array} visibleRange
|
||||
* Specify the proportion of the axis to be rendered. The series bound to
|
||||
* this axis will be synchronized and transformed.
|
||||
*/
|
||||
visibleRange: [0, 1],
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Boolean} needHighPrecision
|
||||
*/
|
||||
needHighPrecision: false
|
||||
},
|
||||
|
||||
observableType: 'component',
|
||||
|
||||
titleOffset: 0,
|
||||
|
||||
animating: 0,
|
||||
|
||||
prevMin: 0,
|
||||
|
||||
prevMax: 1,
|
||||
|
||||
boundSeries: [],
|
||||
|
||||
sprites: null,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @property {Array} The full data range of the axis. Should not be set directly, clear it to `null` and use
|
||||
* `getRange` to update.
|
||||
*/
|
||||
range: null,
|
||||
|
||||
xValues: [],
|
||||
|
||||
yValues: [],
|
||||
|
||||
applyRotation: function (rotation) {
|
||||
var twoPie = Math.PI * 2;
|
||||
return (rotation % twoPie + Math.PI) % twoPie - Math.PI;
|
||||
},
|
||||
|
||||
updateRotation: function (rotation) {
|
||||
var sprites = this.getSprites(),
|
||||
position = this.getPosition();
|
||||
if (!this.getHidden() && position === 'angular' && sprites[0]) {
|
||||
sprites[0].setAttributes({
|
||||
baseRotation: rotation
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
applyTitle: function (title, oldTitle) {
|
||||
var surface;
|
||||
|
||||
if (Ext.isString(title)) {
|
||||
title = { text: title };
|
||||
}
|
||||
|
||||
if (!oldTitle) {
|
||||
oldTitle = Ext.create('sprite.text', title);
|
||||
if ((surface = this.getSurface())) {
|
||||
surface.add(oldTitle);
|
||||
}
|
||||
} else {
|
||||
oldTitle.setAttributes(title);
|
||||
}
|
||||
return oldTitle;
|
||||
},
|
||||
|
||||
constructor: function (config) {
|
||||
var me = this;
|
||||
me.sprites = [];
|
||||
this.labels = [];
|
||||
this.initConfig(config);
|
||||
me.getId();
|
||||
me.mixins.observable.constructor.apply(me, arguments);
|
||||
Ext.ComponentManager.register(me);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {String}
|
||||
*/
|
||||
getAlignment: function () {
|
||||
switch (this.getPosition()) {
|
||||
case 'left':
|
||||
case 'right':
|
||||
return "vertical";
|
||||
case 'top':
|
||||
case 'bottom':
|
||||
return "horizontal";
|
||||
case 'radial':
|
||||
return "radial";
|
||||
case 'angular':
|
||||
return "angular";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {String}
|
||||
*/
|
||||
getGridAlignment: function () {
|
||||
switch (this.getPosition()) {
|
||||
case 'left':
|
||||
case 'right':
|
||||
return "horizontal";
|
||||
case 'top':
|
||||
case 'bottom':
|
||||
return "vertical";
|
||||
case 'radial':
|
||||
return "circular";
|
||||
case 'angular':
|
||||
return "radial";
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Get the surface for drawing the series sprites
|
||||
*/
|
||||
getSurface: function () {
|
||||
if (!this.surface) {
|
||||
var chart = this.getChart();
|
||||
if (!chart) {
|
||||
return null;
|
||||
}
|
||||
var surface = this.surface = chart.getSurface(this.getId(), 'axis'),
|
||||
gridSurface = this.gridSurface = chart.getSurface("grid-" + this.getId(), 'grid'),
|
||||
sprites = this.getSprites(),
|
||||
sprite = sprites[0],
|
||||
grid = this.getGrid(),
|
||||
gridAlignment = this.getGridAlignment(),
|
||||
gridSprite;
|
||||
if (grid) {
|
||||
gridSprite = this.gridSpriteEven = new Ext.chart.Markers();
|
||||
gridSprite.setTemplate({xclass: 'grid.' + gridAlignment});
|
||||
if (Ext.isObject(grid)) {
|
||||
gridSprite.getTemplate().setAttributes(grid);
|
||||
if (Ext.isObject(grid.even)) {
|
||||
gridSprite.getTemplate().setAttributes(grid.even);
|
||||
}
|
||||
}
|
||||
gridSurface.add(gridSprite);
|
||||
sprite.bindMarker(gridAlignment + '-even', gridSprite);
|
||||
|
||||
gridSprite = this.gridSpriteOdd = new Ext.chart.Markers();
|
||||
gridSprite.setTemplate({xclass: 'grid.' + gridAlignment});
|
||||
if (Ext.isObject(grid)) {
|
||||
gridSprite.getTemplate().setAttributes(grid);
|
||||
if (Ext.isObject(grid.odd)) {
|
||||
gridSprite.getTemplate().setAttributes(grid.odd);
|
||||
}
|
||||
}
|
||||
gridSurface.add(gridSprite);
|
||||
sprite.bindMarker(gridAlignment + '-odd', gridSprite);
|
||||
|
||||
gridSurface.waitFor(surface);
|
||||
}
|
||||
}
|
||||
return this.surface;
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Mapping data value into coordinate.
|
||||
*
|
||||
* @param {*} value
|
||||
* @param {String} field
|
||||
* @param {Number} [idx]
|
||||
* @param {Ext.util.MixedCollection} [items]
|
||||
* @return {Number}
|
||||
*/
|
||||
getCoordFor: function (value, field, idx, items) {
|
||||
return this.getLayout().getCoordFor(value, field, idx, items);
|
||||
},
|
||||
|
||||
applyPosition: function (pos) {
|
||||
return pos.toLowerCase();
|
||||
},
|
||||
|
||||
applyLabel: function (newText, oldText) {
|
||||
if (!oldText) {
|
||||
oldText = new Ext.draw.sprite.Text({});
|
||||
}
|
||||
oldText.setAttributes(newText);
|
||||
return oldText;
|
||||
},
|
||||
|
||||
applyLayout: function (layout, oldLayout) {
|
||||
// TODO: finish this
|
||||
layout = Ext.factory(layout, null, oldLayout, 'axisLayout');
|
||||
layout.setAxis(this);
|
||||
return layout;
|
||||
},
|
||||
|
||||
applySegmenter: function (segmenter, oldSegmenter) {
|
||||
// TODO: finish this
|
||||
segmenter = Ext.factory(segmenter, null, oldSegmenter, 'segmenter');
|
||||
segmenter.setAxis(this);
|
||||
return segmenter;
|
||||
},
|
||||
|
||||
updateMinimum: function () {
|
||||
this.range = null;
|
||||
},
|
||||
|
||||
updateMaximum: function () {
|
||||
this.range = null;
|
||||
},
|
||||
|
||||
hideLabels: function () {
|
||||
this.getSprites()[0].setDirty(true);
|
||||
this.setLabel({hidden: true});
|
||||
},
|
||||
|
||||
showLabels: function () {
|
||||
this.getSprites()[0].setDirty(true);
|
||||
this.setLabel({hidden: false});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Reset the axis to its original state, before any user interaction.
|
||||
*
|
||||
*/
|
||||
reset: function () {
|
||||
// TODO: finish this
|
||||
},
|
||||
|
||||
/**
|
||||
* Invokes renderFrame on this axis's surface(s)
|
||||
*/
|
||||
renderFrame: function () {
|
||||
this.getSurface().renderFrame();
|
||||
},
|
||||
|
||||
updateChart: function (newChart, oldChart) {
|
||||
var me = this, surface;
|
||||
if (oldChart) {
|
||||
oldChart.un("serieschanged", me.onSeriesChanged, me);
|
||||
}
|
||||
if (newChart) {
|
||||
newChart.on("serieschanged", me.onSeriesChanged, me);
|
||||
if (newChart.getSeries()) {
|
||||
me.onSeriesChanged(newChart);
|
||||
}
|
||||
me.surface = null;
|
||||
surface = me.getSurface();
|
||||
surface.add(me.getSprites());
|
||||
surface.add(me.getTitle());
|
||||
}
|
||||
},
|
||||
|
||||
applyBackground: function (background) {
|
||||
var rect = Ext.ClassManager.getByAlias('sprite.rect');
|
||||
return rect.def.normalize(background);
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* Invoked when data has changed.
|
||||
*/
|
||||
processData: function () {
|
||||
this.getLayout().processData();
|
||||
this.range = null;
|
||||
},
|
||||
|
||||
getDirection: function () {
|
||||
return this.getChart().getDirectionForAxis(this.getPosition());
|
||||
},
|
||||
|
||||
isSide: function () {
|
||||
var position = this.getPosition();
|
||||
return position === 'left' || position === 'right';
|
||||
},
|
||||
|
||||
applyFields: function (fields) {
|
||||
return [].concat(fields);
|
||||
},
|
||||
|
||||
updateFields: function (fields) {
|
||||
this.fieldsMap = {};
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
this.fieldsMap[fields[i]] = true;
|
||||
}
|
||||
},
|
||||
|
||||
applyVisibleRange: function (visibleRange, oldVisibleRange) {
|
||||
// If it is in reversed order swap them
|
||||
if (visibleRange[0] > visibleRange[1]) {
|
||||
var temp = visibleRange[0];
|
||||
visibleRange[0] = visibleRange[1];
|
||||
visibleRange[0] = temp;
|
||||
}
|
||||
if (visibleRange[1] === visibleRange[0]) {
|
||||
visibleRange[1] += 1 / this.getMaxZoom();
|
||||
}
|
||||
if (visibleRange[1] > visibleRange[0] + 1) {
|
||||
visibleRange[0] = 0;
|
||||
visibleRange[1] = 1;
|
||||
} else if (visibleRange[0] < 0) {
|
||||
visibleRange[1] -= visibleRange[0];
|
||||
visibleRange[0] = 0;
|
||||
} else if (visibleRange[1] > 1) {
|
||||
visibleRange[0] -= visibleRange[1] - 1;
|
||||
visibleRange[1] = 1;
|
||||
}
|
||||
|
||||
if (oldVisibleRange && visibleRange[0] === oldVisibleRange[0] && visibleRange[1] === oldVisibleRange[1]) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return visibleRange;
|
||||
},
|
||||
|
||||
updateVisibleRange: function (visibleRange) {
|
||||
this.fireEvent('transformed', this, visibleRange);
|
||||
},
|
||||
|
||||
onSeriesChanged: function (chart) {
|
||||
var me = this,
|
||||
series = chart.getSeries(),
|
||||
getAxisMethod = 'get' + me.getDirection() + 'Axis',
|
||||
boundSeries = [], i, ln = series.length;
|
||||
for (i = 0; i < ln; i++) {
|
||||
if (this === series[i][getAxisMethod]()) {
|
||||
boundSeries.push(series[i]);
|
||||
}
|
||||
}
|
||||
|
||||
me.boundSeries = boundSeries;
|
||||
me.getLayout().processData();
|
||||
},
|
||||
|
||||
applyRange: function (newRange) {
|
||||
if (!newRange) {
|
||||
return this.dataRange.slice(0);
|
||||
} else {
|
||||
return [
|
||||
newRange[0] === null ? this.dataRange[0] : newRange[0],
|
||||
newRange[1] === null ? this.dataRange[1] : newRange[1]
|
||||
];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the range derived from all the bound series.
|
||||
* @return {Array}
|
||||
*/
|
||||
getRange: function () {
|
||||
var me = this,
|
||||
getRangeMethod = 'get' + me.getDirection() + 'Range';
|
||||
|
||||
if (me.range) {
|
||||
return me.range;
|
||||
}
|
||||
if (!isNaN(me.getMinimum()) && !isNaN(me.getMaximum())) {
|
||||
return this.range = [me.getMinimum(), me.getMaximum()];
|
||||
}
|
||||
var min = Infinity,
|
||||
max = -Infinity,
|
||||
boundSeries = me.boundSeries,
|
||||
series, i, ln;
|
||||
|
||||
// For each series bound to this axis, ask the series for its min/max values
|
||||
// and use them to find the overall min/max.
|
||||
for (i = 0, ln = boundSeries.length; i < ln; i++) {
|
||||
series = boundSeries[i];
|
||||
var minMax = series[getRangeMethod]();
|
||||
|
||||
if (minMax) {
|
||||
if (minMax[0] < min) {
|
||||
min = minMax[0];
|
||||
}
|
||||
if (minMax[1] > max) {
|
||||
max = minMax[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isFinite(max)) {
|
||||
max = me.prevMax;
|
||||
}
|
||||
|
||||
if (!isFinite(min)) {
|
||||
min = me.prevMin;
|
||||
}
|
||||
|
||||
if (this.getLabelInSpan()) {
|
||||
max += this.getIncrement();
|
||||
min -= this.getIncrement();
|
||||
}
|
||||
|
||||
if (!isNaN(me.getMinimum())) {
|
||||
min = me.getMinimum();
|
||||
} else {
|
||||
me.prevMin = min;
|
||||
}
|
||||
|
||||
if (!isNaN(me.getMaximum())) {
|
||||
max = me.getMaximum();
|
||||
} else {
|
||||
me.prevMax = max;
|
||||
}
|
||||
|
||||
return this.range = [min, max];
|
||||
},
|
||||
|
||||
applyStyle: function (style, oldStyle) {
|
||||
var cls = Ext.ClassManager.getByAlias('sprite.' + this.seriesType);
|
||||
if (cls && cls.def) {
|
||||
style = cls.def.normalize(style);
|
||||
}
|
||||
oldStyle = Ext.apply(oldStyle || {}, style);
|
||||
return oldStyle;
|
||||
},
|
||||
|
||||
updateCenter: function (center) {
|
||||
var sprites = this.getSprites(),
|
||||
axisSprite = sprites[0],
|
||||
centerX = center[0],
|
||||
centerY = center[1];
|
||||
if (axisSprite) {
|
||||
axisSprite.setAttributes({
|
||||
centerX: centerX,
|
||||
centerY: centerY
|
||||
});
|
||||
}
|
||||
if (this.gridSpriteEven) {
|
||||
this.gridSpriteEven.getTemplate().setAttributes({
|
||||
translationX: centerX,
|
||||
translationY: centerY,
|
||||
rotationCenterX: centerX,
|
||||
rotationCenterY: centerY
|
||||
});
|
||||
}
|
||||
if (this.gridSpriteOdd) {
|
||||
this.gridSpriteOdd.getTemplate().setAttributes({
|
||||
translationX: centerX,
|
||||
translationY: centerY,
|
||||
rotationCenterX: centerX,
|
||||
rotationCenterY: centerY
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
getSprites: function () {
|
||||
if (!this.getChart()) {
|
||||
return;
|
||||
}
|
||||
var me = this,
|
||||
range = me.getRange(),
|
||||
position = me.getPosition(),
|
||||
chart = me.getChart(),
|
||||
animation = chart.getAnimate(),
|
||||
baseSprite, style,
|
||||
gridAlignment = me.getGridAlignment(),
|
||||
length = me.getLength();
|
||||
|
||||
// If animation is false, then stop animation.
|
||||
if (animation === false) {
|
||||
animation = {
|
||||
duration: 0
|
||||
};
|
||||
}
|
||||
if (range) {
|
||||
style = Ext.applyIf({
|
||||
position: position,
|
||||
axis: me,
|
||||
min: range[0],
|
||||
max: range[1],
|
||||
length: length,
|
||||
grid: me.getGrid(),
|
||||
hidden: me.getHidden(),
|
||||
titleOffset: me.titleOffset,
|
||||
layout: me.getLayout(),
|
||||
segmenter: me.getSegmenter(),
|
||||
label: me.getLabel()
|
||||
}, me.getStyle());
|
||||
|
||||
// If the sprites are not created.
|
||||
if (!me.sprites.length) {
|
||||
baseSprite = new Ext.chart.axis.sprite.Axis(style);
|
||||
baseSprite.fx.setCustomDuration({
|
||||
baseRotation: 0
|
||||
});
|
||||
baseSprite.fx.on("animationstart", "onAnimationStart", me);
|
||||
baseSprite.fx.on("animationend", "onAnimationEnd", me);
|
||||
me.sprites.push(baseSprite);
|
||||
me.updateTitleSprite();
|
||||
} else {
|
||||
baseSprite = me.sprites[0];
|
||||
baseSprite.fx.setConfig(animation);
|
||||
baseSprite.setAttributes(style);
|
||||
baseSprite.setLayout(me.getLayout());
|
||||
baseSprite.setSegmenter(me.getSegmenter());
|
||||
baseSprite.setLabel(me.getLabel());
|
||||
}
|
||||
|
||||
if (me.getRenderer()) {
|
||||
baseSprite.setRenderer(me.getRenderer());
|
||||
}
|
||||
}
|
||||
|
||||
return me.sprites;
|
||||
},
|
||||
|
||||
updateTitleSprite: function () {
|
||||
if (!this.sprites[0]) {
|
||||
return;
|
||||
}
|
||||
var me = this,
|
||||
thickness = this.sprites[0].thickness,
|
||||
surface = me.getSurface(),
|
||||
title = this.getTitle(),
|
||||
position = me.getPosition(),
|
||||
titleMargin = me.getTitleMargin(),
|
||||
length = me.getLength(),
|
||||
anchor = surface.roundPixel(length / 2);
|
||||
|
||||
if (title) {
|
||||
switch (position) {
|
||||
case 'top':
|
||||
title.setAttributes({
|
||||
x: anchor,
|
||||
y: titleMargin / 2,
|
||||
textBaseline: 'top',
|
||||
textAlign: 'center'
|
||||
}, true, true);
|
||||
title.applyTransformations();
|
||||
me.titleOffset = title.getBBox().height + titleMargin;
|
||||
break;
|
||||
case 'bottom':
|
||||
title.setAttributes({
|
||||
x: anchor,
|
||||
y: thickness + titleMargin,
|
||||
textBaseline: 'top',
|
||||
textAlign: 'center'
|
||||
}, true, true);
|
||||
title.applyTransformations();
|
||||
me.titleOffset = title.getBBox().height + titleMargin;
|
||||
break;
|
||||
case 'left':
|
||||
title.setAttributes({
|
||||
x: titleMargin / 2,
|
||||
y: anchor,
|
||||
textBaseline: 'top',
|
||||
textAlign: 'center',
|
||||
rotationCenterX: titleMargin / 2,
|
||||
rotationCenterY: anchor,
|
||||
rotationRads: -Math.PI / 2
|
||||
}, true, true);
|
||||
title.applyTransformations();
|
||||
me.titleOffset = title.getBBox().width + titleMargin;
|
||||
break;
|
||||
case 'right':
|
||||
title.setAttributes({
|
||||
x: thickness - titleMargin / 2,
|
||||
y: anchor,
|
||||
textBaseline: 'bottom',
|
||||
textAlign: 'center',
|
||||
rotationCenterX: thickness,
|
||||
rotationCenterY: anchor,
|
||||
rotationRads: Math.PI / 2
|
||||
}, true, true);
|
||||
title.applyTransformations();
|
||||
me.titleOffset = title.getBBox().width + titleMargin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onThicknessChanged: function () {
|
||||
var me = this;
|
||||
me.getChart().onThicknessChanged();
|
||||
},
|
||||
|
||||
getThickness: function () {
|
||||
if (this.getHidden()) {
|
||||
return 0;
|
||||
}
|
||||
return (this.sprites[0] && this.sprites[0].thickness || 1) + this.titleOffset;
|
||||
},
|
||||
|
||||
onAnimationStart: function () {
|
||||
this.animating++;
|
||||
if (this.animating === 1) {
|
||||
this.fireEvent("animationstart");
|
||||
}
|
||||
},
|
||||
|
||||
onAnimationEnd: function () {
|
||||
this.animating--;
|
||||
if (this.animating === 0) {
|
||||
this.fireEvent("animationend");
|
||||
}
|
||||
},
|
||||
|
||||
// Methods used in ComponentQuery and controller
|
||||
getItemId: function () {
|
||||
return this.getId();
|
||||
},
|
||||
|
||||
getAncestorIds: function () {
|
||||
return [this.getChart().getId()];
|
||||
},
|
||||
|
||||
isXType: function (xtype) {
|
||||
return xtype === 'axis';
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
Ext.ComponentManager.unregister(this);
|
||||
this.callSuper();
|
||||
}
|
||||
});
|
||||
|
||||
69
OfficeWeb/3rdparty/touch/src/chart/axis/Category.js
vendored
Normal file
69
OfficeWeb/3rdparty/touch/src/chart/axis/Category.js
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @class Ext.chart.axis.Category
|
||||
* @extends Ext.chart.axis.Axis
|
||||
*
|
||||
* A type of axis that displays items in categories. This axis is generally used to
|
||||
* display categorical information like names of items, month names, quarters, etc.
|
||||
* but no quantitative values. For that other type of information {@link Ext.chart.axis.Numeric Numeric}
|
||||
* axis are more suitable.
|
||||
*
|
||||
* As with other axis you can set the position of the axis and its title. For example:
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.CartesianChart({
|
||||
* animate: true,
|
||||
* innerPadding: {
|
||||
* left: 40,
|
||||
* right: 40,
|
||||
* },
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* axes: [{
|
||||
* type: 'category',
|
||||
* position: 'bottom',
|
||||
* fields: ['name'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* }
|
||||
* }],
|
||||
* series: [{
|
||||
* type: 'area',
|
||||
* subStyle: {
|
||||
* fill: ['blue', 'green', 'red']
|
||||
* },
|
||||
* xField: 'name',
|
||||
* yField: ['data1', 'data2', 'data3']
|
||||
*
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*
|
||||
* In this example with set the category axis to the bottom of the surface, bound the axis to
|
||||
* the `name` property and set as title "Sample Values".
|
||||
*/
|
||||
|
||||
Ext.define('Ext.chart.axis.Category', {
|
||||
requires: [
|
||||
'Ext.chart.axis.layout.CombineDuplicate',
|
||||
'Ext.chart.axis.segmenter.Names'
|
||||
],
|
||||
extend: 'Ext.chart.axis.Axis',
|
||||
alias: 'axis.category',
|
||||
type: 'category',
|
||||
|
||||
config: {
|
||||
layout: 'combineDuplicate',
|
||||
|
||||
segmenter: 'names'
|
||||
}
|
||||
});
|
||||
73
OfficeWeb/3rdparty/touch/src/chart/axis/Numeric.js
vendored
Normal file
73
OfficeWeb/3rdparty/touch/src/chart/axis/Numeric.js
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @class Ext.chart.axis.Numeric
|
||||
* @extends Ext.chart.axis.Axis
|
||||
*
|
||||
* An axis to handle numeric values. This axis is used for quantitative data as
|
||||
* opposed to the category axis. You can set minimum and maximum values to the
|
||||
* axis so that the values are bound to that. If no values are set, then the
|
||||
* scale will auto-adjust to the values.
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.CartesianChart({
|
||||
* animate: true,
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':1, 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':2, 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':3, 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':4, 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':5, 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* axes: [{
|
||||
* type: 'numeric',
|
||||
* grid: true,
|
||||
* position: 'left',
|
||||
* fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* title: 'Sample Values',
|
||||
* grid: {
|
||||
* odd: {
|
||||
* opacity: 1,
|
||||
* fill: '#ddd',
|
||||
* stroke: '#bbb',
|
||||
* 'lineWidth': 1
|
||||
* }
|
||||
* },
|
||||
* minimum: 0,
|
||||
* adjustMinimumByMajorUnit: 0
|
||||
* }],
|
||||
* series: [{
|
||||
* type: 'area',
|
||||
* subStyle: {
|
||||
* fill: ['blue', 'green', 'red']
|
||||
* },
|
||||
* xField: 'name',
|
||||
* yField: ['data1', 'data2', 'data3']
|
||||
*
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
* In this example we create an axis of Numeric type. We set a minimum value so that
|
||||
* even if all series have values greater than zero, the grid starts at zero. We bind
|
||||
* the axis onto the left part of the surface by setting _position_ to _left_.
|
||||
* We bind three different store fields to this axis by setting _fields_ to an array.
|
||||
* We set the title of the axis to _Number of Hits_ by using the _title_ property.
|
||||
* We use a _grid_ configuration to set odd background rows to a certain style and even rows
|
||||
* to be transparent/ignored.
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.chart.axis.Numeric', {
|
||||
extend: 'Ext.chart.axis.Axis',
|
||||
alias: 'axis.numeric',
|
||||
type: 'numeric',
|
||||
requires: ['Ext.chart.axis.layout.Continuous', 'Ext.chart.axis.segmenter.Numeric'],
|
||||
config: {
|
||||
layout: 'continuous',
|
||||
|
||||
segmenter: 'numeric',
|
||||
|
||||
aggregator: 'double'
|
||||
}
|
||||
});
|
||||
140
OfficeWeb/3rdparty/touch/src/chart/axis/Time.js
vendored
Normal file
140
OfficeWeb/3rdparty/touch/src/chart/axis/Time.js
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* @class Ext.chart.axis.Time
|
||||
* @extends Ext.chart.axis.Numeric
|
||||
*
|
||||
* A type of axis whose units are measured in time values. Use this axis
|
||||
* for listing dates that you will want to group or dynamically change.
|
||||
* If you just want to display dates as categories then use the
|
||||
* Category class for axis instead.
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.CartesianChart({
|
||||
* animate: true,
|
||||
* store: {
|
||||
* fields: ['time', 'open', 'high', 'low', 'close'],
|
||||
* data: [
|
||||
* {'time':new Date('Jan 1 2010').getTime(), 'open':600, 'high':614, 'low':578, 'close':590},
|
||||
* {'time':new Date('Jan 2 2010').getTime(), 'open':590, 'high':609, 'low':580, 'close':580},
|
||||
* {'time':new Date('Jan 3 2010').getTime(), 'open':580, 'high':602, 'low':578, 'close':602},
|
||||
* {'time':new Date('Jan 4 2010').getTime(), 'open':602, 'high':614, 'low':586, 'close':586},
|
||||
* {'time':new Date('Jan 5 2010').getTime(), 'open':586, 'high':602, 'low':565, 'close':565}
|
||||
* ]
|
||||
* },
|
||||
* axes: [{
|
||||
* type: 'numeric',
|
||||
* position: 'left',
|
||||
* fields: ['open', 'high', 'low', 'close'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* grid: true,
|
||||
* minimum: 560,
|
||||
* maximum: 640
|
||||
* }, {
|
||||
* type: 'time',
|
||||
* position: 'bottom',
|
||||
* fields: ['time'],
|
||||
* fromDate: new Date('Dec 31 2009'),
|
||||
* toDate: new Date('Jan 6 2010'),
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* style: {
|
||||
* axisLine: false
|
||||
* }
|
||||
* }],
|
||||
* series: [{
|
||||
* type: 'candlestick',
|
||||
* xField: 'time',
|
||||
* openField: 'open',
|
||||
* highField: 'high',
|
||||
* lowField: 'low',
|
||||
* closeField: 'close',
|
||||
* style: {
|
||||
* ohlcType: 'ohlc',
|
||||
* dropStyle: {
|
||||
* fill: 'rgb(237, 123, 43)',
|
||||
* stroke: 'rgb(237, 123, 43)'
|
||||
* },
|
||||
* raiseStyle: {
|
||||
* fill: 'rgb(55, 153, 19)',
|
||||
* stroke: 'rgb(55, 153, 19)'
|
||||
* }
|
||||
* },
|
||||
* aggregator: {
|
||||
* strategy: 'time'
|
||||
* }
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*/
|
||||
Ext.define('Ext.chart.axis.Time', {
|
||||
extend: 'Ext.chart.axis.Numeric',
|
||||
alias: 'axis.time',
|
||||
type: 'time',
|
||||
requires: ['Ext.chart.axis.layout.Continuous', 'Ext.chart.axis.segmenter.Time', 'Ext.DateExtras'],
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Boolean} calculateByLabelSize
|
||||
* The minimum value drawn by the axis. If not set explicitly, the axis
|
||||
* minimum will be calculated automatically.
|
||||
*/
|
||||
calculateByLabelSize: true,
|
||||
|
||||
/**
|
||||
* @cfg {String/Boolean} dateFormat
|
||||
* Indicates the format the date will be rendered on.
|
||||
* For example: 'M d' will render the dates as 'Jan 30', etc.
|
||||
*/
|
||||
dateFormat: null,
|
||||
|
||||
/**
|
||||
* @cfg {Date} fromDate The starting date for the time axis.
|
||||
*/
|
||||
fromDate: null,
|
||||
|
||||
/**
|
||||
* @cfg {Date} toDate The ending date for the time axis.
|
||||
*/
|
||||
toDate: null,
|
||||
|
||||
/**
|
||||
* @cfg {Array} [step=[Ext.Date.DAY, 1]] An array with two components:
|
||||
*
|
||||
* - The unit of the step (Ext.Date.DAY, Ext.Date.MONTH, etc).
|
||||
* - The number of units for the step (1, 2, etc).
|
||||
*
|
||||
*/
|
||||
step: [Ext.Date.DAY, 1],
|
||||
|
||||
layout: 'continuous',
|
||||
|
||||
segmenter: 'time',
|
||||
|
||||
aggregator: 'time'
|
||||
},
|
||||
|
||||
updateDateFormat: function (format) {
|
||||
this.setRenderer(function (date) {
|
||||
return Ext.Date.format(new Date(date), format);
|
||||
});
|
||||
},
|
||||
|
||||
updateFromDate: function (date) {
|
||||
this.setMinimum(+date);
|
||||
},
|
||||
|
||||
updateToDate: function (date) {
|
||||
this.setMaximum(+date);
|
||||
},
|
||||
|
||||
getCoordFor: function (value) {
|
||||
if (Ext.isString(value)) {
|
||||
value = new Date(value);
|
||||
}
|
||||
return +value;
|
||||
}
|
||||
});
|
||||
20
OfficeWeb/3rdparty/touch/src/chart/axis/layout/CombineDuplicate.js
vendored
Normal file
20
OfficeWeb/3rdparty/touch/src/chart/axis/layout/CombineDuplicate.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @class Ext.chart.axis.layout.CombineDuplicate
|
||||
* @extends Ext.chart.axis.layout.Discrete
|
||||
*
|
||||
* Discrete processor that combines duplicate data points.
|
||||
*/
|
||||
Ext.define("Ext.chart.axis.layout.CombineDuplicate", {
|
||||
extend: 'Ext.chart.axis.layout.Discrete',
|
||||
alias: 'axisLayout.combineDuplicate',
|
||||
|
||||
getCoordFor: function (value, field, idx, items) {
|
||||
if (!(value in this.labelMap)) {
|
||||
var result = this.labelMap[value] = this.labels.length;
|
||||
this.labels.push(value);
|
||||
return result;
|
||||
}
|
||||
return this.labelMap[value];
|
||||
}
|
||||
|
||||
});
|
||||
40
OfficeWeb/3rdparty/touch/src/chart/axis/layout/Continuous.js
vendored
Normal file
40
OfficeWeb/3rdparty/touch/src/chart/axis/layout/Continuous.js
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @class Ext.chart.axis.layout.Continuous
|
||||
* @extends Ext.chart.axis.layout.Layout
|
||||
*
|
||||
* Processor for axis data that can be interpolated.
|
||||
*/
|
||||
Ext.define("Ext.chart.axis.layout.Continuous", {
|
||||
extend: 'Ext.chart.axis.layout.Layout',
|
||||
alias: 'axisLayout.continuous',
|
||||
config: {
|
||||
adjustMinimumByMajorUnit: false,
|
||||
adjustMaximumByMajorUnit: false
|
||||
},
|
||||
|
||||
getCoordFor: function (value, field, idx, items) {
|
||||
return +value;
|
||||
},
|
||||
|
||||
//@inheritdoc
|
||||
snapEnds: function (context, min, max, estStepSize) {
|
||||
var segmenter = context.segmenter,
|
||||
out = context.segmenter.preferredStep(min, estStepSize),
|
||||
unit = out.unit,
|
||||
step = out.step,
|
||||
from = segmenter.align(min, step, unit),
|
||||
steps = segmenter.diff(min, max, unit) + 1;
|
||||
return {
|
||||
min: segmenter.from(min),
|
||||
max: segmenter.from(max),
|
||||
from: from,
|
||||
to: segmenter.add(from, steps * step, unit),
|
||||
step: step,
|
||||
steps: steps,
|
||||
unit: unit,
|
||||
get: function (current) {
|
||||
return segmenter.add(this.from, this.step * current, unit);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
108
OfficeWeb/3rdparty/touch/src/chart/axis/layout/Discrete.js
vendored
Normal file
108
OfficeWeb/3rdparty/touch/src/chart/axis/layout/Discrete.js
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @class Ext.chart.axis.layout.Discrete
|
||||
* @extends Ext.chart.axis.layout.Layout
|
||||
*
|
||||
* Simple processor for data that cannot be interpolated.
|
||||
*/
|
||||
Ext.define("Ext.chart.axis.layout.Discrete", {
|
||||
extend: 'Ext.chart.axis.layout.Layout',
|
||||
alias: 'axisLayout.discrete',
|
||||
|
||||
processData: function () {
|
||||
var me = this,
|
||||
axis = me.getAxis(),
|
||||
boundSeries = axis.boundSeries,
|
||||
direction = axis.getDirection(),
|
||||
i, ln, item;
|
||||
this.labels = [];
|
||||
this.labelMap = {};
|
||||
for (i = 0, ln = boundSeries.length; i < ln; i++) {
|
||||
item = boundSeries[i];
|
||||
if (item['get' + direction + 'Axis']() === axis) {
|
||||
item['coordinate' + direction]();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// @inheritdoc
|
||||
calculateLayout: function (context) {
|
||||
context.data = this.labels;
|
||||
this.callSuper([context]);
|
||||
},
|
||||
|
||||
//@inheritdoc
|
||||
calculateMajorTicks: function (context) {
|
||||
var me = this,
|
||||
attr = context.attr,
|
||||
data = context.data,
|
||||
range = attr.max - attr.min,
|
||||
zoom = range / attr.length * (attr.visibleMax - attr.visibleMin),
|
||||
viewMin = attr.min + range * attr.visibleMin,
|
||||
viewMax = attr.min + range * attr.visibleMax,
|
||||
estStepSize = attr.estStepSize * zoom;
|
||||
|
||||
var out = me.snapEnds(context, Math.max(0, attr.min), Math.min(attr.max, data.length - 1), estStepSize);
|
||||
if (out) {
|
||||
me.trimByRange(context, out, viewMin - zoom * (1 + attr.startGap), viewMax + zoom * (1 + attr.endGap));
|
||||
context.majorTicks = out;
|
||||
}
|
||||
},
|
||||
|
||||
// @inheritdoc
|
||||
snapEnds: function (context, min, max, estStepSize) {
|
||||
estStepSize = Math.ceil(estStepSize);
|
||||
var steps = Math.floor((max - min) / estStepSize),
|
||||
data = context.data;
|
||||
return {
|
||||
min: min,
|
||||
max: max,
|
||||
from: min,
|
||||
to: steps * estStepSize + min,
|
||||
step: estStepSize,
|
||||
steps: steps,
|
||||
unit: 1,
|
||||
getLabel: function (current) {
|
||||
return data[this.from + this.step * current];
|
||||
},
|
||||
get: function (current) {
|
||||
return this.from + this.step * current;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
// @inheritdoc
|
||||
trimByRange: function (context, out, trimMin, trimMax) {
|
||||
var unit = out.unit,
|
||||
beginIdx = Math.ceil((trimMin - out.from) / unit) * unit,
|
||||
endIdx = Math.floor((trimMax - out.from) / unit) * unit,
|
||||
begin = Math.max(0, Math.ceil(beginIdx / out.step)),
|
||||
end = Math.min(out.steps, Math.floor(endIdx / out.step));
|
||||
|
||||
if (end < out.steps) {
|
||||
out.to = end;
|
||||
}
|
||||
|
||||
if (out.max > trimMax) {
|
||||
out.max = out.to;
|
||||
}
|
||||
|
||||
if (out.from < trimMin) {
|
||||
out.from = out.from + begin * out.step * unit;
|
||||
while (out.from < trimMin) {
|
||||
begin++;
|
||||
out.from += out.step * unit;
|
||||
}
|
||||
}
|
||||
|
||||
if (out.min < trimMin) {
|
||||
out.min = out.from;
|
||||
}
|
||||
|
||||
out.steps = end - begin;
|
||||
},
|
||||
|
||||
getCoordFor: function (value, field, idx, items) {
|
||||
this.labels.push(value);
|
||||
return this.labels.length - 1;
|
||||
}
|
||||
});
|
||||
136
OfficeWeb/3rdparty/touch/src/chart/axis/layout/Layout.js
vendored
Normal file
136
OfficeWeb/3rdparty/touch/src/chart/axis/layout/Layout.js
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* @abstract
|
||||
* @class Ext.chart.axis.layout.Layout
|
||||
*
|
||||
* Interface used by Axis to process its data into a meaningful layout.
|
||||
*/
|
||||
Ext.define("Ext.chart.axis.layout.Layout", {
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Ext.chart.axis.Axis} axis The axis that the Layout is bound.
|
||||
*/
|
||||
axis: null
|
||||
},
|
||||
|
||||
constructor: function (config) {
|
||||
this.initConfig();
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes the data of the series bound to the axis.
|
||||
* @param series The bound series.
|
||||
*/
|
||||
processData: function (series) {
|
||||
var me = this,
|
||||
axis = me.getAxis(),
|
||||
direction = axis.getDirection(),
|
||||
boundSeries = axis.boundSeries,
|
||||
i, ln, item;
|
||||
if (series) {
|
||||
series['coordinate' + direction]();
|
||||
} else {
|
||||
for (i = 0, ln = boundSeries.length; i < ln; i++) {
|
||||
item = boundSeries[i];
|
||||
if (item['get' + direction + 'Axis']() === axis) {
|
||||
item['coordinate' + direction]();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates the position of major ticks for the axis.
|
||||
* @param context
|
||||
*/
|
||||
calculateMajorTicks: function (context) {
|
||||
var me = this,
|
||||
attr = context.attr,
|
||||
range = attr.max - attr.min,
|
||||
zoom = range / attr.length * (attr.visibleMax - attr.visibleMin),
|
||||
viewMin = attr.min + range * attr.visibleMin,
|
||||
viewMax = attr.min + range * attr.visibleMax,
|
||||
estStepSize = attr.estStepSize * zoom,
|
||||
out = me.snapEnds(context, attr.min, attr.max, estStepSize);
|
||||
if (out) {
|
||||
me.trimByRange(context, out, viewMin - zoom * (1 + attr.startGap), viewMax + zoom * (1 + attr.endGap));
|
||||
context.majorTicks = out;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates the position of sub ticks for the axis.
|
||||
* @param context
|
||||
*/
|
||||
calculateMinorTicks: function (context) {
|
||||
// TODO: Finish Minor ticks.
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates the position of tick marks for the axis.
|
||||
* @param context
|
||||
* @return {*}
|
||||
*/
|
||||
calculateLayout: function (context) {
|
||||
var me = this,
|
||||
attr = context.attr,
|
||||
majorTicks = attr.majorTicks,
|
||||
minorTicks = attr.minorTicks;
|
||||
if (attr.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (majorTicks) {
|
||||
this.calculateMajorTicks(context);
|
||||
if (minorTicks) {
|
||||
this.calculateMinorTicks(context);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Snaps the data bound to the axis to meaningful tick marks.
|
||||
* @param context
|
||||
* @param min
|
||||
* @param max
|
||||
* @param estStepSize
|
||||
*/
|
||||
snapEnds: Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* Trims the layout of the axis by the defined minimum and maximum.
|
||||
* @param context
|
||||
* @param out
|
||||
* @param trimMin
|
||||
* @param trimMax
|
||||
*/
|
||||
trimByRange: function (context, out, trimMin, trimMax) {
|
||||
var segmenter = context.segmenter,
|
||||
unit = out.unit,
|
||||
beginIdx = segmenter.diff(out.from, trimMin, unit),
|
||||
endIdx = segmenter.diff(out.from, trimMax, unit),
|
||||
begin = Math.max(0, Math.ceil(beginIdx / out.step)),
|
||||
end = Math.min(out.steps, Math.floor(endIdx / out.step));
|
||||
|
||||
if (end < out.steps) {
|
||||
out.to = segmenter.add(out.from, end * out.step, unit);
|
||||
}
|
||||
|
||||
if (out.max > trimMax) {
|
||||
out.max = out.to;
|
||||
}
|
||||
|
||||
if (out.from < trimMin) {
|
||||
out.from = segmenter.add(out.from, begin * out.step, unit);
|
||||
while (out.from < trimMin) {
|
||||
begin++;
|
||||
out.from = segmenter.add(out.from, out.step, unit);
|
||||
}
|
||||
}
|
||||
|
||||
if (out.min < trimMin) {
|
||||
out.min = out.from;
|
||||
}
|
||||
|
||||
out.steps = end - begin;
|
||||
}
|
||||
});
|
||||
36
OfficeWeb/3rdparty/touch/src/chart/axis/segmenter/Names.js
vendored
Normal file
36
OfficeWeb/3rdparty/touch/src/chart/axis/segmenter/Names.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @class Ext.chart.axis.segmenter.Names
|
||||
* @extends Ext.chart.axis.segmenter.Segmenter
|
||||
*
|
||||
* Names data type. Names will be calculated as their indices in the methods in this class.
|
||||
* The `preferredStep` always return `{ unit: 1, step: 1 }` to indicate "show every item".
|
||||
*
|
||||
*/
|
||||
Ext.define("Ext.chart.axis.segmenter.Names", {
|
||||
extend: 'Ext.chart.axis.segmenter.Segmenter',
|
||||
alias: 'segmenter.names',
|
||||
|
||||
renderer: function (value, context) {
|
||||
return value;
|
||||
},
|
||||
|
||||
diff: function (min, max, unit) {
|
||||
return Math.floor(max - min);
|
||||
},
|
||||
|
||||
align: function (value, step, unit) {
|
||||
return Math.floor(value);
|
||||
},
|
||||
|
||||
|
||||
add: function (value, step, unit) {
|
||||
return value + step;
|
||||
},
|
||||
|
||||
preferredStep: function (min, estStepSize, minIdx, data) {
|
||||
return {
|
||||
unit: 1,
|
||||
step: 1
|
||||
};
|
||||
}
|
||||
});
|
||||
45
OfficeWeb/3rdparty/touch/src/chart/axis/segmenter/Numeric.js
vendored
Normal file
45
OfficeWeb/3rdparty/touch/src/chart/axis/segmenter/Numeric.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @class Ext.chart.axis.segmenter.Numeric
|
||||
* @extends Ext.chart.axis.segmenter.Segmenter
|
||||
*
|
||||
* Numeric data type.
|
||||
*/
|
||||
Ext.define("Ext.chart.axis.segmenter.Numeric", {
|
||||
extend: 'Ext.chart.axis.segmenter.Segmenter',
|
||||
alias: 'segmenter.numeric',
|
||||
|
||||
renderer: function (value, context) {
|
||||
return value.toFixed(Math.max(0, context.majorTicks.unit.fixes));
|
||||
},
|
||||
|
||||
diff: function (min, max, unit) {
|
||||
return Math.floor((max - min) / unit.scale);
|
||||
},
|
||||
|
||||
align: function (value, step, unit) {
|
||||
return Math.floor(value / (unit.scale * step)) * unit.scale * step;
|
||||
},
|
||||
|
||||
|
||||
add: function (value, step, unit) {
|
||||
return value + step * (unit.scale);
|
||||
},
|
||||
|
||||
preferredStep: function (min, estStepSize) {
|
||||
var logs = Math.floor(Math.log(estStepSize) * Math.LOG10E),
|
||||
scale = Math.pow(10, logs);
|
||||
estStepSize /= scale;
|
||||
if (estStepSize < 2) {
|
||||
estStepSize = 2;
|
||||
} else if (estStepSize < 5) {
|
||||
estStepSize = 5;
|
||||
} else if (estStepSize < 10) {
|
||||
estStepSize = 10;
|
||||
logs++;
|
||||
}
|
||||
return {
|
||||
unit: { fixes: -logs, scale: scale },
|
||||
step: estStepSize
|
||||
};
|
||||
}
|
||||
});
|
||||
84
OfficeWeb/3rdparty/touch/src/chart/axis/segmenter/Segmenter.js
vendored
Normal file
84
OfficeWeb/3rdparty/touch/src/chart/axis/segmenter/Segmenter.js
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @abstract
|
||||
* @class Ext.chart.axis.segmenter.Segmenter
|
||||
*
|
||||
* Interface for a segmenter in an Axis. A segmenter defines the operations you can do to a specific
|
||||
* data type.
|
||||
*
|
||||
* See {@link Ext.chart.axis.Axis}.
|
||||
*
|
||||
*/
|
||||
Ext.define("Ext.chart.axis.segmenter.Segmenter", {
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Ext.chart.axis.Axis} axis The axis that the Segmenter is bound.
|
||||
*/
|
||||
axis: null
|
||||
},
|
||||
|
||||
constructor: function (config) {
|
||||
this.initConfig(config);
|
||||
},
|
||||
|
||||
/**
|
||||
* This method formats the value.
|
||||
*
|
||||
* @param {*} value The value to format.
|
||||
* @param {Object} context Axis layout context.
|
||||
* @return {String}
|
||||
*/
|
||||
renderer: function (value, context) {
|
||||
return String(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert from any data into the target type.
|
||||
* @param {*} value The value to convert from
|
||||
* @return {*} The converted value.
|
||||
*/
|
||||
from: function (value) {
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the difference between the min and max value based on the given unit scale.
|
||||
*
|
||||
* @param {*} min The smaller value.
|
||||
* @param {*} max The larger value.
|
||||
* @param {*} unit The unit scale. Unit can be any type.
|
||||
* @return {Number} The number of `unit`s between min and max. It is the minimum n that min + n * unit >= max.
|
||||
*/
|
||||
diff: Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* Align value with step of units.
|
||||
* For example, for the date segmenter, if The unit is "Month" and step is 3, the value will be aligned by
|
||||
* seasons.
|
||||
*
|
||||
* @param {*} value The value to be aligned.
|
||||
* @param {Number} step The step of units.
|
||||
* @param {*} unit The unit.
|
||||
* @return {*} Aligned value.
|
||||
*/
|
||||
align: Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* Add `step` `unit`s to the value.
|
||||
* @param {*} value The value to be added.
|
||||
* @param {Number} step The step of units. Negative value are allowed.
|
||||
* @param {*} unit The unit.
|
||||
*/
|
||||
add: Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* Given a start point and estimated step size of a range, determine the preferred step size.
|
||||
*
|
||||
* @param {*} start The start point of range.
|
||||
* @param {*} estStepSize The estimated step size.
|
||||
* @return {Object} Return the step size by an object of step x unit.
|
||||
* @return {Number} return.step The step count of units.
|
||||
* @return {*} return.unit The unit.
|
||||
*/
|
||||
preferredStep: Ext.emptyFn
|
||||
});
|
||||
107
OfficeWeb/3rdparty/touch/src/chart/axis/segmenter/Time.js
vendored
Normal file
107
OfficeWeb/3rdparty/touch/src/chart/axis/segmenter/Time.js
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @class Ext.chart.axis.segmenter.Time
|
||||
* @extends Ext.chart.axis.segmenter.Segmenter
|
||||
*
|
||||
* Time data type.
|
||||
*/
|
||||
Ext.define("Ext.chart.axis.segmenter.Time", {
|
||||
extend: 'Ext.chart.axis.segmenter.Segmenter',
|
||||
alias: 'segmenter.time',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Object} step
|
||||
* If specified, the will override the result of {@link #preferredStep}.
|
||||
*/
|
||||
step: null
|
||||
},
|
||||
|
||||
renderer: function (value, context) {
|
||||
var ExtDate = Ext.Date;
|
||||
switch (context.majorTicks.unit) {
|
||||
case 'y':
|
||||
return ExtDate.format(value, 'Y');
|
||||
case 'mo':
|
||||
return ExtDate.format(value, 'Y-m');
|
||||
case 'd':
|
||||
return ExtDate.format(value, 'Y-m-d');
|
||||
}
|
||||
return ExtDate.format(value, 'Y-m-d\nH:i:s');
|
||||
},
|
||||
|
||||
from: function (value) {
|
||||
return new Date(value);
|
||||
},
|
||||
|
||||
diff: function (min, max, unit) {
|
||||
var ExtDate = Ext.Date;
|
||||
if (isFinite(min)) {
|
||||
min = new Date(min);
|
||||
}
|
||||
if (isFinite(max)) {
|
||||
max = new Date(max);
|
||||
}
|
||||
return ExtDate.diff(min, max, unit);
|
||||
},
|
||||
|
||||
align: function (date, step, unit) {
|
||||
if (unit === 'd' && step >= 7) {
|
||||
date = Ext.Date.align(date, 'd', step);
|
||||
date.setDate(date.getDate() - date.getDay() + 1);
|
||||
return date;
|
||||
} else {
|
||||
return Ext.Date.align(date, unit, step);
|
||||
}
|
||||
},
|
||||
|
||||
add: function (value, step, unit) {
|
||||
return Ext.Date.add(new Date(value), unit, step);
|
||||
},
|
||||
|
||||
preferredStep: function (min, estStepSize) {
|
||||
if (this.getStep()) {
|
||||
return this.getStep();
|
||||
}
|
||||
var from = new Date(+min),
|
||||
to = new Date(+min + Math.ceil(estStepSize)),
|
||||
ExtDate = Ext.Date,
|
||||
units = [
|
||||
[ExtDate.YEAR, 1, 2, 5, 10, 20, 50, 100, 200, 500],
|
||||
[ExtDate.MONTH, 1, 3, 6],
|
||||
[ExtDate.DAY, 1, 7, 14],
|
||||
[ExtDate.HOUR, 1, 6, 12],
|
||||
[ExtDate.MINUTE, 1, 5, 15, 30],
|
||||
[ExtDate.SECOND, 1, 5, 15, 30],
|
||||
[ExtDate.MILLI, 1, 2, 5, 10, 20, 50, 100, 200, 500]
|
||||
],
|
||||
result;
|
||||
|
||||
for (var i = 0; i < units.length; i++) {
|
||||
var unit = units[i][0],
|
||||
diff = this.diff(from, to, unit);
|
||||
if (diff > 0) {
|
||||
for (var j = 1; j < units[i].length; j++) {
|
||||
if (diff <= units[i][j]) {
|
||||
result = {
|
||||
unit: unit,
|
||||
step: units[i][j]
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
i--;
|
||||
result = {
|
||||
unit: units[i][0],
|
||||
step: 1
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
result = {unit: ExtDate.DAY, step: 1}; // Default step is one Day.
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
700
OfficeWeb/3rdparty/touch/src/chart/axis/sprite/Axis.js
vendored
Normal file
700
OfficeWeb/3rdparty/touch/src/chart/axis/sprite/Axis.js
vendored
Normal file
@@ -0,0 +1,700 @@
|
||||
/**
|
||||
* @private
|
||||
* @class Ext.chart.axis.sprite.Axis
|
||||
* @extends Ext.draw.sprite.Sprite
|
||||
*
|
||||
* The axis sprite. Currently all types of the axis will be rendered with this sprite.
|
||||
* TODO(touch-2.2): Split different types of axis into different sprite classes.
|
||||
*/
|
||||
Ext.define("Ext.chart.axis.sprite.Axis", {
|
||||
extend: 'Ext.draw.sprite.Sprite',
|
||||
mixins: {
|
||||
markerHolder: "Ext.chart.MarkerHolder"
|
||||
},
|
||||
|
||||
requires: ['Ext.draw.sprite.Text'],
|
||||
|
||||
inheritableStatics: {
|
||||
def: {
|
||||
processors: {
|
||||
/**
|
||||
* @cfg {Boolean} grid 'true' if the axis has a grid.
|
||||
*/
|
||||
grid: 'bool',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} axisLine 'true' if the main line of the axis is drawn.
|
||||
*/
|
||||
axisLine: 'bool',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} minorTricks 'true' if the axis has sub ticks.
|
||||
*/
|
||||
minorTicks: 'bool',
|
||||
|
||||
/**
|
||||
* @cfg {Number} minorTickSize The length of the minor ticks.
|
||||
*/
|
||||
minorTickSize: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} majorTicks 'true' if the axis has major ticks.
|
||||
*/
|
||||
majorTicks: 'bool',
|
||||
|
||||
/**
|
||||
* @cfg {Number} majorTickSize The length of the major ticks.
|
||||
*/
|
||||
majorTickSize: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Number} length The total length of the axis.
|
||||
*/
|
||||
length: 'number',
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Number} startGap Axis start determined by the chart inset padding.
|
||||
*/
|
||||
startGap: 'number',
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Number} endGap Axis end determined by the chart inset padding.
|
||||
*/
|
||||
endGap: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Number} dataMin The minimum value of the axis data.
|
||||
*/
|
||||
dataMin: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Number} dataMax The maximum value of the axis data.
|
||||
*/
|
||||
dataMax: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Number} visibleMin The minimum value that is displayed.
|
||||
*/
|
||||
visibleMin: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Number} visibleMax The maximum value that is displayed.
|
||||
*/
|
||||
visibleMax: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {String} position The position of the axis on the chart.
|
||||
*/
|
||||
position: 'enums(left,right,top,bottom,angular,radial)',
|
||||
|
||||
/**
|
||||
* @cfg {Number} minStepSize The minimum step size between ticks.
|
||||
*/
|
||||
minStepSize: 'number',
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Number} estStepSize The estimated step size between ticks.
|
||||
*/
|
||||
estStepSize: 'number',
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Unused.
|
||||
*/
|
||||
titleOffset: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Number} textPadding The padding around axis labels to determine collision.
|
||||
*/
|
||||
textPadding: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Number} min The minimum value of the axis.
|
||||
*/
|
||||
min: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Number} max The maximum value of the axis.
|
||||
*/
|
||||
max: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Number} centerX The central point of the angular axis on the x-axis.
|
||||
*/
|
||||
centerX: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Number} centerX The central point of the angular axis on the y-axis.
|
||||
*/
|
||||
centerY: 'number',
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Number} radius
|
||||
* Unused.
|
||||
*/
|
||||
radius: 'number',
|
||||
|
||||
/**
|
||||
* @cfg {Number} The starting rotation of the angular axis.
|
||||
*/
|
||||
baseRotation: 'number',
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Unused.
|
||||
*/
|
||||
data: 'default',
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} 'true' if the estimated step size is adjusted by text size.
|
||||
*/
|
||||
enlargeEstStepSizeByText: 'bool'
|
||||
},
|
||||
|
||||
defaults: {
|
||||
grid: false,
|
||||
axisLine: true,
|
||||
minorTicks: false,
|
||||
minorTickSize: 3,
|
||||
majorTicks: true,
|
||||
majorTickSize: 5,
|
||||
length: 0,
|
||||
startGap: 0,
|
||||
endGap: 0,
|
||||
visibleMin: 0,
|
||||
visibleMax: 1,
|
||||
dataMin: 0,
|
||||
dataMax: 1,
|
||||
position: '',
|
||||
minStepSize: 0,
|
||||
estStepSize: 42,
|
||||
min: 0,
|
||||
max: 1,
|
||||
centerX: 0,
|
||||
centerY: 0,
|
||||
radius: 1,
|
||||
baseRotation: 0,
|
||||
data: null,
|
||||
titleOffset: 0,
|
||||
textPadding: 5,
|
||||
scalingCenterY: 0,
|
||||
scalingCenterX: 0,
|
||||
// Override default
|
||||
strokeStyle: 'black',
|
||||
enlargeEstStepSizeByText: false
|
||||
},
|
||||
|
||||
dirtyTriggers: {
|
||||
minorTickSize: 'bbox',
|
||||
majorTickSize: 'bbox',
|
||||
position: 'bbox,layout',
|
||||
axisLine: 'bbox,layout',
|
||||
min: 'layout',
|
||||
max: 'layout',
|
||||
length: 'layout',
|
||||
minStepSize: 'layout',
|
||||
estStepSize: 'layout',
|
||||
data: 'layout',
|
||||
dataMin: 'layout',
|
||||
dataMax: 'layout',
|
||||
visibleMin: 'layout',
|
||||
visibleMax: 'layout',
|
||||
enlargeEstStepSizeByText: 'layout'
|
||||
},
|
||||
updaters: {
|
||||
'layout': function () {
|
||||
this.doLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
config: {
|
||||
|
||||
/**
|
||||
* @cfg {Object} label
|
||||
*
|
||||
* The label configuration object for the Axis. This object may include style attributes
|
||||
* like `spacing`, `padding`, `font` that receives a string or number and
|
||||
* returns a new string with the modified values.
|
||||
*/
|
||||
label: null,
|
||||
|
||||
/**
|
||||
* @cfg {Object|Ext.chart.axis.layout.Layout} layout The layout configuration used by the axis.
|
||||
*/
|
||||
layout: null,
|
||||
|
||||
/**
|
||||
* @cfg {Object|Ext.chart.axis.segmenter.Segmenter} segmenter The method of segmenter used by the axis.
|
||||
*/
|
||||
segmenter: null,
|
||||
|
||||
/**
|
||||
* @cfg {Function} renderer Allows direct customisation of rendered axis sprites.
|
||||
*/
|
||||
renderer: null,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Object} layoutContext Stores the context after calculating layout.
|
||||
*/
|
||||
layoutContext: null,
|
||||
|
||||
/**
|
||||
* @cfg {Ext.chart.axis.Axis} axis The axis represented by the this sprite.
|
||||
*/
|
||||
axis: null
|
||||
},
|
||||
|
||||
thickness: 0,
|
||||
|
||||
stepSize: 0,
|
||||
|
||||
getBBox: function () { return null; },
|
||||
|
||||
doLayout: function () {
|
||||
var me = this,
|
||||
attr = me.attr,
|
||||
layout = me.getLayout(),
|
||||
min = attr.dataMin + (attr.dataMax - attr.dataMin) * attr.visibleMin,
|
||||
max = attr.dataMin + (attr.dataMax - attr.dataMin) * attr.visibleMax,
|
||||
context = {
|
||||
attr: attr,
|
||||
segmenter: me.getSegmenter()
|
||||
};
|
||||
|
||||
if (attr.position === 'left' || attr.position === 'right') {
|
||||
attr.translationX = 0;
|
||||
attr.translationY = max * attr.length / (max - min);
|
||||
attr.scalingX = 1;
|
||||
attr.scalingY = -attr.length / (max - min);
|
||||
attr.scalingCenterY = 0;
|
||||
attr.scalingCenterX = 0;
|
||||
me.applyTransformations(true);
|
||||
} else if (attr.position === 'top' || attr.position === 'bottom') {
|
||||
attr.translationX = -min * attr.length / (max - min);
|
||||
attr.translationY = 0;
|
||||
attr.scalingX = attr.length / (max - min);
|
||||
attr.scalingY = 1;
|
||||
attr.scalingCenterY = 0;
|
||||
attr.scalingCenterX = 0;
|
||||
me.applyTransformations(true);
|
||||
}
|
||||
|
||||
if (layout) {
|
||||
layout.calculateLayout(context);
|
||||
me.setLayoutContext(context);
|
||||
}
|
||||
},
|
||||
|
||||
iterate: function (snaps, fn) {
|
||||
var i, position;
|
||||
if (snaps.getLabel) {
|
||||
if (snaps.min < snaps.from) {
|
||||
fn.call(this, snaps.min, snaps.getLabel(snaps.min), -1, snaps);
|
||||
}
|
||||
for (i = 0; i <= snaps.steps; i++) {
|
||||
fn.call(this, snaps.get(i), snaps.getLabel(i), i, snaps);
|
||||
}
|
||||
if (snaps.max > snaps.to) {
|
||||
fn.call(this, snaps.max, snaps.getLabel(snaps.max), snaps.steps + 1, snaps);
|
||||
}
|
||||
} else {
|
||||
if (snaps.min < snaps.from) {
|
||||
fn.call(this, snaps.min, snaps.min, -1, snaps);
|
||||
}
|
||||
for (i = 0; i <= snaps.steps; i++) {
|
||||
position = snaps.get(i);
|
||||
fn.call(this, position, position, i, snaps);
|
||||
}
|
||||
if (snaps.max > snaps.to) {
|
||||
fn.call(this, snaps.max, snaps.max, snaps.steps + 1, snaps);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
renderTicks: function (surface, ctx, layout, clipRegion) {
|
||||
var me = this,
|
||||
attr = me.attr,
|
||||
docked = attr.position,
|
||||
matrix = attr.matrix,
|
||||
halfLineWidth = 0.5 * attr.lineWidth,
|
||||
xx = matrix.getXX(),
|
||||
dx = matrix.getDX(),
|
||||
yy = matrix.getYY(),
|
||||
dy = matrix.getDY(),
|
||||
majorTicks = layout.majorTicks,
|
||||
majorTickSize = attr.majorTickSize,
|
||||
minorTicks = layout.minorTicks,
|
||||
minorTickSize = attr.minorTickSize;
|
||||
|
||||
if (majorTicks) {
|
||||
switch (docked) {
|
||||
case 'right':
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
position = surface.roundPixel(position * yy + dy) + halfLineWidth;
|
||||
ctx.moveTo(0, position);
|
||||
ctx.lineTo(majorTickSize, position);
|
||||
});
|
||||
break;
|
||||
case 'left':
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
position = surface.roundPixel(position * yy + dy) + halfLineWidth;
|
||||
ctx.moveTo(clipRegion[2] - majorTickSize, position);
|
||||
ctx.lineTo(clipRegion[2], position);
|
||||
});
|
||||
break;
|
||||
case 'bottom':
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
position = surface.roundPixel(position * xx + dx) - halfLineWidth;
|
||||
ctx.moveTo(position, 0);
|
||||
ctx.lineTo(position, majorTickSize);
|
||||
});
|
||||
break;
|
||||
case 'top':
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
position = surface.roundPixel(position * xx + dx) - halfLineWidth;
|
||||
ctx.moveTo(position, clipRegion[3]);
|
||||
ctx.lineTo(position, clipRegion[3] - majorTickSize);
|
||||
});
|
||||
break;
|
||||
case 'angular':
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
position = position / (attr.max + 1) * Math.PI * 2 + attr.baseRotation;
|
||||
ctx.moveTo(
|
||||
attr.centerX + (attr.length) * Math.cos(position),
|
||||
attr.centerY + (attr.length) * Math.sin(position)
|
||||
);
|
||||
ctx.lineTo(
|
||||
attr.centerX + (attr.length + majorTickSize) * Math.cos(position),
|
||||
attr.centerY + (attr.length + majorTickSize) * Math.sin(position)
|
||||
);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
renderLabels: function (surface, ctx, layout, clipRegion) {
|
||||
var me = this,
|
||||
attr = me.attr,
|
||||
halfLineWidth = 0.5 * attr.lineWidth,
|
||||
docked = attr.position,
|
||||
matrix = attr.matrix,
|
||||
textPadding = attr.textPadding,
|
||||
xx = matrix.getXX(),
|
||||
dx = matrix.getDX(),
|
||||
yy = matrix.getYY(),
|
||||
dy = matrix.getDY(),
|
||||
thickness = 0,
|
||||
majorTicks = layout.majorTicks,
|
||||
padding = Math.max(attr.majorTickSize, attr.minorTickSize) + attr.lineWidth,
|
||||
label = this.getLabel(), font,
|
||||
lastLabelText = null,
|
||||
textSize = 0, textCount = 0,
|
||||
segmenter = layout.segmenter,
|
||||
renderer = this.getRenderer(),
|
||||
labelInverseMatrix, lastBBox = null, bbox, fly, text;
|
||||
if (majorTicks && label && !label.attr.hidden) {
|
||||
font = label.attr.font;
|
||||
if (ctx.font !== font) {
|
||||
ctx.font = font;
|
||||
} // This can profoundly improve performance.
|
||||
label.setAttributes({translationX: 0, translationY: 0}, true, true);
|
||||
label.applyTransformations();
|
||||
labelInverseMatrix = label.attr.inverseMatrix.elements.slice(0);
|
||||
switch (docked) {
|
||||
case 'left':
|
||||
label.setAttributes({
|
||||
textAlign: 'center',
|
||||
textBaseline: 'middle',
|
||||
translationX: surface.roundPixel(clipRegion[2] - padding + dx) - halfLineWidth - me.thickness / 2
|
||||
}, true, true);
|
||||
break;
|
||||
case 'right':
|
||||
label.setAttributes({
|
||||
textAlign: 'center',
|
||||
textBaseline: 'middle',
|
||||
translationX: surface.roundPixel(padding + dx) - halfLineWidth + me.thickness / 2
|
||||
}, true, true);
|
||||
break;
|
||||
case 'top':
|
||||
label.setAttributes({
|
||||
textAlign: 'center',
|
||||
textBaseline: 'middle',
|
||||
translationY: surface.roundPixel(clipRegion[3] - padding) - halfLineWidth - me.thickness / 2
|
||||
}, true, true);
|
||||
break;
|
||||
case 'bottom':
|
||||
label.setAttributes({
|
||||
textAlign: 'center',
|
||||
textBaseline: 'middle',
|
||||
translationY: surface.roundPixel(padding) - halfLineWidth + me.thickness / 2
|
||||
}, true, true);
|
||||
break;
|
||||
case 'radial' :
|
||||
label.setAttributes({
|
||||
textAlign: 'center',
|
||||
textBaseline: 'middle',
|
||||
translationX: attr.centerX
|
||||
}, true, true);
|
||||
break;
|
||||
case 'angular':
|
||||
label.setAttributes({
|
||||
textAlign: 'center',
|
||||
textBaseline: 'middle',
|
||||
translationY: attr.centerY
|
||||
}, true, true);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: there are better ways to detect collision.
|
||||
if (docked === 'left' || docked === 'right') {
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
if (labelText === undefined) {
|
||||
return;
|
||||
}
|
||||
text = renderer ? renderer.call(this, labelText, layout, lastLabelText) : segmenter.renderer(labelText, layout, lastLabelText);
|
||||
lastLabelText = labelText;
|
||||
label.setAttributes({
|
||||
text: String(text),
|
||||
translationY: surface.roundPixel(position * yy + dy)
|
||||
}, true, true);
|
||||
label.applyTransformations();
|
||||
thickness = Math.max(thickness, label.getBBox().width + padding);
|
||||
if (thickness <= me.thickness) {
|
||||
fly = Ext.draw.Matrix.fly(label.attr.matrix.elements.slice(0));
|
||||
bbox = fly.prepend.apply(fly, labelInverseMatrix).transformBBox(label.getBBox(true));
|
||||
if (lastBBox && !Ext.draw.Draw.isBBoxIntersect(bbox, lastBBox, textPadding)) {
|
||||
return;
|
||||
}
|
||||
surface.renderSprite(label);
|
||||
lastBBox = bbox;
|
||||
textSize += bbox.height;
|
||||
textCount++;
|
||||
}
|
||||
});
|
||||
} else if (docked === 'top' || docked === 'bottom') {
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
if (labelText === undefined) {
|
||||
return;
|
||||
}
|
||||
text = renderer ? renderer.call(this, labelText, layout, lastLabelText) : segmenter.renderer(labelText, layout, lastLabelText);
|
||||
lastLabelText = labelText;
|
||||
label.setAttributes({
|
||||
text: String(text),
|
||||
translationX: surface.roundPixel(position * xx + dx)
|
||||
}, true, true);
|
||||
label.applyTransformations();
|
||||
thickness = Math.max(thickness, label.getBBox().height + padding);
|
||||
if (thickness <= me.thickness) {
|
||||
fly = Ext.draw.Matrix.fly(label.attr.matrix.elements.slice(0));
|
||||
bbox = fly.prepend.apply(fly, labelInverseMatrix).transformBBox(label.getBBox(true));
|
||||
if (lastBBox && !Ext.draw.Draw.isBBoxIntersect(bbox, lastBBox, textPadding)) {
|
||||
return;
|
||||
}
|
||||
surface.renderSprite(label);
|
||||
lastBBox = bbox;
|
||||
textSize += bbox.width;
|
||||
textCount++;
|
||||
}
|
||||
});
|
||||
} else if (docked === 'radial') {
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
if (labelText === undefined) {
|
||||
return;
|
||||
}
|
||||
text = renderer ? renderer.call(this, labelText, layout, lastLabelText) : segmenter.renderer(labelText, layout, lastLabelText);
|
||||
lastLabelText = labelText;
|
||||
if (typeof text !== 'undefined') {
|
||||
label.setAttributes({
|
||||
text: String(text),
|
||||
translationY: attr.centerY - surface.roundPixel(position) / attr.max * attr.length
|
||||
}, true, true);
|
||||
label.applyTransformations();
|
||||
bbox = label.attr.matrix.transformBBox(label.getBBox(true));
|
||||
if (lastBBox && !Ext.draw.Draw.isBBoxIntersect(bbox, lastBBox)) {
|
||||
return;
|
||||
}
|
||||
surface.renderSprite(label);
|
||||
lastBBox = bbox;
|
||||
textSize += bbox.width;
|
||||
textCount++;
|
||||
}
|
||||
});
|
||||
} else if (docked === 'angular') {
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
if (labelText === undefined) {
|
||||
return;
|
||||
}
|
||||
text = renderer ? renderer.call(this, labelText, layout, lastLabelText) : segmenter.renderer(labelText, layout, lastLabelText);
|
||||
lastLabelText = labelText;
|
||||
|
||||
if (typeof text !== 'undefined') {
|
||||
var angle = position / (attr.max + 1) * Math.PI * 2 + attr.baseRotation;
|
||||
label.setAttributes({
|
||||
text: String(text),
|
||||
translationX: attr.centerX + (attr.length + 10) * Math.cos(angle),
|
||||
translationY: attr.centerY + (attr.length + 10) * Math.sin(angle)
|
||||
}, true, true);
|
||||
label.applyTransformations();
|
||||
bbox = label.attr.matrix.transformBBox(label.getBBox(true));
|
||||
if (lastBBox && !Ext.draw.Draw.isBBoxIntersect(bbox, lastBBox)) {
|
||||
return;
|
||||
}
|
||||
surface.renderSprite(label);
|
||||
lastBBox = bbox;
|
||||
textSize += bbox.width;
|
||||
textCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (attr.enlargeEstStepSizeByText && textCount) {
|
||||
textSize /= textCount;
|
||||
textSize += padding;
|
||||
textSize *= 2;
|
||||
if (attr.estStepSize < textSize) {
|
||||
attr.estStepSize = textSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.abs(me.thickness - (thickness)) > 1) {
|
||||
me.thickness = thickness;
|
||||
attr.bbox.plain.dirty = true;
|
||||
attr.bbox.transform.dirty = true;
|
||||
me.doThicknessChanged();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
renderAxisLine: function (surface, ctx, layout, clipRegion) {
|
||||
var me = this,
|
||||
attr = me.attr,
|
||||
halfWidth = attr.lineWidth * 0.5,
|
||||
docked = attr.position;
|
||||
if (attr.axisLine) {
|
||||
switch (docked) {
|
||||
case 'left':
|
||||
ctx.moveTo(clipRegion[2] - halfWidth, -attr.endGap);
|
||||
ctx.lineTo(clipRegion[2] - halfWidth, attr.length + attr.startGap);
|
||||
break;
|
||||
case 'right':
|
||||
ctx.moveTo(halfWidth, -attr.endGap);
|
||||
ctx.lineTo(halfWidth, attr.length + attr.startGap);
|
||||
break;
|
||||
case 'bottom':
|
||||
ctx.moveTo(-attr.startGap, halfWidth);
|
||||
ctx.lineTo(attr.length + attr.endGap, halfWidth);
|
||||
break;
|
||||
case 'top':
|
||||
ctx.moveTo(-attr.startGap, clipRegion[3] - halfWidth);
|
||||
ctx.lineTo(attr.length + attr.endGap, clipRegion[3] - halfWidth);
|
||||
break;
|
||||
case 'angular':
|
||||
ctx.moveTo(attr.centerX + attr.length, attr.centerY);
|
||||
ctx.arc(attr.centerX, attr.centerY, attr.length, 0, Math.PI * 2, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
renderGridLines: function (surface, ctx, layout, clipRegion) {
|
||||
var me = this,
|
||||
attr = me.attr,
|
||||
matrix = attr.matrix,
|
||||
xx = matrix.getXX(),
|
||||
yy = matrix.getYY(),
|
||||
dx = matrix.getDX(),
|
||||
dy = matrix.getDY(),
|
||||
position = attr.position,
|
||||
majorTicks = layout.majorTicks,
|
||||
anchor, j, lastAnchor;
|
||||
if (attr.grid) {
|
||||
if (majorTicks) {
|
||||
if (position === 'left' || position === 'right') {
|
||||
lastAnchor = attr.min * yy + dy;
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
anchor = position * yy + dy;
|
||||
me.putMarker('horizontal-' + (i % 2 ? 'odd' : 'even'), {
|
||||
y: anchor,
|
||||
height: lastAnchor - anchor
|
||||
}, j = i, true);
|
||||
lastAnchor = anchor;
|
||||
});
|
||||
j++;
|
||||
anchor = 0;
|
||||
me.putMarker('horizontal-' + (j % 2 ? 'odd' : 'even'), {
|
||||
y: anchor,
|
||||
height: lastAnchor - anchor
|
||||
}, j, true);
|
||||
} else if (position === 'top' || position === 'bottom') {
|
||||
lastAnchor = attr.min * xx + dx;
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
anchor = position * xx + dx;
|
||||
me.putMarker('vertical-' + (i % 2 ? 'odd' : 'even'), {
|
||||
x: anchor,
|
||||
width: lastAnchor - anchor
|
||||
}, j = i, true);
|
||||
lastAnchor = anchor;
|
||||
});
|
||||
j++;
|
||||
anchor = attr.length;
|
||||
me.putMarker('vertical-' + (j % 2 ? 'odd' : 'even'), {
|
||||
x: anchor,
|
||||
width: lastAnchor - anchor
|
||||
}, j, true);
|
||||
} else if (position === 'radial') {
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
anchor = position / attr.max * attr.length;
|
||||
me.putMarker('circular-' + (i % 2 ? 'odd' : 'even'), {
|
||||
scalingX: anchor,
|
||||
scalingY: anchor
|
||||
}, i, true);
|
||||
lastAnchor = anchor;
|
||||
});
|
||||
} else if (position === 'angular') {
|
||||
me.iterate(majorTicks, function (position, labelText, i) {
|
||||
anchor = position / (attr.max + 1) * Math.PI * 2 + attr.baseRotation;
|
||||
me.putMarker('radial-' + (i % 2 ? 'odd' : 'even'), {
|
||||
rotationRads: anchor,
|
||||
rotationCenterX: 0,
|
||||
rotationCenterY: 0,
|
||||
scalingX: attr.length,
|
||||
scalingY: attr.length
|
||||
}, i, true);
|
||||
lastAnchor = anchor;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
doThicknessChanged: function () {
|
||||
var axis = this.getAxis();
|
||||
if (axis) {
|
||||
axis.onThicknessChanged();
|
||||
}
|
||||
},
|
||||
|
||||
render: function (surface, ctx, clipRegion) {
|
||||
var me = this,
|
||||
layout = me.getLayoutContext();
|
||||
if (layout) {
|
||||
if (false === me.renderLabels(surface, ctx, layout, clipRegion)) {
|
||||
return false;
|
||||
}
|
||||
ctx.beginPath();
|
||||
me.renderTicks(surface, ctx, layout, clipRegion);
|
||||
me.renderAxisLine(surface, ctx, layout, clipRegion);
|
||||
me.renderGridLines(surface, ctx, layout, clipRegion);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
});
|
||||
19
OfficeWeb/3rdparty/touch/src/chart/grid/CircularGrid.js
vendored
Normal file
19
OfficeWeb/3rdparty/touch/src/chart/grid/CircularGrid.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @class Ext.chart.grid.CircularGrid
|
||||
* @extends Ext.draw.sprite.Circle
|
||||
*
|
||||
* Circular Grid sprite.
|
||||
*/
|
||||
Ext.define("Ext.chart.grid.CircularGrid", {
|
||||
extend: 'Ext.draw.sprite.Circle',
|
||||
alias: 'grid.circular',
|
||||
|
||||
inheritableStatics: {
|
||||
def: {
|
||||
defaults: {
|
||||
r: 1,
|
||||
strokeStyle: '#DDD'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
46
OfficeWeb/3rdparty/touch/src/chart/grid/HorizontalGrid.js
vendored
Normal file
46
OfficeWeb/3rdparty/touch/src/chart/grid/HorizontalGrid.js
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @class Ext.chart.grid.HorizontalGrid
|
||||
* @extends Ext.draw.sprite.Sprite
|
||||
*
|
||||
* Horizontal Grid sprite. Used in Cartesian Charts.
|
||||
*/
|
||||
Ext.define("Ext.chart.grid.HorizontalGrid", {
|
||||
extend: 'Ext.draw.sprite.Sprite',
|
||||
alias: 'grid.horizontal',
|
||||
|
||||
inheritableStatics: {
|
||||
def: {
|
||||
processors: {
|
||||
x: 'number',
|
||||
y: 'number',
|
||||
width: 'number',
|
||||
height: 'number'
|
||||
},
|
||||
|
||||
defaults: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 1,
|
||||
height: 1,
|
||||
strokeStyle: '#DDD'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render: function (surface, ctx, clipRegion) {
|
||||
var attr = this.attr,
|
||||
x = attr.x,
|
||||
y = surface.roundPixel(attr.y),
|
||||
w = attr.width,
|
||||
h = attr.height,
|
||||
halfLineWidth = ctx.lineWidth * 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.rect(clipRegion[0] - surface.matrix.getDX(), y + halfLineWidth, +clipRegion[2], attr.height);
|
||||
ctx.fill();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(clipRegion[0] - surface.matrix.getDX(), y + halfLineWidth);
|
||||
ctx.lineTo(clipRegion[0] + clipRegion[2] - surface.matrix.getDX(), y + halfLineWidth);
|
||||
ctx.stroke();
|
||||
}
|
||||
});
|
||||
44
OfficeWeb/3rdparty/touch/src/chart/grid/RadialGrid.js
vendored
Normal file
44
OfficeWeb/3rdparty/touch/src/chart/grid/RadialGrid.js
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @class Ext.chart.grid.RadialGrid
|
||||
* @extends Ext.draw.sprite.Path
|
||||
*
|
||||
* Radial Grid sprite. Used by Radar to render a series of concentric circles.
|
||||
* Represents the scale of the radar chart on the yField.
|
||||
*/
|
||||
Ext.define("Ext.chart.grid.RadialGrid", {
|
||||
extend: 'Ext.draw.sprite.Path',
|
||||
alias: 'grid.radial',
|
||||
|
||||
inheritableStatics: {
|
||||
def: {
|
||||
processors: {
|
||||
startRadius: 'number',
|
||||
endRadius: 'number'
|
||||
},
|
||||
|
||||
defaults: {
|
||||
startRadius: 0,
|
||||
endRadius: 1,
|
||||
scalingCenterX: 0,
|
||||
scalingCenterY: 0,
|
||||
strokeStyle: '#DDD'
|
||||
},
|
||||
|
||||
dirtyTriggers: {
|
||||
startRadius: 'path,bbox',
|
||||
endRadius: 'path,bbox'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.callSuper(arguments);
|
||||
},
|
||||
|
||||
updatePath: function (path, attr) {
|
||||
var startRadius = attr.startRadius,
|
||||
endRadius = attr.endRadius;
|
||||
path.moveTo(startRadius, 0);
|
||||
path.lineTo(endRadius, 0);
|
||||
}
|
||||
});
|
||||
43
OfficeWeb/3rdparty/touch/src/chart/grid/VerticalGrid.js
vendored
Normal file
43
OfficeWeb/3rdparty/touch/src/chart/grid/VerticalGrid.js
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @class Ext.chart.grid.VerticalGrid
|
||||
* @extends Ext.draw.sprite.Sprite
|
||||
*
|
||||
* Vertical Grid sprite. Used in Cartesian Charts.
|
||||
*/
|
||||
Ext.define("Ext.chart.grid.VerticalGrid", {
|
||||
extend: 'Ext.draw.sprite.Sprite',
|
||||
alias: 'grid.vertical',
|
||||
|
||||
inheritableStatics: {
|
||||
def: {
|
||||
processors: {
|
||||
x: 'number',
|
||||
y: 'number',
|
||||
width: 'number',
|
||||
height: 'number'
|
||||
},
|
||||
|
||||
defaults: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 1,
|
||||
height: 1,
|
||||
strokeStyle: '#DDD'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render: function (surface, ctx, clipRegion) {
|
||||
var attr = this.attr,
|
||||
x = surface.roundPixel(attr.x),
|
||||
halfLineWidth = ctx.lineWidth * 0.5;
|
||||
ctx.beginPath();
|
||||
ctx.rect(x - halfLineWidth, clipRegion[1] - surface.matrix.getDY(), attr.width, clipRegion[3]);
|
||||
ctx.fill();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x - halfLineWidth, clipRegion[1] - surface.matrix.getDY());
|
||||
ctx.lineTo(x - halfLineWidth, clipRegion[1] + clipRegion[3] - surface.matrix.getDY());
|
||||
ctx.stroke();
|
||||
}
|
||||
});
|
||||
230
OfficeWeb/3rdparty/touch/src/chart/interactions/Abstract.js
vendored
Normal file
230
OfficeWeb/3rdparty/touch/src/chart/interactions/Abstract.js
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* @class Ext.chart.interactions.Abstract
|
||||
*
|
||||
* Defines a common abstract parent class for all interactions.
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.chart.interactions.Abstract', {
|
||||
|
||||
xtype: 'interaction',
|
||||
|
||||
mixins: {
|
||||
observable: "Ext.mixin.Observable"
|
||||
},
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} gesture
|
||||
* Specifies which gesture type should be used for starting the interaction.
|
||||
*/
|
||||
gesture: 'tap',
|
||||
|
||||
/**
|
||||
* @cfg {Ext.chart.AbstractChart} chart The chart that the interaction is bound.
|
||||
*/
|
||||
chart: null,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} enabled 'true' if the interaction is enabled.
|
||||
*/
|
||||
enabled: true
|
||||
},
|
||||
|
||||
/**
|
||||
* Android device is emerging too many events so if we re-render every frame it will take for-ever to finish a frame.
|
||||
* This throttle technique will limit the timespan between two frames.
|
||||
*/
|
||||
throttleGap: 0,
|
||||
|
||||
stopAnimationBeforeSync: false,
|
||||
|
||||
constructor: function (config) {
|
||||
var me = this;
|
||||
me.initConfig(config);
|
||||
Ext.ComponentManager.register(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* A method to be implemented by subclasses where all event attachment should occur.
|
||||
*/
|
||||
initialize: Ext.emptyFn,
|
||||
|
||||
updateChart: function (newChart, oldChart) {
|
||||
var me = this, gestures = me.getGestures();
|
||||
if (oldChart === newChart) {
|
||||
return;
|
||||
}
|
||||
if (oldChart) {
|
||||
me.removeChartListener(oldChart);
|
||||
}
|
||||
if (newChart) {
|
||||
me.addChartListener();
|
||||
}
|
||||
},
|
||||
|
||||
getGestures: function () {
|
||||
var gestures = {};
|
||||
gestures[this.getGesture()] = this.onGesture;
|
||||
return gestures;
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* Placeholder method.
|
||||
*/
|
||||
onGesture: Ext.emptyFn,
|
||||
|
||||
/**
|
||||
* @protected Find and return a single series item corresponding to the given event,
|
||||
* or null if no matching item is found.
|
||||
* @param {Event} e
|
||||
* @return {Object} the item object or null if none found.
|
||||
*/
|
||||
getItemForEvent: function (e) {
|
||||
var me = this,
|
||||
chart = me.getChart(),
|
||||
chartXY = chart.getEventXY(e);
|
||||
return chart.getItemForPoint(chartXY[0], chartXY[1]);
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected Find and return all series items corresponding to the given event.
|
||||
* @param {Event} e
|
||||
* @return {Array} array of matching item objects
|
||||
*/
|
||||
getItemsForEvent: function (e) {
|
||||
var me = this,
|
||||
chart = me.getChart(),
|
||||
chartXY = chart.getEventXY(e);
|
||||
return chart.getItemsForPoint(chartXY[0], chartXY[1]);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
addChartListener: function () {
|
||||
var me = this,
|
||||
chart = me.getChart(),
|
||||
gestures = me.getGestures(),
|
||||
gesture, fn;
|
||||
me.listeners = me.listeners || {};
|
||||
|
||||
function insertGesture(name, fn) {
|
||||
chart.on(
|
||||
name,
|
||||
// wrap the handler so it does not fire if the event is locked by another interaction
|
||||
me.listeners[name] = function (e) {
|
||||
var locks = me.getLocks();
|
||||
if (!(name in locks) || locks[name] === me) {
|
||||
if (e && e.stopPropagation) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
return (Ext.isFunction(fn) ? fn : me[fn]).apply(this, arguments);
|
||||
}
|
||||
},
|
||||
me
|
||||
);
|
||||
}
|
||||
|
||||
for (gesture in gestures) {
|
||||
insertGesture(gesture, gestures[gesture]);
|
||||
}
|
||||
},
|
||||
|
||||
removeChartListener: function (chart) {
|
||||
var me = this,
|
||||
gestures = me.getGestures(),
|
||||
gesture, fn;
|
||||
|
||||
function removeGesture(name) {
|
||||
chart.un(name, me.listeners[name]);
|
||||
delete me.listeners[name];
|
||||
}
|
||||
|
||||
for (gesture in gestures) {
|
||||
removeGesture(gesture);
|
||||
}
|
||||
},
|
||||
|
||||
lockEvents: function () {
|
||||
var me = this,
|
||||
locks = me.getLocks(),
|
||||
args = Array.prototype.slice.call(arguments),
|
||||
i = args.length;
|
||||
while (i--) {
|
||||
locks[args[i]] = me;
|
||||
}
|
||||
},
|
||||
|
||||
unlockEvents: function () {
|
||||
var locks = this.getLocks(),
|
||||
args = Array.prototype.slice.call(arguments),
|
||||
i = args.length;
|
||||
while (i--) {
|
||||
delete locks[args[i]];
|
||||
}
|
||||
},
|
||||
|
||||
getLocks: function () {
|
||||
var chart = this.getChart();
|
||||
return chart.lockedEvents || (chart.lockedEvents = {});
|
||||
},
|
||||
|
||||
isMultiTouch: function () {
|
||||
return !(Ext.os.is.MultiTouch === false || (Ext.os.is.Android3 || Ext.os.is.Android2) || Ext.os.is.Desktop);
|
||||
},
|
||||
|
||||
initializeDefaults: Ext.emptyFn,
|
||||
|
||||
doSync: function () {
|
||||
var chart = this.getChart();
|
||||
if (this.syncTimer) {
|
||||
clearTimeout(this.syncTimer);
|
||||
this.syncTimer = null;
|
||||
}
|
||||
if (this.stopAnimationBeforeSync) {
|
||||
chart.resizing = true;
|
||||
}
|
||||
chart.redraw();
|
||||
if (this.stopAnimationBeforeSync) {
|
||||
chart.resizing = false;
|
||||
}
|
||||
this.syncThrottle = +new Date() + this.throttleGap;
|
||||
},
|
||||
|
||||
sync: function () {
|
||||
var me = this;
|
||||
if (me.throttleGap && Ext.frameStartTime < me.syncThrottle) {
|
||||
if (me.syncTimer) {
|
||||
return;
|
||||
}
|
||||
me.syncTimer = setTimeout(function () {
|
||||
me.doSync();
|
||||
}, me.throttleGap);
|
||||
} else {
|
||||
me.doSync();
|
||||
}
|
||||
},
|
||||
|
||||
getItemId: function () {
|
||||
return this.getId();
|
||||
},
|
||||
|
||||
isXType: function (xtype) {
|
||||
return xtype === 'interaction';
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
Ext.ComponentManager.unregister(this);
|
||||
this.listeners = [];
|
||||
this.callSuper();
|
||||
}
|
||||
}, function () {
|
||||
if (Ext.os.is.Android2) {
|
||||
this.prototype.throttleGap = 20;
|
||||
} else if (Ext.os.is.Android4) {
|
||||
this.prototype.throttleGap = 40;
|
||||
}
|
||||
});
|
||||
372
OfficeWeb/3rdparty/touch/src/chart/interactions/CrossZoom.js
vendored
Normal file
372
OfficeWeb/3rdparty/touch/src/chart/interactions/CrossZoom.js
vendored
Normal file
@@ -0,0 +1,372 @@
|
||||
/**
|
||||
* @class Ext.chart.interactions.CrossZoom
|
||||
* @extends Ext.chart.interactions.Abstract
|
||||
*
|
||||
* The CrossZoom interaction allows the user to zoom in on a selected area of the chart.
|
||||
*
|
||||
* @example preview
|
||||
* var lineChart = new Ext.chart.CartesianChart({
|
||||
* interactions: [{
|
||||
* type: 'crosszoom'
|
||||
* }],
|
||||
* animate: true,
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* axes: [{
|
||||
* type: 'numeric',
|
||||
* position: 'left',
|
||||
* fields: ['data1'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* grid: true,
|
||||
* minimum: 0
|
||||
* }, {
|
||||
* type: 'category',
|
||||
* position: 'bottom',
|
||||
* fields: ['name'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* }
|
||||
* }],
|
||||
* series: [{
|
||||
* type: 'line',
|
||||
* highlight: {
|
||||
* size: 7,
|
||||
* radius: 7
|
||||
* },
|
||||
* style: {
|
||||
* stroke: 'rgb(143,203,203)'
|
||||
* },
|
||||
* xField: 'name',
|
||||
* yField: 'data1',
|
||||
* marker: {
|
||||
* type: 'path',
|
||||
* path: ['M', -2, 0, 0, 2, 2, 0, 0, -2, 'Z'],
|
||||
* stroke: 'blue',
|
||||
* lineWidth: 0
|
||||
* }
|
||||
* }, {
|
||||
* type: 'line',
|
||||
* highlight: {
|
||||
* size: 7,
|
||||
* radius: 7
|
||||
* },
|
||||
* fill: true,
|
||||
* xField: 'name',
|
||||
* yField: 'data3',
|
||||
* marker: {
|
||||
* type: 'circle',
|
||||
* radius: 4,
|
||||
* lineWidth: 0
|
||||
* }
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(lineChart);
|
||||
*/
|
||||
Ext.define('Ext.chart.interactions.CrossZoom', {
|
||||
|
||||
extend: 'Ext.chart.interactions.Abstract',
|
||||
|
||||
type: 'crosszoom',
|
||||
alias: 'interaction.crosszoom',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Object/Array} axes
|
||||
* Specifies which axes should be made navigable. The config value can take the following formats:
|
||||
*
|
||||
* - An Object whose keys correspond to the {@link Ext.chart.axis.Axis#position position} of each
|
||||
* axis that should be made navigable. Each key's value can either be an Object with further
|
||||
* configuration options for each axis or simply `true` for a default set of options.
|
||||
* {
|
||||
* type: 'crosszoom',
|
||||
* axes: {
|
||||
* left: {
|
||||
* maxZoom: 5,
|
||||
* allowPan: false
|
||||
* },
|
||||
* bottom: true
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* If using the full Object form, the following options can be specified for each axis:
|
||||
*
|
||||
* - minZoom (Number) A minimum zoom level for the axis. Defaults to `1` which is its natural size.
|
||||
* - maxZoom (Number) A maximum zoom level for the axis. Defaults to `10`.
|
||||
* - startZoom (Number) A starting zoom level for the axis. Defaults to `1`.
|
||||
* - allowZoom (Boolean) Whether zooming is allowed for the axis. Defaults to `true`.
|
||||
* - allowPan (Boolean) Whether panning is allowed for the axis. Defaults to `true`.
|
||||
* - startPan (Boolean) A starting panning offset for the axis. Defaults to `0`.
|
||||
*
|
||||
* - An Array of strings, each one corresponding to the {@link Ext.chart.axis.Axis#position position}
|
||||
* of an axis that should be made navigable. The default options will be used for each named axis.
|
||||
*
|
||||
* {
|
||||
* type: 'crosszoom',
|
||||
* axes: ['left', 'bottom']
|
||||
* }
|
||||
*
|
||||
* If the `axes` config is not specified, it will default to making all axes navigable with the
|
||||
* default axis options.
|
||||
*/
|
||||
axes: true,
|
||||
|
||||
gesture: 'drag',
|
||||
|
||||
undoButton: {}
|
||||
},
|
||||
|
||||
stopAnimationBeforeSync: false,
|
||||
|
||||
constructor: function () {
|
||||
this.callSuper(arguments);
|
||||
this.zoomHistory = [];
|
||||
},
|
||||
|
||||
applyAxes: function (axesConfig) {
|
||||
var result = {};
|
||||
if (axesConfig === true) {
|
||||
return {
|
||||
top: {},
|
||||
right: {},
|
||||
bottom: {},
|
||||
left: {}
|
||||
};
|
||||
} else if (Ext.isArray(axesConfig)) {
|
||||
// array of axis names - translate to full object form
|
||||
result = {};
|
||||
Ext.each(axesConfig, function (axis) {
|
||||
result[axis] = {};
|
||||
});
|
||||
} else if (Ext.isObject(axesConfig)) {
|
||||
Ext.iterate(axesConfig, function (key, val) {
|
||||
// axis name with `true` value -> translate to object
|
||||
if (val === true) {
|
||||
result[key] = {};
|
||||
} else if (val !== false) {
|
||||
result[key] = val;
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
applyUndoButton: function (button, oldButton) {
|
||||
var me = this;
|
||||
if (button) {
|
||||
if (oldButton) {
|
||||
oldButton.destroy();
|
||||
}
|
||||
return Ext.create('Ext.Button', Ext.apply({
|
||||
cls: [],
|
||||
iconCls: 'refresh',
|
||||
text: 'Undo Zoom',
|
||||
iconMask: true,
|
||||
disabled: true,
|
||||
handler: function () {
|
||||
me.undoZoom();
|
||||
}
|
||||
}, button));
|
||||
} else if (oldButton) {
|
||||
oldButton.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
getGestures: function () {
|
||||
var me = this,
|
||||
gestures = {};
|
||||
gestures[me.getGesture()] = 'onGesture';
|
||||
gestures[me.getGesture() + 'start'] = 'onGestureStart';
|
||||
gestures[me.getGesture() + 'end'] = 'onGestureEnd';
|
||||
gestures.doubletap = 'onDoubleTap';
|
||||
return gestures;
|
||||
},
|
||||
|
||||
getSurface: function () {
|
||||
return this.getChart() && this.getChart().getSurface("overlay");
|
||||
},
|
||||
|
||||
onGestureStart: function (e) {
|
||||
var me = this,
|
||||
chart = me.getChart(),
|
||||
region = chart.getInnerRegion(),
|
||||
xy = chart.element.getXY(),
|
||||
x = e.pageX - xy[0],
|
||||
y = e.pageY - xy[1],
|
||||
surface = this.getSurface();
|
||||
if (region[0] < x && x < region[0] + region[2] && region[1] < y && y < region[1] + region[3]) {
|
||||
me.lockEvents(me.getGesture());
|
||||
me.startX = x;
|
||||
me.startY = y;
|
||||
me.selectionRect = surface.add({
|
||||
type: 'rect',
|
||||
globalAlpha: 0.3,
|
||||
fillStyle: 'rgba(80,80,140,0.3)',
|
||||
strokeStyle: 'rgba(80,80,140,1)',
|
||||
lineWidth: 2,
|
||||
x: x,
|
||||
y: y,
|
||||
width: 0,
|
||||
height: 0,
|
||||
zIndex: 1000
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onGesture: function (e) {
|
||||
var me = this;
|
||||
if (me.getLocks()[me.getGesture()] === me) {
|
||||
var chart = me.getChart(),
|
||||
surface = me.getSurface(),
|
||||
region = chart.getInnerRegion(),
|
||||
xy = chart.element.getXY(),
|
||||
x = e.pageX - xy[0],
|
||||
y = e.pageY - xy[1];
|
||||
if (x < region[0]) {
|
||||
x = region[0];
|
||||
} else if (x > region[0] + region[2]) {
|
||||
x = region[0] + region[2];
|
||||
}
|
||||
|
||||
if (y < region[1]) {
|
||||
y = region[1];
|
||||
} else if (y > region[1] + region[3]) {
|
||||
y = region[1] + region[3];
|
||||
}
|
||||
me.selectionRect.setAttributes({
|
||||
width: x - me.startX,
|
||||
height: y - me.startY
|
||||
});
|
||||
if (Math.abs(me.startX - x) < 11 || Math.abs(me.startY - y) < 11) {
|
||||
me.selectionRect.setAttributes({globalAlpha: 0.3});
|
||||
} else {
|
||||
me.selectionRect.setAttributes({globalAlpha: 1});
|
||||
}
|
||||
surface.renderFrame();
|
||||
}
|
||||
},
|
||||
|
||||
onGestureEnd: function (e) {
|
||||
var me = this;
|
||||
if (me.getLocks()[me.getGesture()] === me) {
|
||||
var chart = me.getChart(),
|
||||
surface = me.getSurface(),
|
||||
region = chart.getInnerRegion(),
|
||||
selectionRect = me.selectionRect,
|
||||
xy = chart.element.getXY(),
|
||||
x = e.pageX - xy[0],
|
||||
y = e.pageY - xy[1];
|
||||
if (x < region[0]) {
|
||||
x = region[0];
|
||||
} else if (x > region[0] + region[2]) {
|
||||
x = region[0] + region[2];
|
||||
}
|
||||
|
||||
if (y < region[1]) {
|
||||
y = region[1];
|
||||
} else if (y > region[1] + region[3]) {
|
||||
y = region[1] + region[3];
|
||||
}
|
||||
|
||||
if (Math.abs(me.startX - x) < 11 || Math.abs(me.startY - y) < 11) {
|
||||
surface.remove(me.selectionRect);
|
||||
} else {
|
||||
me.zoomBy([
|
||||
(Math.min(me.startX, x) - region[0]) / region[2],
|
||||
1 - (Math.max(me.startY, y) - region[1]) / region[3],
|
||||
(Math.max(me.startX, x) - region[0]) / region[2],
|
||||
1 - (Math.min(me.startY, y) - region[1]) / region[3]
|
||||
]);
|
||||
|
||||
selectionRect.setAttributes({
|
||||
x: Math.min(me.startX, x),
|
||||
y: Math.min(me.startY, y),
|
||||
width: Math.abs(me.startX - x),
|
||||
height: Math.abs(me.startY - y)
|
||||
});
|
||||
|
||||
selectionRect.fx.setConfig(chart.getAnimate() || {duration: 0});
|
||||
selectionRect.setAttributes({
|
||||
globalAlpha: 0,
|
||||
x: region[0],
|
||||
y: region[1],
|
||||
width: region[2],
|
||||
height: region[3]
|
||||
});
|
||||
chart.suspendThicknessChanged();
|
||||
selectionRect.fx.on('animationend', function () {
|
||||
chart.resumeThicknessChanged();
|
||||
surface.remove(me.selectionRect);
|
||||
});
|
||||
}
|
||||
|
||||
this.selectionRect = null;
|
||||
surface.renderFrame();
|
||||
me.sync();
|
||||
me.unlockEvents(me.getGesture());
|
||||
}
|
||||
},
|
||||
|
||||
zoomBy: function (region) {
|
||||
var me = this,
|
||||
axisConfigs = me.getAxes(),
|
||||
axes = me.getChart().getAxes(),
|
||||
config,
|
||||
zoomMap = {};
|
||||
|
||||
for (var i = 0; i < axes.length; i++) {
|
||||
var axis = axes[i];
|
||||
config = axisConfigs[axis.getPosition()];
|
||||
if (config && config.allowZoom !== false) {
|
||||
var isSide = axis.isSide(),
|
||||
oldRange = axis.getVisibleRange();
|
||||
zoomMap[axis.getId()] = oldRange.slice(0);
|
||||
if (!isSide) {
|
||||
axis.setVisibleRange([
|
||||
(oldRange[1] - oldRange[0]) * region[0] + oldRange[0],
|
||||
(oldRange[1] - oldRange[0]) * region[2] + oldRange[0]
|
||||
]);
|
||||
} else {
|
||||
axis.setVisibleRange([
|
||||
(oldRange[1] - oldRange[0]) * region[1] + oldRange[0],
|
||||
(oldRange[1] - oldRange[0]) * region[3] + oldRange[0]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
me.zoomHistory.push(zoomMap);
|
||||
me.getUndoButton().setDisabled(false);
|
||||
},
|
||||
|
||||
undoZoom: function () {
|
||||
var zoomMap = this.zoomHistory.pop(),
|
||||
axes = this.getChart().getAxes();
|
||||
if (zoomMap) {
|
||||
for (var i = 0; i < axes.length; i++) {
|
||||
var axis = axes[i];
|
||||
if (zoomMap[axis.getId()]) {
|
||||
axis.setVisibleRange(zoomMap[axis.getId()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.getUndoButton().setDisabled(this.zoomHistory.length === 0);
|
||||
this.sync();
|
||||
},
|
||||
|
||||
onDoubleTap: function (e) {
|
||||
this.undoZoom();
|
||||
}
|
||||
});
|
||||
37
OfficeWeb/3rdparty/touch/src/chart/interactions/ItemHighlight.js
vendored
Normal file
37
OfficeWeb/3rdparty/touch/src/chart/interactions/ItemHighlight.js
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @class Ext.chart.interactions.ItemHighlight
|
||||
* @extends Ext.chart.interactions.Abstract
|
||||
*
|
||||
* The ItemHighlight interaction allows the user to highlight series items in the chart.
|
||||
*/
|
||||
Ext.define('Ext.chart.interactions.ItemHighlight', {
|
||||
|
||||
extend: 'Ext.chart.interactions.Abstract',
|
||||
|
||||
type: 'itemhighlight',
|
||||
alias: 'interaction.itemhighlight',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} gesture
|
||||
* Defines the gesture type that should trigger item highlighting.
|
||||
*/
|
||||
gesture: 'tap'
|
||||
},
|
||||
|
||||
getGestures: function () {
|
||||
var gestures = {};
|
||||
gestures.itemtap = 'onGesture';
|
||||
gestures.tap = 'onFailedGesture';
|
||||
return gestures;
|
||||
},
|
||||
|
||||
onGesture: function (series, item, e) {
|
||||
e.highlightItem = item;
|
||||
},
|
||||
|
||||
onFailedGesture: function (e) {
|
||||
this.getChart().setHighlightItem(e.highlightItem || null);
|
||||
this.sync();
|
||||
}
|
||||
});
|
||||
106
OfficeWeb/3rdparty/touch/src/chart/interactions/ItemInfo.js
vendored
Normal file
106
OfficeWeb/3rdparty/touch/src/chart/interactions/ItemInfo.js
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* The ItemInfo interaction allows displaying detailed information about a series data
|
||||
* point in a popup panel.
|
||||
*
|
||||
* To attach this interaction to a chart, include an entry in the chart's
|
||||
* {@link Ext.chart.AbstractChart#interactions interactions} config with the `iteminfo` type:
|
||||
*
|
||||
* new Ext.chart.AbstractChart({
|
||||
* renderTo: Ext.getBody(),
|
||||
* width: 800,
|
||||
* height: 600,
|
||||
* store: store1,
|
||||
* axes: [ ...some axes options... ],
|
||||
* series: [ ...some series options... ],
|
||||
* interactions: [{
|
||||
* type: 'iteminfo',
|
||||
* listeners: {
|
||||
* show: function(me, item, panel) {
|
||||
* panel.setHtml('Stock Price: $' + item.record.get('price'));
|
||||
* }
|
||||
* }
|
||||
* }]
|
||||
* });
|
||||
*/
|
||||
Ext.define('Ext.chart.interactions.ItemInfo', {
|
||||
|
||||
extend: 'Ext.chart.interactions.Abstract',
|
||||
|
||||
type: 'iteminfo',
|
||||
alias: 'interaction.iteminfo',
|
||||
|
||||
/**
|
||||
* @event show
|
||||
* Fires when the info panel is shown.
|
||||
* @param {Ext.chart.interactions.ItemInfo} this The interaction instance
|
||||
* @param {Object} item The item whose info is being displayed
|
||||
* @param {Ext.Panel} panel The panel for displaying the info
|
||||
*/
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} gesture
|
||||
* Defines the gesture type that should trigger the item info panel to be displayed.
|
||||
*/
|
||||
gesture: 'itemtap',
|
||||
|
||||
/**
|
||||
* @cfg {Object} panel
|
||||
* An optional set of configuration overrides for the {@link Ext.Panel} that gets
|
||||
* displayed. This object will be merged with the default panel configuration.
|
||||
*/
|
||||
panel: {
|
||||
modal: true,
|
||||
centered: true,
|
||||
width: 250,
|
||||
height: 300,
|
||||
styleHtmlContent: true,
|
||||
scrollable: 'vertical',
|
||||
hideOnMaskTap: true,
|
||||
fullscreen: false,
|
||||
hidden: true,
|
||||
zIndex: 30,
|
||||
items: [
|
||||
{
|
||||
docked: 'top',
|
||||
xtype: 'toolbar',
|
||||
title: 'Item Detail'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
applyPanel: function (panel, oldPanel) {
|
||||
return Ext.factory(panel, 'Ext.Panel', oldPanel);
|
||||
},
|
||||
|
||||
updatePanel: function (panel, oldPanel) {
|
||||
if (panel) {
|
||||
panel.on('hide', "reset", this);
|
||||
}
|
||||
if (oldPanel) {
|
||||
oldPanel.un('hide', "reset", this);
|
||||
}
|
||||
},
|
||||
|
||||
onGesture: function (series, item) {
|
||||
var me = this,
|
||||
panel = me.getPanel();
|
||||
me.item = item;
|
||||
me.fireEvent('show', me, item, panel);
|
||||
Ext.Viewport.add(panel);
|
||||
panel.show('pop');
|
||||
series.setAttributesForItem(item, { highlighted: true });
|
||||
me.sync();
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
var me = this,
|
||||
item = me.item;
|
||||
if (item) {
|
||||
item.series.setAttributesForItem(item, { highlighted: false });
|
||||
delete me.item;
|
||||
me.sync();
|
||||
}
|
||||
}
|
||||
});
|
||||
476
OfficeWeb/3rdparty/touch/src/chart/interactions/PanZoom.js
vendored
Normal file
476
OfficeWeb/3rdparty/touch/src/chart/interactions/PanZoom.js
vendored
Normal file
@@ -0,0 +1,476 @@
|
||||
/**
|
||||
* The PanZoom interaction allows the user to navigate the data for one or more chart
|
||||
* axes by panning and/or zooming. Navigation can be limited to particular axes. Zooming is
|
||||
* performed by pinching on the chart or axis area; panning is performed by single-touch dragging.
|
||||
*
|
||||
* For devices which do not support multiple-touch events, zooming can not be done via pinch gestures; in this case the
|
||||
* interaction will allow the user to perform both zooming and panning using the same single-touch drag gesture.
|
||||
* {@link #modeToggleButton} provides a button to indicate and toggle between two modes.
|
||||
*
|
||||
* @example preview
|
||||
* var lineChart = new Ext.chart.CartesianChart({
|
||||
* interactions: [{
|
||||
* type: 'panzoom',
|
||||
* zoomOnPanGesture: true
|
||||
* }],
|
||||
* animate: true,
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* axes: [{
|
||||
* type: 'numeric',
|
||||
* position: 'left',
|
||||
* fields: ['data1'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* grid: true,
|
||||
* minimum: 0
|
||||
* }, {
|
||||
* type: 'category',
|
||||
* position: 'bottom',
|
||||
* fields: ['name'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* }
|
||||
* }],
|
||||
* series: [{
|
||||
* type: 'line',
|
||||
* highlight: {
|
||||
* size: 7,
|
||||
* radius: 7
|
||||
* },
|
||||
* style: {
|
||||
* stroke: 'rgb(143,203,203)'
|
||||
* },
|
||||
* xField: 'name',
|
||||
* yField: 'data1',
|
||||
* marker: {
|
||||
* type: 'path',
|
||||
* path: ['M', -2, 0, 0, 2, 2, 0, 0, -2, 'Z'],
|
||||
* stroke: 'blue',
|
||||
* lineWidth: 0
|
||||
* }
|
||||
* }, {
|
||||
* type: 'line',
|
||||
* highlight: {
|
||||
* size: 7,
|
||||
* radius: 7
|
||||
* },
|
||||
* fill: true,
|
||||
* xField: 'name',
|
||||
* yField: 'data3',
|
||||
* marker: {
|
||||
* type: 'circle',
|
||||
* radius: 4,
|
||||
* lineWidth: 0
|
||||
* }
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(lineChart);
|
||||
*
|
||||
* The configuration object for the `panzoom` interaction type should specify which axes
|
||||
* will be made navigable via the `axes` config. See the {@link #axes} config documentation
|
||||
* for details on the allowed formats. If the `axes` config is not specified, it will default
|
||||
* to making all axes navigable with the default axis options.
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.chart.interactions.PanZoom', {
|
||||
|
||||
extend: 'Ext.chart.interactions.Abstract',
|
||||
|
||||
type: 'panzoom',
|
||||
alias: 'interaction.panzoom',
|
||||
requires: [
|
||||
'Ext.util.Region',
|
||||
'Ext.draw.Animator'
|
||||
],
|
||||
|
||||
config: {
|
||||
|
||||
/**
|
||||
* @cfg {Object/Array} axes
|
||||
* Specifies which axes should be made navigable. The config value can take the following formats:
|
||||
*
|
||||
* - An Object whose keys correspond to the {@link Ext.chart.axis.Axis#position position} of each
|
||||
* axis that should be made navigable. Each key's value can either be an Object with further
|
||||
* configuration options for each axis or simply `true` for a default set of options.
|
||||
* {
|
||||
* type: 'panzoom',
|
||||
* axes: {
|
||||
* left: {
|
||||
* maxZoom: 5,
|
||||
* allowPan: false
|
||||
* },
|
||||
* bottom: true
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* If using the full Object form, the following options can be specified for each axis:
|
||||
*
|
||||
* - minZoom (Number) A minimum zoom level for the axis. Defaults to `1` which is its natural size.
|
||||
* - maxZoom (Number) A maximum zoom level for the axis. Defaults to `10`.
|
||||
* - startZoom (Number) A starting zoom level for the axis. Defaults to `1`.
|
||||
* - allowZoom (Boolean) Whether zooming is allowed for the axis. Defaults to `true`.
|
||||
* - allowPan (Boolean) Whether panning is allowed for the axis. Defaults to `true`.
|
||||
* - startPan (Boolean) A starting panning offset for the axis. Defaults to `0`.
|
||||
*
|
||||
* - An Array of strings, each one corresponding to the {@link Ext.chart.axis.Axis#position position}
|
||||
* of an axis that should be made navigable. The default options will be used for each named axis.
|
||||
*
|
||||
* {
|
||||
* type: 'panzoom',
|
||||
* axes: ['left', 'bottom']
|
||||
* }
|
||||
*
|
||||
* If the `axes` config is not specified, it will default to making all axes navigable with the
|
||||
* default axis options.
|
||||
*/
|
||||
axes: {
|
||||
top: {},
|
||||
right: {},
|
||||
bottom: {},
|
||||
left: {}
|
||||
},
|
||||
|
||||
minZoom: 1,
|
||||
|
||||
maxZoom: 10000,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} showOverflowArrows
|
||||
* If `true`, arrows will be conditionally shown at either end of each axis to indicate that the
|
||||
* axis is overflowing and can therefore be panned in that direction. Set this to `false` to
|
||||
* prevent the arrows from being displayed.
|
||||
*/
|
||||
showOverflowArrows: true,
|
||||
|
||||
/**
|
||||
* @cfg {Object} overflowArrowOptions
|
||||
* A set of optional overrides for the overflow arrow sprites' options. Only relevant when
|
||||
* {@link #showOverflowArrows} is `true`.
|
||||
*/
|
||||
|
||||
gesture: 'pinch',
|
||||
|
||||
panGesture: 'drag',
|
||||
|
||||
zoomOnPanGesture: false,
|
||||
|
||||
modeToggleButton: {
|
||||
cls: ['x-panzoom-toggle', 'x-zooming'],
|
||||
iconCls: 'x-panzoom-toggle-icon',
|
||||
iconMask: true
|
||||
},
|
||||
|
||||
hideLabelInGesture: false //Ext.os.is.Android
|
||||
},
|
||||
|
||||
stopAnimationBeforeSync: true,
|
||||
|
||||
applyAxes: function (axesConfig, oldAxesConfig) {
|
||||
return Ext.merge(oldAxesConfig || {}, axesConfig);
|
||||
},
|
||||
|
||||
applyZoomOnPanGesture: function (zoomOnPanGesture) {
|
||||
this.getChart();
|
||||
if (this.isMultiTouch()) {
|
||||
return false;
|
||||
}
|
||||
return zoomOnPanGesture;
|
||||
},
|
||||
|
||||
updateZoomOnPanGesture: function (zoomOnPanGesture) {
|
||||
if (!this.isMultiTouch()) {
|
||||
var button = this.getModeToggleButton(),
|
||||
zoomModeCls = Ext.baseCSSPrefix + 'zooming';
|
||||
if (zoomOnPanGesture) {
|
||||
button.addCls(zoomModeCls);
|
||||
if (!button.config.hideText) {
|
||||
button.setText(' Zoom');
|
||||
}
|
||||
} else {
|
||||
button.removeCls(zoomModeCls);
|
||||
if (!button.config.hideText) {
|
||||
button.setText(' Pan');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toggleMode: function () {
|
||||
var me = this;
|
||||
if (!me.isMultiTouch()) {
|
||||
me.setZoomOnPanGesture(!me.getZoomOnPanGesture());
|
||||
}
|
||||
},
|
||||
|
||||
applyModeToggleButton: function (button, oldButton) {
|
||||
var me = this,
|
||||
result = Ext.factory(button, "Ext.Button", oldButton);
|
||||
if (result && !oldButton) {
|
||||
result.setHandler(function () {
|
||||
me.toggleMode();
|
||||
});
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
getGestures: function () {
|
||||
var me = this,
|
||||
gestures = {};
|
||||
gestures[me.getGesture()] = 'onGesture';
|
||||
gestures[me.getGesture() + 'start'] = 'onGestureStart';
|
||||
gestures[me.getGesture() + 'end'] = 'onGestureEnd';
|
||||
gestures[me.getPanGesture()] = 'onPanGesture';
|
||||
gestures[me.getPanGesture() + 'start'] = 'onPanGestureStart';
|
||||
gestures[me.getPanGesture() + 'end'] = 'onPanGestureEnd';
|
||||
gestures.doubletap = 'onDoubleTap';
|
||||
return gestures;
|
||||
},
|
||||
|
||||
onDoubleTap: function (e) {
|
||||
|
||||
},
|
||||
|
||||
onPanGestureStart: function (e) {
|
||||
if (!e || !e.touches || e.touches.length < 2) { //Limit drags to single touch
|
||||
var me = this,
|
||||
region = me.getChart().getInnerRegion(),
|
||||
xy = me.getChart().element.getXY();
|
||||
me.startX = e.pageX - xy[0] - region[0];
|
||||
me.startY = e.pageY - xy[1] - region[1];
|
||||
me.oldVisibleRanges = null;
|
||||
me.hideLabels();
|
||||
me.getChart().suspendThicknessChanged();
|
||||
}
|
||||
},
|
||||
|
||||
onPanGesture: function (e) {
|
||||
if (!e.touches || e.touches.length < 2) { //Limit drags to single touch
|
||||
var me = this,
|
||||
region = me.getChart().getInnerRegion(),
|
||||
xy = me.getChart().element.getXY();
|
||||
if (me.getZoomOnPanGesture()) {
|
||||
me.transformAxesBy(me.getZoomableAxes(e), 0, 0, (e.pageX - xy[0] - region[0]) / me.startX, me.startY / (e.pageY - xy[1] - region[1]));
|
||||
} else {
|
||||
me.transformAxesBy(me.getPannableAxes(e), e.pageX - xy[0] - region[0] - me.startX, e.pageY - xy[1] - region[1] - me.startY, 1, 1);
|
||||
}
|
||||
me.sync();
|
||||
}
|
||||
},
|
||||
|
||||
onPanGestureEnd: function (e) {
|
||||
var me = this;
|
||||
me.getChart().resumeThicknessChanged();
|
||||
me.showLabels();
|
||||
me.sync();
|
||||
},
|
||||
|
||||
onGestureStart: function (e) {
|
||||
if (e.touches && e.touches.length === 2) {
|
||||
var me = this,
|
||||
xy = me.getChart().element.getXY(),
|
||||
region = me.getChart().getInnerRegion(),
|
||||
x = xy[0] + region[0],
|
||||
y = xy[1] + region[1],
|
||||
newPoints = [e.touches[0].point.x - x, e.touches[0].point.y - y, e.touches[1].point.x - x, e.touches[1].point.y - y],
|
||||
xDistance = Math.max(44, Math.abs(newPoints[2] - newPoints[0])),
|
||||
yDistance = Math.max(44, Math.abs(newPoints[3] - newPoints[1]));
|
||||
me.getChart().suspendThicknessChanged();
|
||||
me.lastZoomDistances = [xDistance, yDistance];
|
||||
me.lastPoints = newPoints;
|
||||
me.oldVisibleRanges = null;
|
||||
me.hideLabels();
|
||||
}
|
||||
},
|
||||
|
||||
onGesture: function (e) {
|
||||
if (e.touches && e.touches.length === 2) {
|
||||
var me = this,
|
||||
region = me.getChart().getInnerRegion(),
|
||||
xy = me.getChart().element.getXY(),
|
||||
x = xy[0] + region[0],
|
||||
y = xy[1] + region[1],
|
||||
abs = Math.abs,
|
||||
lastPoints = me.lastPoints,
|
||||
newPoints = [e.touches[0].point.x - x, e.touches[0].point.y - y, e.touches[1].point.x - x, e.touches[1].point.y - y],
|
||||
xDistance = Math.max(44, abs(newPoints[2] - newPoints[0])),
|
||||
yDistance = Math.max(44, abs(newPoints[3] - newPoints[1])),
|
||||
lastDistances = this.lastZoomDistances || [xDistance, yDistance],
|
||||
zoomX = xDistance / lastDistances[0],
|
||||
zoomY = yDistance / lastDistances[1];
|
||||
|
||||
me.transformAxesBy(me.getZoomableAxes(e),
|
||||
region[2] * (zoomX - 1) / 2 + newPoints[2] - lastPoints[2] * zoomX,
|
||||
region[3] * (zoomY - 1) / 2 + newPoints[3] - lastPoints[3] * zoomY,
|
||||
zoomX,
|
||||
zoomY);
|
||||
me.sync();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
onGestureEnd: function (e) {
|
||||
var me = this;
|
||||
me.showLabels();
|
||||
me.sync();
|
||||
},
|
||||
|
||||
hideLabels: function () {
|
||||
if (this.getHideLabelInGesture()) {
|
||||
this.eachInteractiveAxes(function (axis) {
|
||||
axis.hideLabels();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
showLabels: function () {
|
||||
if (this.getHideLabelInGesture()) {
|
||||
this.eachInteractiveAxes(function (axis) {
|
||||
axis.showLabels();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
isEventOnAxis: function (e, axis) {
|
||||
// TODO: right now this uses the current event position but really we want to only
|
||||
// use the gesture's start event. Pinch does not give that to us though.
|
||||
var region = axis.getSurface().getRegion();
|
||||
return region[0] <= e.pageX && e.pageX <= region[0] + region[2] && region[1] <= e.pageY && e.pageY <= region[1] + region[3];
|
||||
},
|
||||
|
||||
getPannableAxes: function (e) {
|
||||
var me = this,
|
||||
axisConfigs = me.getAxes(),
|
||||
axes = me.getChart().getAxes(),
|
||||
i, ln = axes.length,
|
||||
result = [], isEventOnAxis = false,
|
||||
config;
|
||||
|
||||
if (e) {
|
||||
for (i = 0; i < ln; i++) {
|
||||
if (this.isEventOnAxis(e, axes[i])) {
|
||||
isEventOnAxis = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ln; i++) {
|
||||
config = axisConfigs[axes[i].getPosition()];
|
||||
if (config && config.allowPan !== false && (!isEventOnAxis || this.isEventOnAxis(e, axes[i]))) {
|
||||
result.push(axes[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
getZoomableAxes: function (e) {
|
||||
var me = this,
|
||||
axisConfigs = me.getAxes(),
|
||||
axes = me.getChart().getAxes(),
|
||||
result = [],
|
||||
i, ln = axes.length, axis,
|
||||
isEventOnAxis = false, config;
|
||||
|
||||
if (e) {
|
||||
for (i = 0; i < ln; i++) {
|
||||
if (this.isEventOnAxis(e, axes[i])) {
|
||||
isEventOnAxis = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ln; i++) {
|
||||
axis = axes[i];
|
||||
config = axisConfigs[axis.getPosition()];
|
||||
if (config && config.allowZoom !== false && (!isEventOnAxis || this.isEventOnAxis(e, axis))) {
|
||||
result.push(axis);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
eachInteractiveAxes: function (fn) {
|
||||
var me = this,
|
||||
axisConfigs = me.getAxes(),
|
||||
axes = me.getChart().getAxes();
|
||||
for (var i = 0; i < axes.length; i++) {
|
||||
if (axisConfigs[axes[i].getPosition()]) {
|
||||
if (false === fn.call(this, axes[i])) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
transformAxesBy: function (axes, panX, panY, sx, sy) {
|
||||
var region = this.getChart().getInnerRegion(),
|
||||
axesCfg = this.getAxes(), axisCfg,
|
||||
oldVisibleRanges = this.oldVisibleRanges;
|
||||
|
||||
if (!oldVisibleRanges) {
|
||||
this.oldVisibleRanges = oldVisibleRanges = {};
|
||||
this.eachInteractiveAxes(function (axis) {
|
||||
oldVisibleRanges[axis.getId()] = axis.getVisibleRange();
|
||||
});
|
||||
}
|
||||
|
||||
if (!region) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < axes.length; i++) {
|
||||
axisCfg = axesCfg[axes[i].getPosition()];
|
||||
this.transformAxisBy(axes[i], oldVisibleRanges[axes[i].getId()], panX, panY, sx, sy, axisCfg.minZoom, axisCfg.maxZoom);
|
||||
}
|
||||
},
|
||||
|
||||
transformAxisBy: function (axis, oldVisibleRange, panX, panY, sx, sy, minZoom, maxZoom) {
|
||||
var me = this,
|
||||
visibleLength = oldVisibleRange[1] - oldVisibleRange[0],
|
||||
actualMinZoom = axis.config.minZoom || minZoom || me.getMinZoom(),
|
||||
actualMaxZoom = axis.config.maxZoom || maxZoom || me.getMaxZoom(),
|
||||
region = me.getChart().getInnerRegion();
|
||||
if (!region) {
|
||||
return;
|
||||
}
|
||||
|
||||
var isSide = axis.isSide(),
|
||||
length = isSide ? region[3] : region[2],
|
||||
pan = isSide ? -panY : panX;
|
||||
visibleLength /= isSide ? sy : sx;
|
||||
if (visibleLength < 0) {
|
||||
visibleLength = -visibleLength;
|
||||
}
|
||||
|
||||
if (visibleLength * actualMinZoom > 1) {
|
||||
visibleLength = 1;
|
||||
}
|
||||
|
||||
if (visibleLength * actualMaxZoom < 1) {
|
||||
visibleLength = 1 / actualMaxZoom;
|
||||
}
|
||||
|
||||
axis.setVisibleRange([
|
||||
(oldVisibleRange[0] + oldVisibleRange[1] - visibleLength) * 0.5 - pan / length * visibleLength,
|
||||
(oldVisibleRange[0] + oldVisibleRange[1] + visibleLength) * 0.5 - pan / length * visibleLength
|
||||
]);
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
this.setModeToggleButton(null);
|
||||
this.callSuper();
|
||||
}
|
||||
});
|
||||
101
OfficeWeb/3rdparty/touch/src/chart/interactions/Rotate.js
vendored
Normal file
101
OfficeWeb/3rdparty/touch/src/chart/interactions/Rotate.js
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @class Ext.chart.interactions.Rotate
|
||||
* @extends Ext.chart.interactions.Abstract
|
||||
*
|
||||
* The Rotate interaction allows the user to rotate a polar chart about its central point.
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.PolarChart({
|
||||
* animate: true,
|
||||
* interactions: ['rotate'],
|
||||
* colors: ["#115fa6", "#94ae0a", "#a61120", "#ff8809", "#ffd13e"],
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* series: [{
|
||||
* type: 'pie',
|
||||
* labelField: 'name',
|
||||
* xField: 'data3',
|
||||
* donut: 30
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*/
|
||||
Ext.define('Ext.chart.interactions.Rotate', {
|
||||
|
||||
extend: 'Ext.chart.interactions.Abstract',
|
||||
|
||||
type: 'rotate',
|
||||
|
||||
alias: 'interaction.rotate',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} gesture
|
||||
* Defines the gesture type that will be used to rotate the chart. Currently only
|
||||
* supports `pinch` for two-finger rotation and `drag` for single-finger rotation.
|
||||
*/
|
||||
gesture: 'rotate'
|
||||
},
|
||||
|
||||
oldRotations: null,
|
||||
|
||||
getGestures: function () {
|
||||
var gestures = {};
|
||||
gestures.rotate = 'onRotate';
|
||||
gestures.rotateend = 'onRotate';
|
||||
gestures.dragstart = 'onGestureStart';
|
||||
gestures.drag = 'onGesture';
|
||||
gestures.dragend = 'onGesture';
|
||||
return gestures;
|
||||
},
|
||||
|
||||
getAngle: function (e) {
|
||||
var me = this,
|
||||
chart = me.getChart(),
|
||||
xy = chart.getEventXY(e),
|
||||
center = chart.getCenter();
|
||||
return Math.atan2(xy[1] - center[1],
|
||||
xy[0] - center[0]);
|
||||
},
|
||||
|
||||
onGestureStart: function (e) {
|
||||
this.angle = this.getAngle(e);
|
||||
this.oldRotations = {};
|
||||
},
|
||||
|
||||
onGesture: function (e) {
|
||||
var me = this,
|
||||
chart = me.getChart(),
|
||||
angle = this.getAngle(e) - this.angle,
|
||||
axes = chart.getAxes(), axis,
|
||||
series = chart.getSeries(), seriesItem,
|
||||
center = chart.getCenter(),
|
||||
oldRotations = this.oldRotations,
|
||||
oldRotation, i, ln;
|
||||
for (i = 0, ln = axes.length; i < ln; i++) {
|
||||
axis = axes[i];
|
||||
oldRotation = oldRotations[axis.getId()] || (oldRotations[axis.getId()] = axis.getRotation());
|
||||
axis.setRotation(angle + oldRotation);
|
||||
}
|
||||
|
||||
for (i = 0, ln = series.length; i < ln; i++) {
|
||||
seriesItem = series[i];
|
||||
oldRotation = oldRotations[seriesItem.getId()] || (oldRotations[seriesItem.getId()] = seriesItem.getRotation());
|
||||
seriesItem.setRotation(angle + oldRotation);
|
||||
}
|
||||
me.sync();
|
||||
},
|
||||
|
||||
onRotate: function (e) {
|
||||
|
||||
}
|
||||
});
|
||||
22
OfficeWeb/3rdparty/touch/src/chart/interactions/RotatePie3D.js
vendored
Normal file
22
OfficeWeb/3rdparty/touch/src/chart/interactions/RotatePie3D.js
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @class Ext.chart.interactions.RotatePie3D
|
||||
* @extends Ext.chart.interactions.Rotate
|
||||
*
|
||||
* A special version of the Rotate interaction used by Pie3D Chart.
|
||||
*/
|
||||
Ext.define('Ext.chart.interactions.RotatePie3D', {
|
||||
|
||||
extend: 'Ext.chart.interactions.Rotate',
|
||||
|
||||
type: 'rotatePie3d',
|
||||
|
||||
alias: 'interaction.rotatePie3d',
|
||||
|
||||
getAngle: function (e) {
|
||||
var me = this,
|
||||
chart = me.getChart(),
|
||||
xy = chart.element.getXY(),
|
||||
region = chart.getMainRegion();
|
||||
return Math.atan2(e.pageY - xy[1] - region[3] * 0.5, e.pageX - xy[0] - region[2] * 0.5);
|
||||
}
|
||||
});
|
||||
107
OfficeWeb/3rdparty/touch/src/chart/label/Callout.js
vendored
Normal file
107
OfficeWeb/3rdparty/touch/src/chart/label/Callout.js
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @class Ext.chart.label.Callout
|
||||
* @extends Ext.draw.modifier.Modifier
|
||||
*
|
||||
* This is a modifier to place labels and callouts by additional attributes.
|
||||
*/
|
||||
Ext.define("Ext.chart.label.Callout", {
|
||||
extend: 'Ext.draw.modifier.Modifier',
|
||||
|
||||
prepareAttributes: function (attr) {
|
||||
if (!attr.hasOwnProperty('calloutOriginal')) {
|
||||
attr.calloutOriginal = Ext.Object.chain(attr);
|
||||
}
|
||||
if (this._previous) {
|
||||
this._previous.prepareAttributes(attr.calloutOriginal);
|
||||
}
|
||||
},
|
||||
|
||||
setAttrs: function (attr, changes) {
|
||||
var callout = attr.callout,
|
||||
origin = attr.calloutOriginal,
|
||||
bbox = attr.bbox.plain,
|
||||
width = (bbox.width || 0) + attr.labelOverflowPadding,
|
||||
height = (bbox.height || 0) + attr.labelOverflowPadding,
|
||||
dx, dy, r;
|
||||
|
||||
if ('callout' in changes) {
|
||||
callout = changes.callout;
|
||||
}
|
||||
|
||||
if ('callout' in changes || 'calloutPlaceX' in changes || 'calloutPlaceY' in changes || 'x' in changes || 'y' in changes) {
|
||||
var rotationRads = 'rotationRads' in changes ? origin.rotationRads = changes.rotationRads : origin.rotationRads,
|
||||
x = 'x' in changes ? (origin.x = changes.x) : origin.x,
|
||||
y = 'y' in changes ? (origin.y = changes.y) : origin.y,
|
||||
calloutPlaceX = 'calloutPlaceX' in changes ? changes.calloutPlaceX : attr.calloutPlaceX,
|
||||
calloutPlaceY = 'calloutPlaceY' in changes ? changes.calloutPlaceY : attr.calloutPlaceY,
|
||||
calloutVertical = 'calloutVertical' in changes ? changes.calloutVertical : attr.calloutVertical,
|
||||
temp;
|
||||
|
||||
// Normalize Rotations
|
||||
rotationRads %= Math.PI * 2;
|
||||
if (Math.cos(rotationRads) < 0) {
|
||||
rotationRads = (rotationRads + Math.PI) % (Math.PI * 2);
|
||||
}
|
||||
|
||||
if (rotationRads > Math.PI) {
|
||||
rotationRads -= Math.PI * 2;
|
||||
}
|
||||
|
||||
if (calloutVertical) {
|
||||
rotationRads = rotationRads * (1 - callout) + Math.PI / 2 * callout;
|
||||
temp = width;
|
||||
width = height;
|
||||
height = temp;
|
||||
} else {
|
||||
rotationRads = rotationRads * (1 - callout);
|
||||
}
|
||||
changes.rotationRads = rotationRads;
|
||||
|
||||
|
||||
// Placing label.
|
||||
changes.x = x * (1 - callout) + calloutPlaceX * callout;
|
||||
changes.y = y * (1 - callout) + calloutPlaceY * callout;
|
||||
|
||||
|
||||
// Placing the end of the callout line.
|
||||
dx = calloutPlaceX - x;
|
||||
dy = calloutPlaceY - y;
|
||||
if (Math.abs(dy * width) > Math.abs(height * dx)) {
|
||||
// on top/bottom
|
||||
if (dy > 0) {
|
||||
changes.calloutEndX = changes.x - (height / (dy * 2) * dx) * callout;
|
||||
changes.calloutEndY = changes.y - height / 2 * callout;
|
||||
} else {
|
||||
changes.calloutEndX = changes.x + (height / (dy * 2) * dx) * callout;
|
||||
changes.calloutEndY = changes.y + height / 2 * callout;
|
||||
}
|
||||
} else {
|
||||
// on left/right
|
||||
if (dx > 0) {
|
||||
changes.calloutEndX = changes.x - width / 2;
|
||||
changes.calloutEndY = changes.y - (width / (dx * 2) * dy) * callout;
|
||||
} else {
|
||||
changes.calloutEndX = changes.x + width / 2;
|
||||
changes.calloutEndY = changes.y + (width / (dx * 2) * dy) * callout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changes;
|
||||
},
|
||||
|
||||
pushDown: function (attr, changes) {
|
||||
changes = Ext.draw.modifier.Modifier.prototype.pushDown.call(this, attr.calloutOriginal, changes);
|
||||
return this.setAttrs(attr, changes);
|
||||
},
|
||||
|
||||
popUp: function (attr, changes) {
|
||||
attr = attr.__proto__;
|
||||
changes = this.setAttrs(attr, changes);
|
||||
if (this._next) {
|
||||
return this._next.popUp(attr, changes);
|
||||
} else {
|
||||
return Ext.apply(attr, changes);
|
||||
}
|
||||
}
|
||||
});
|
||||
91
OfficeWeb/3rdparty/touch/src/chart/label/Label.js
vendored
Normal file
91
OfficeWeb/3rdparty/touch/src/chart/label/Label.js
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* @class Ext.chart.label.Label
|
||||
* @extends Ext.draw.sprite.Text
|
||||
*
|
||||
* Sprite used to represent labels in series.
|
||||
*/
|
||||
Ext.define("Ext.chart.label.Label", {
|
||||
extend: "Ext.draw.sprite.Text",
|
||||
requires: ['Ext.chart.label.Callout'],
|
||||
|
||||
inheritableStatics: {
|
||||
def: {
|
||||
processors: {
|
||||
callout: 'limited01',
|
||||
calloutPlaceX: 'number',
|
||||
calloutPlaceY: 'number',
|
||||
calloutStartX: 'number',
|
||||
calloutStartY: 'number',
|
||||
calloutEndX: 'number',
|
||||
calloutEndY: 'number',
|
||||
calloutColor: 'color',
|
||||
calloutVertical: 'bool',
|
||||
labelOverflowPadding: 'number'
|
||||
},
|
||||
defaults: {
|
||||
callout: 0,
|
||||
calloutPlaceX: 0,
|
||||
calloutPlaceY: 0,
|
||||
calloutStartX: 0,
|
||||
calloutStartY: 0,
|
||||
calloutEndX: 0,
|
||||
calloutEndY: 0,
|
||||
calloutVertical: false,
|
||||
calloutColor: 'black',
|
||||
labelOverflowPadding: 5
|
||||
},
|
||||
|
||||
dirtyTriggers: {
|
||||
callout: 'transform',
|
||||
calloutPlaceX: 'transform',
|
||||
calloutPlaceY: 'transform',
|
||||
labelOverflowPadding: 'transform',
|
||||
calloutRotation: 'transform'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Object} fx Animation configuration.
|
||||
*/
|
||||
fx: {
|
||||
customDuration: {
|
||||
callout: 200
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
prepareModifiers: function () {
|
||||
this.callSuper(arguments);
|
||||
this.calloutModifier = new Ext.chart.label.Callout({sprite: this});
|
||||
this.fx.setNext(this.calloutModifier);
|
||||
this.calloutModifier.setNext(this.topModifier);
|
||||
},
|
||||
|
||||
render: function (surface, ctx, clipRegion) {
|
||||
var me = this,
|
||||
attr = me.attr;
|
||||
ctx.save();
|
||||
ctx.globalAlpha *= Math.max(0, attr.callout - 0.5) * 2;
|
||||
if (ctx.globalAlpha > 0) {
|
||||
ctx.strokeStyle = attr.calloutColor;
|
||||
ctx.fillStyle = attr.calloutColor;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(me.attr.calloutStartX, me.attr.calloutStartY);
|
||||
ctx.lineTo(me.attr.calloutEndX, me.attr.calloutEndY);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(me.attr.calloutStartX, me.attr.calloutStartY, 1, 0, 2 * Math.PI, true);
|
||||
ctx.fill();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(me.attr.calloutEndX, me.attr.calloutEndY, 1, 0, 2 * Math.PI, true);
|
||||
ctx.fill();
|
||||
}
|
||||
ctx.restore();
|
||||
|
||||
Ext.draw.sprite.Text.prototype.render.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
61
OfficeWeb/3rdparty/touch/src/chart/series/Area.js
vendored
Normal file
61
OfficeWeb/3rdparty/touch/src/chart/series/Area.js
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @class Ext.chart.series.Area
|
||||
* @extends Ext.chart.series.StackedCartesian
|
||||
*
|
||||
* Creates an Area Chart.
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.CartesianChart({
|
||||
* animate: true,
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* axes: [{
|
||||
* type: 'numeric',
|
||||
* position: 'left',
|
||||
* fields: ['data1'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* grid: true,
|
||||
* minimum: 0
|
||||
* }, {
|
||||
* type: 'category',
|
||||
* position: 'bottom',
|
||||
* fields: ['name'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* }
|
||||
* }],
|
||||
* series: [{
|
||||
* type: 'area',
|
||||
* subStyle: {
|
||||
* fill: ['blue', 'green', 'red']
|
||||
* },
|
||||
* xField: 'name',
|
||||
* yField: ['data1', 'data2', 'data3']
|
||||
*
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*/
|
||||
Ext.define('Ext.chart.series.Area', {
|
||||
|
||||
extend: 'Ext.chart.series.StackedCartesian',
|
||||
|
||||
alias: 'series.area',
|
||||
type: 'area',
|
||||
seriesType: 'areaSeries',
|
||||
|
||||
requires: ['Ext.chart.series.sprite.Area']
|
||||
});
|
||||
104
OfficeWeb/3rdparty/touch/src/chart/series/Bar.js
vendored
Normal file
104
OfficeWeb/3rdparty/touch/src/chart/series/Bar.js
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @class Ext.chart.series.Bar
|
||||
* @extends Ext.chart.series.StackedCartesian
|
||||
*
|
||||
* Creates a Bar Chart.
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.Chart({
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* axes: [{
|
||||
* type: 'numeric',
|
||||
* position: 'left',
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* fields: 'data1'
|
||||
* }, {
|
||||
* type: 'category',
|
||||
* position: 'bottom',
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* fields: 'name'
|
||||
* }],
|
||||
* series: [{
|
||||
* type: 'bar',
|
||||
* xField: 'name',
|
||||
* yField: 'data1',
|
||||
* style: {
|
||||
* fill: 'blue'
|
||||
* }
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*/
|
||||
Ext.define('Ext.chart.series.Bar', {
|
||||
|
||||
extend: 'Ext.chart.series.StackedCartesian',
|
||||
|
||||
alias: 'series.bar',
|
||||
type: 'bar',
|
||||
seriesType: 'barSeries',
|
||||
|
||||
requires: [
|
||||
'Ext.chart.series.sprite.Bar',
|
||||
'Ext.draw.sprite.Rect'
|
||||
],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Object} itemInstancing Sprite template used for series.
|
||||
*/
|
||||
itemInstancing: {
|
||||
type: 'rect',
|
||||
fx: {
|
||||
customDuration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
radius: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
updateXAxis: function (axis) {
|
||||
axis.setLabelInSpan(true);
|
||||
this.callSuper(arguments);
|
||||
},
|
||||
|
||||
updateStacked: function (stacked) {
|
||||
var sprites = this.getSprites(),
|
||||
attrs = {}, i, ln = sprites.length;
|
||||
|
||||
if (this.getStacked()) {
|
||||
attrs.groupCount = 1;
|
||||
attrs.groupOffset = 0;
|
||||
for (i = 0; i < ln; i++) {
|
||||
sprites[i].setAttributes(attrs);
|
||||
}
|
||||
} else {
|
||||
attrs.groupCount = this.getYField().length;
|
||||
for (i = 0; i < ln; i++) {
|
||||
attrs.groupOffset = i;
|
||||
sprites[i].setAttributes(attrs);
|
||||
}
|
||||
}
|
||||
this.callSuper(arguments);
|
||||
}
|
||||
});
|
||||
100
OfficeWeb/3rdparty/touch/src/chart/series/CandleStick.js
vendored
Normal file
100
OfficeWeb/3rdparty/touch/src/chart/series/CandleStick.js
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @class Ext.chart.series.CandleStick
|
||||
* @extends Ext.chart.series.Cartesian
|
||||
*
|
||||
* Creates a candlestick or OHLC Chart.
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.CartesianChart({
|
||||
* animate: true,
|
||||
* store: {
|
||||
* fields: ['time', 'open', 'high', 'low', 'close'],
|
||||
* data: [
|
||||
* {'time':new Date('Jan 1 2010').getTime(), 'open':600, 'high':614, 'low':578, 'close':590},
|
||||
* {'time':new Date('Jan 2 2010').getTime(), 'open':590, 'high':609, 'low':580, 'close':580},
|
||||
* {'time':new Date('Jan 3 2010').getTime(), 'open':580, 'high':602, 'low':578, 'close':602},
|
||||
* {'time':new Date('Jan 4 2010').getTime(), 'open':602, 'high':614, 'low':586, 'close':586},
|
||||
* {'time':new Date('Jan 5 2010').getTime(), 'open':586, 'high':602, 'low':565, 'close':565}
|
||||
* ]
|
||||
* },
|
||||
* axes: [{
|
||||
* type: 'numeric',
|
||||
* position: 'left',
|
||||
* fields: ['open', 'high', 'low', 'close'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* grid: true,
|
||||
* minimum: 560,
|
||||
* maximum: 640
|
||||
* }, {
|
||||
* type: 'time',
|
||||
* position: 'bottom',
|
||||
* fields: ['time'],
|
||||
* fromDate: new Date('Dec 31 2009'),
|
||||
* toDate: new Date('Jan 6 2010'),
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* style: {
|
||||
* axisLine: false
|
||||
* }
|
||||
* }],
|
||||
* series: [{
|
||||
* type: 'candlestick',
|
||||
* xField: 'time',
|
||||
* openField: 'open',
|
||||
* highField: 'high',
|
||||
* lowField: 'low',
|
||||
* closeField: 'close',
|
||||
* style: {
|
||||
* dropStyle: {
|
||||
* fill: 'rgb(237, 123, 43)',
|
||||
* stroke: 'rgb(237, 123, 43)'
|
||||
* },
|
||||
* raiseStyle: {
|
||||
* fill: 'rgb(55, 153, 19)',
|
||||
* stroke: 'rgb(55, 153, 19)'
|
||||
* }
|
||||
* },
|
||||
* aggregator: {
|
||||
* strategy: 'time'
|
||||
* }
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*/
|
||||
Ext.define("Ext.chart.series.CandleStick", {
|
||||
extend: "Ext.chart.series.Cartesian",
|
||||
requires: ['Ext.chart.series.sprite.CandleStick'],
|
||||
alias: 'series.candlestick',
|
||||
type: 'candlestick',
|
||||
seriesType: 'candlestickSeries',
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} openField
|
||||
* The store record field name that represents the opening value of the given period.
|
||||
*/
|
||||
openField: null,
|
||||
/**
|
||||
* @cfg {String} highField
|
||||
* The store record field name that represents the highest value of the time interval represented.
|
||||
*/
|
||||
highField: null,
|
||||
/**
|
||||
* @cfg {String} lowField
|
||||
* The store record field name that represents the lowest value of the time interval represented.
|
||||
*/
|
||||
lowField: null,
|
||||
/**
|
||||
* @cfg {String} closeField
|
||||
* The store record field name that represents the closing value of the given period.
|
||||
*/
|
||||
closeField: null
|
||||
},
|
||||
|
||||
fieldCategoryY: ['Open', 'High', 'Low', 'Close']
|
||||
});
|
||||
144
OfficeWeb/3rdparty/touch/src/chart/series/Cartesian.js
vendored
Normal file
144
OfficeWeb/3rdparty/touch/src/chart/series/Cartesian.js
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @abstract
|
||||
* @class Ext.chart.series.Cartesian
|
||||
* @extends Ext.chart.series.Series
|
||||
*
|
||||
* Common base class for series implementations which plot values using x/y coordinates.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
Ext.define('Ext.chart.series.Cartesian', {
|
||||
extend: 'Ext.chart.series.Series',
|
||||
config: {
|
||||
/**
|
||||
* The field used to access the x axis value from the items from the data
|
||||
* source.
|
||||
*
|
||||
* @cfg {String} xField
|
||||
*/
|
||||
xField: null,
|
||||
|
||||
/**
|
||||
* The field used to access the y-axis value from the items from the data
|
||||
* source.
|
||||
*
|
||||
* @cfg {String} yField
|
||||
*/
|
||||
yField: null,
|
||||
|
||||
/**
|
||||
* @cfg {Ext.chart.axis.Axis} xAxis The chart axis bound to the series on the x-axis.
|
||||
*/
|
||||
xAxis: null,
|
||||
|
||||
/**
|
||||
* @cfg {Ext.chart.axis.Axis} yAxis The chart axis bound to the series on the y-axis.
|
||||
*/
|
||||
yAxis: null
|
||||
},
|
||||
|
||||
directions: ['X', 'Y'],
|
||||
fieldCategoryX: ['X'],
|
||||
fieldCategoryY: ['Y'],
|
||||
|
||||
updateXAxis: function (axis) {
|
||||
axis.processData(this);
|
||||
},
|
||||
|
||||
updateYAxis: function (axis) {
|
||||
axis.processData(this);
|
||||
},
|
||||
|
||||
coordinateX: function () {
|
||||
return this.coordinate('X', 0, 2);
|
||||
},
|
||||
|
||||
coordinateY: function () {
|
||||
return this.coordinate('Y', 1, 2);
|
||||
},
|
||||
|
||||
getItemForPoint: function (x, y) {
|
||||
if (this.getSprites()) {
|
||||
var me = this,
|
||||
sprite = me.getSprites()[0],
|
||||
store = me.getStore(),
|
||||
item;
|
||||
|
||||
if (sprite) {
|
||||
var index = sprite.getIndexNearPoint(x, y);
|
||||
if (index !== -1) {
|
||||
item = {
|
||||
series: this,
|
||||
category: this.getItemInstancing() ? 'items' : 'markers',
|
||||
index: index,
|
||||
record: store.getData().items[index],
|
||||
field: this.getYField(),
|
||||
sprite: sprite
|
||||
};
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
createSprite: function () {
|
||||
var sprite = this.callSuper(),
|
||||
xAxis = this.getXAxis();
|
||||
sprite.setFlipXY(this.getChart().getFlipXY());
|
||||
if (sprite.setAggregator && xAxis && xAxis.getAggregator) {
|
||||
if (xAxis.getAggregator) {
|
||||
sprite.setAggregator({strategy: xAxis.getAggregator()});
|
||||
} else {
|
||||
sprite.setAggregator({});
|
||||
}
|
||||
}
|
||||
return sprite;
|
||||
},
|
||||
|
||||
getSprites: function () {
|
||||
var me = this,
|
||||
chart = this.getChart(),
|
||||
animation = chart && chart.getAnimate(),
|
||||
itemInstancing = me.getItemInstancing(),
|
||||
sprites = me.sprites, sprite;
|
||||
|
||||
if (!chart) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!sprites.length) {
|
||||
sprite = me.createSprite();
|
||||
} else {
|
||||
sprite = sprites[0];
|
||||
}
|
||||
|
||||
if (animation) {
|
||||
me.getLabel().getTemplate().fx.setConfig(animation);
|
||||
if (itemInstancing) {
|
||||
sprite.itemsMarker.getTemplate().fx.setConfig(animation);
|
||||
}
|
||||
sprite.fx.setConfig(animation);
|
||||
}
|
||||
return sprites;
|
||||
},
|
||||
|
||||
provideLegendInfo: function (target) {
|
||||
var style = this.getStyle();
|
||||
target.push({
|
||||
name: this.getTitle() || this.getYField() || this.getId(),
|
||||
mark: style.fillStyle || style.strokeStyle || 'black',
|
||||
disabled: false,
|
||||
series: this.getId(),
|
||||
index: 0
|
||||
});
|
||||
},
|
||||
|
||||
getXRange: function () {
|
||||
return [this.dataRange[0], this.dataRange[2]];
|
||||
},
|
||||
|
||||
getYRange: function () {
|
||||
return [this.dataRange[1], this.dataRange[3]];
|
||||
}
|
||||
})
|
||||
;
|
||||
257
OfficeWeb/3rdparty/touch/src/chart/series/Gauge.js
vendored
Normal file
257
OfficeWeb/3rdparty/touch/src/chart/series/Gauge.js
vendored
Normal file
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
* @class Ext.chart.series.Gauge
|
||||
* @extends Ext.chart.series.Series
|
||||
*
|
||||
* Creates a Gauge Chart.
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.SpaceFillingChart({
|
||||
* series: [{
|
||||
* type: 'gauge',
|
||||
* minimum: 100,
|
||||
* maximum: 800,
|
||||
* value: 400,
|
||||
* donut: 30,
|
||||
* subStyle: {
|
||||
* fillStyle: ["#115fa6", "lightgrey"]
|
||||
* }
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*/
|
||||
Ext.define('Ext.chart.series.Gauge', {
|
||||
alias: 'series.gauge',
|
||||
extend: 'Ext.chart.series.Series',
|
||||
type: "gauge",
|
||||
seriesType: 'sector',
|
||||
|
||||
requires: [
|
||||
'Ext.draw.sprite.Sector'
|
||||
],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} angleField
|
||||
* @deprecated Use field directly
|
||||
* The store record field name to be used for the gauge angles.
|
||||
* The values bound to this field name must be positive real numbers.
|
||||
*/
|
||||
angleField: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} field
|
||||
* The store record field name to be used for the gauge angles.
|
||||
* The values bound to this field name must be positive real numbers.
|
||||
*/
|
||||
field: null,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} needle
|
||||
* Use the Gauge Series as an area series or add a needle to it.
|
||||
*/
|
||||
needle: false,
|
||||
|
||||
/**
|
||||
* @cfg {Number} needleLengthRatio
|
||||
* The length ratio between the length of needle and the radius of background section.
|
||||
*/
|
||||
needleLengthRatio: 0.8,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean/Number} donut
|
||||
* Use the entire disk or just a fraction of it for the gauge.
|
||||
*/
|
||||
donut: 30,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} showInLegend
|
||||
* Whether to add the gauge chart elements as legend items.
|
||||
*/
|
||||
showInLegend: false,
|
||||
|
||||
/**
|
||||
* @cfg {Number} value
|
||||
* Directly sets the displayed value of the gauge.
|
||||
*/
|
||||
value: null,
|
||||
|
||||
/**
|
||||
* @cfg {Number} minimum
|
||||
* The minimum value of the gauge.
|
||||
*/
|
||||
minimum: 0,
|
||||
|
||||
/**
|
||||
* @cfg {Number} maximum
|
||||
* The maximum value of the gauge.
|
||||
*/
|
||||
maximum: 100,
|
||||
|
||||
rotation: 0,
|
||||
|
||||
totalAngle: Math.PI / 2,
|
||||
|
||||
region: [0, 0, 1, 1],
|
||||
|
||||
center: [0.5, 0.75],
|
||||
|
||||
radius: 0.5,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} wholeDisk Indicates whether to show the whole disk or only the marked part.
|
||||
*/
|
||||
wholeDisk: false
|
||||
},
|
||||
|
||||
updateAngleField: function (angleField) {
|
||||
this.setField(angleField);
|
||||
},
|
||||
|
||||
updateRegion: function (region) {
|
||||
var wholeDisk = this.getWholeDisk(),
|
||||
halfTotalAngle = wholeDisk ? Math.PI : this.getTotalAngle() / 2,
|
||||
donut = this.getDonut() / 100,
|
||||
width, height, radius;
|
||||
if (halfTotalAngle <= Math.PI / 2) {
|
||||
width = 2 * Math.sin(halfTotalAngle);
|
||||
height = 1 - donut * Math.cos(halfTotalAngle);
|
||||
} else {
|
||||
width = 2;
|
||||
height = 1 - Math.cos(halfTotalAngle);
|
||||
}
|
||||
|
||||
radius = Math.min(region[2] / width, region[3] / height);
|
||||
this.setRadius(radius);
|
||||
this.setCenter([region[2] / 2, radius + (region[3] - height * radius) / 2]);
|
||||
},
|
||||
|
||||
updateCenter: function (center) {
|
||||
this.setStyle({
|
||||
centerX: center[0],
|
||||
centerY: center[1],
|
||||
rotationCenterX: center[0],
|
||||
rotationCenterY: center[1]
|
||||
});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
updateRotation: function (rotation) {
|
||||
this.setStyle({
|
||||
rotationRads: rotation - (this.getTotalAngle() + Math.PI) / 2
|
||||
});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
updateRadius: function (radius) {
|
||||
var donut = this.getDonut(),
|
||||
needle = this.getNeedle(),
|
||||
needleLengthRatio = needle ? this.getNeedleLengthRatio() : 1;
|
||||
this.setSubStyle({
|
||||
endRho: [radius * needleLengthRatio, radius],
|
||||
startRho: radius / 100 * donut
|
||||
});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
updateDonut: function (donut) {
|
||||
var radius = this.getRadius(),
|
||||
needle = this.getNeedle(),
|
||||
needleLengthRatio = needle ? this.getNeedleLengthRatio() : 1;
|
||||
this.setSubStyle({
|
||||
endRho: [radius * needleLengthRatio, radius],
|
||||
startRho: radius / 100 * donut
|
||||
});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
applyValue: function (value) {
|
||||
return Math.min(this.getMaximum(), Math.max(value, this.getMinimum()));
|
||||
},
|
||||
|
||||
updateValue: function (value) {
|
||||
var needle = this.getNeedle(),
|
||||
pos = (value - this.getMinimum()) / (this.getMaximum() - this.getMinimum()),
|
||||
total = this.getTotalAngle(),
|
||||
angle = pos * total,
|
||||
sprites = this.getSprites();
|
||||
|
||||
if (needle) {
|
||||
sprites[0].setAttributes({
|
||||
startAngle: angle,
|
||||
endAngle: angle
|
||||
});
|
||||
} else {
|
||||
sprites[0].setAttributes({
|
||||
endAngle: angle
|
||||
});
|
||||
}
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
processData: function () {
|
||||
var store = this.getStore();
|
||||
if (!store) {
|
||||
return;
|
||||
}
|
||||
var field = this.getField();
|
||||
if (!field) {
|
||||
return;
|
||||
}
|
||||
if (!store.getData().items.length) {
|
||||
return;
|
||||
}
|
||||
this.setValue(store.getData().items[0].get(field));
|
||||
},
|
||||
|
||||
getDefaultSpriteConfig: function () {
|
||||
return {
|
||||
type: 'sector',
|
||||
fx: {
|
||||
customDuration: {
|
||||
translationX: 0,
|
||||
translationY: 0,
|
||||
rotationCenterX: 0,
|
||||
rotationCenterY: 0,
|
||||
centerX: 0,
|
||||
centerY: 0,
|
||||
startRho: 0,
|
||||
endRho: 0,
|
||||
baseRotation: 0
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
getSprites: function () {
|
||||
//initialize store
|
||||
if(!this.getStore() && !Ext.isNumber(this.getValue())) {
|
||||
return null;
|
||||
}
|
||||
var me = this,
|
||||
sprite,
|
||||
animate = this.getChart().getAnimate(),
|
||||
sprites = me.sprites;
|
||||
|
||||
if (sprites && sprites.length) {
|
||||
sprites[0].fx.setConfig(animate);
|
||||
return sprites;
|
||||
}
|
||||
|
||||
// The needle
|
||||
sprite = me.createSprite();
|
||||
sprite.setAttributes({
|
||||
zIndex: 10
|
||||
});
|
||||
|
||||
// The background
|
||||
sprite = me.createSprite();
|
||||
sprite.setAttributes({
|
||||
startAngle: 0,
|
||||
endAngle: me.getTotalAngle()
|
||||
});
|
||||
me.doUpdateStyles();
|
||||
return sprites;
|
||||
}
|
||||
});
|
||||
|
||||
335
OfficeWeb/3rdparty/touch/src/chart/series/ItemPublisher.js
vendored
Normal file
335
OfficeWeb/3rdparty/touch/src/chart/series/ItemPublisher.js
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
Ext.define('Ext.chart.series.ItemPublisher', {
|
||||
extend: 'Ext.event.publisher.Publisher',
|
||||
|
||||
targetType: 'series',
|
||||
|
||||
handledEvents: [
|
||||
/**
|
||||
* @event itemmousemove
|
||||
* Fires when the mouse is moved on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemmousemove',
|
||||
/**
|
||||
* @event itemmouseup
|
||||
* Fires when a mouseup event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemmouseup',
|
||||
/**
|
||||
* @event itemmousedown
|
||||
* Fires when a mousedown event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemmousedown',
|
||||
/**
|
||||
* @event itemmouseover
|
||||
* Fires when the mouse enters a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemmouseover',
|
||||
/**
|
||||
* @event itemmouseout
|
||||
* Fires when the mouse exits a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemmouseout',
|
||||
/**
|
||||
* @event itemclick
|
||||
* Fires when a click event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemclick',
|
||||
/**
|
||||
* @event itemdoubleclick
|
||||
* Fires when a doubleclick event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemdoubleclick',
|
||||
/**
|
||||
* @event itemtap
|
||||
* Fires when a tap event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemtap',
|
||||
/**
|
||||
* @event itemtapstart
|
||||
* Fires when a tapstart event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemtapstart',
|
||||
/**
|
||||
* @event itemtapend
|
||||
* Fires when a tapend event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemtapend',
|
||||
/**
|
||||
* @event itemtapcancel
|
||||
* Fires when a tapcancel event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemtapcancel',
|
||||
/**
|
||||
* @event itemtaphold
|
||||
* Fires when a taphold event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemtaphold',
|
||||
/**
|
||||
* @event itemdoubletap
|
||||
* Fires when a doubletap event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemdoubletap',
|
||||
/**
|
||||
* @event itemsingletap
|
||||
* Fires when a singletap event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemsingletap',
|
||||
/**
|
||||
* @event itemtouchstart
|
||||
* Fires when a touchstart event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemtouchstart',
|
||||
/**
|
||||
* @event itemtouchmove
|
||||
* Fires when a touchmove event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemtouchmove',
|
||||
/**
|
||||
* @event itemtouchend
|
||||
* Fires when a touchend event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemtouchend',
|
||||
/**
|
||||
* @event itemdragstart
|
||||
* Fires when a dragstart event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemdragstart',
|
||||
/**
|
||||
* @event itemdrag
|
||||
* Fires when a drag event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemdrag',
|
||||
/**
|
||||
* @event itemdragend
|
||||
* Fires when a dragend event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemdragend',
|
||||
/**
|
||||
* @event itempinchstart
|
||||
* Fires when a pinchstart event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itempinchstart',
|
||||
/**
|
||||
* @event itempinch
|
||||
* Fires when a pinch event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itempinch',
|
||||
/**
|
||||
* @event itempinchend
|
||||
* Fires when a pinchend event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itempinchend',
|
||||
/**
|
||||
* @event itemswipe
|
||||
* Fires when a swipe event occurs on a series item.
|
||||
* @param {Ext.chart.series.Series} series
|
||||
* @param {Object} item
|
||||
* @param {Event} event
|
||||
*/
|
||||
'itemswipe'
|
||||
],
|
||||
|
||||
delegationRegex: /^item([a-z]+)$/i,
|
||||
|
||||
getSubscribers: function (chartId) {
|
||||
var subscribers = this.subscribers;
|
||||
|
||||
if (!subscribers.hasOwnProperty(chartId)) {
|
||||
subscribers[chartId] = {};
|
||||
}
|
||||
|
||||
return subscribers[chartId];
|
||||
},
|
||||
|
||||
subscribe: function (target, eventName) {
|
||||
var match = target.match(this.idSelectorRegex),
|
||||
dispatcher = this.dispatcher,
|
||||
targetType = this.targetType,
|
||||
subscribers, series, id;
|
||||
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
|
||||
id = match[1];
|
||||
series = Ext.ComponentManager.get(id);
|
||||
if (!series) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!series.getChart()) {
|
||||
dispatcher.addListener(targetType, target, 'chartattached', 'attachChart', this, [series, eventName], 'before');
|
||||
} else {
|
||||
this.attachChart(series.getChart(), [series, eventName]);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
unsubscribe: function (target, eventName, all) {
|
||||
var match = target.match(this.idSelectorRegex),
|
||||
dispatcher = this.dispatcher,
|
||||
targetType = this.targetType,
|
||||
subscribers, series, id;
|
||||
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
|
||||
id = match[1];
|
||||
series = Ext.ComponentManager.get(id);
|
||||
if (!series) {
|
||||
return false;
|
||||
}
|
||||
|
||||
subscribers = this.getSubscribers(target, false);
|
||||
if (!subscribers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
subscribers.$length--;
|
||||
if (subscribers.hasOwnProperty(eventName)) {
|
||||
subscribers[eventName]--;
|
||||
if (series.getChart()) {
|
||||
this.detachChart(series.getChart(), [series, eventName, subscribers]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
relayMethod: function (e, sender, args) {
|
||||
var chart = args[0],
|
||||
eventName = args[1],
|
||||
dispatcher = this.dispatcher,
|
||||
targetType = this.targetType,
|
||||
chartXY = chart.getEventXY(e),
|
||||
x = chartXY[0],
|
||||
y = chartXY[1],
|
||||
subscriber = this.getSubscribers(chart.getId())[eventName],
|
||||
i, ln;
|
||||
if (subscriber) {
|
||||
for (i = 0, ln = subscriber.length; i < ln; i++) {
|
||||
var series = subscriber[i],
|
||||
item = series.getItemForPoint(x, y);
|
||||
if (item) {
|
||||
dispatcher.doDispatchEvent(targetType, '#' + series.getId(), eventName, [series, item, e]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
detachChart: function (chart, args) {
|
||||
var dispatcher = this.dispatcher,
|
||||
targetType = this.targetType,
|
||||
series = args[0],
|
||||
eventName = args[1],
|
||||
subscribers = args[2],
|
||||
match = eventName.match(this.delegationRegex);
|
||||
if (match) {
|
||||
var chartEventName = match[1];
|
||||
if (subscribers.hasOwnProperty(eventName)) {
|
||||
Ext.remove(subscribers[eventName], series);
|
||||
if (subscribers[eventName].length === 0) {
|
||||
chart.element.un(chartEventName, "relayMethod", this, [chart, series, eventName]);
|
||||
}
|
||||
}
|
||||
dispatcher.removeListener(targetType, '#' + series.getId(), 'chartdetached', 'detachChart', this, [series, eventName, subscribers], 'after');
|
||||
}
|
||||
},
|
||||
|
||||
attachChart: function (chart, args) {
|
||||
var dispatcher = this.dispatcher,
|
||||
targetType = this.targetType,
|
||||
series = args[0],
|
||||
eventName = args[1],
|
||||
subscribers = this.getSubscribers(chart.getId()),
|
||||
match = eventName.match(this.delegationRegex);
|
||||
if (match) {
|
||||
var chartEventName = match[1];
|
||||
if (!subscribers.hasOwnProperty(eventName)) {
|
||||
subscribers[eventName] = [];
|
||||
dispatcher.addListener(targetType, '#' + series.getId(), 'chartdetached', 'detachChart', this, [series, eventName, subscribers], 'after');
|
||||
chart.element.on(chartEventName, "relayMethod", this, [chart, eventName]);
|
||||
}
|
||||
subscribers[eventName].push(series);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}, function () {
|
||||
|
||||
});
|
||||
139
OfficeWeb/3rdparty/touch/src/chart/series/Line.js
vendored
Normal file
139
OfficeWeb/3rdparty/touch/src/chart/series/Line.js
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* @class Ext.chart.series.Line
|
||||
* @extends Ext.chart.series.Cartesian
|
||||
*
|
||||
* Creates a Line Chart. A Line Chart is a useful visualization technique to display quantitative information for different
|
||||
* categories or other real values (as opposed to the bar chart), that can show some progression (or regression) in the dataset.
|
||||
* As with all other series, the Line Series must be appended in the *series* Chart array configuration. See the Chart
|
||||
* documentation for more information. A typical configuration object for the line series could be:
|
||||
*
|
||||
* @example preview
|
||||
* var lineChart = new Ext.chart.CartesianChart({
|
||||
* animate: true,
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* axes: [{
|
||||
* type: 'numeric',
|
||||
* position: 'left',
|
||||
* fields: ['data1'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* grid: true,
|
||||
* minimum: 0
|
||||
* }, {
|
||||
* type: 'category',
|
||||
* position: 'bottom',
|
||||
* fields: ['name'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* }
|
||||
* }],
|
||||
* series: [{
|
||||
* type: 'line',
|
||||
* highlight: {
|
||||
* size: 7,
|
||||
* radius: 7
|
||||
* },
|
||||
* style: {
|
||||
* stroke: 'rgb(143,203,203)'
|
||||
* },
|
||||
* xField: 'name',
|
||||
* yField: 'data1',
|
||||
* marker: {
|
||||
* type: 'path',
|
||||
* path: ['M', -2, 0, 0, 2, 2, 0, 0, -2, 'Z'],
|
||||
* stroke: 'blue',
|
||||
* lineWidth: 0
|
||||
* }
|
||||
* }, {
|
||||
* type: 'line',
|
||||
* highlight: {
|
||||
* size: 7,
|
||||
* radius: 7
|
||||
* },
|
||||
* fill: true,
|
||||
* xField: 'name',
|
||||
* yField: 'data3',
|
||||
* marker: {
|
||||
* type: 'circle',
|
||||
* radius: 4,
|
||||
* lineWidth: 0
|
||||
* }
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(lineChart);
|
||||
*
|
||||
* In this configuration we're adding two series (or lines), one bound to the `data1`
|
||||
* property of the store and the other to `data3`. The type for both configurations is
|
||||
* `line`. The `xField` for both series is the same, the `name` property of the store.
|
||||
* Both line series share the same axis, the left axis. You can set particular marker
|
||||
* configuration by adding properties onto the markerConfig object. Both series have
|
||||
* an object as highlight so that markers animate smoothly to the properties in highlight
|
||||
* when hovered. The second series has `fill = true` which means that the line will also
|
||||
* have an area below it of the same color.
|
||||
*
|
||||
* **Note:** In the series definition remember to explicitly set the axis to bind the
|
||||
* values of the line series to. This can be done by using the `axis` configuration property.
|
||||
*/
|
||||
Ext.define('Ext.chart.series.Line', {
|
||||
extend: 'Ext.chart.series.Cartesian',
|
||||
alias: 'series.line',
|
||||
type: 'line',
|
||||
seriesType: 'lineSeries',
|
||||
|
||||
requires: [
|
||||
'Ext.chart.series.sprite.Line'
|
||||
],
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Number} selectionTolerance
|
||||
* The offset distance from the cursor position to the line series to trigger events (then used for highlighting series, etc).
|
||||
*/
|
||||
selectionTolerance: 20,
|
||||
|
||||
/**
|
||||
* @cfg {Object} style
|
||||
* An object containing styles for the visualization lines. These styles will override the theme styles.
|
||||
* Some options contained within the style object will are described next.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @cfg {Boolean/Number} smooth
|
||||
* If set to `true` or a non-zero number, the line will be smoothed/rounded around its points; otherwise
|
||||
* straight line segments will be drawn.
|
||||
*
|
||||
* A numeric value is interpreted as a divisor of the horizontal distance between consecutive points in
|
||||
* the line; larger numbers result in sharper curves while smaller numbers result in smoother curves.
|
||||
*
|
||||
* If set to `true` then a default numeric value of 3 will be used.
|
||||
*/
|
||||
smooth: false,
|
||||
|
||||
aggregator: { strategy: 'double' }
|
||||
},
|
||||
|
||||
/**
|
||||
* @private Default numeric smoothing value to be used when `{@link #smooth} = true`.
|
||||
*/
|
||||
defaultSmoothness: 3,
|
||||
|
||||
/**
|
||||
* @private Size of the buffer area on either side of the viewport to provide seamless zoom/pan
|
||||
* transforms. Expressed as a multiple of the viewport length, e.g. 1 will make the buffer on
|
||||
* each side equal to the length of the visible axis viewport.
|
||||
*/
|
||||
overflowBuffer: 1
|
||||
});
|
||||
315
OfficeWeb/3rdparty/touch/src/chart/series/Pie.js
vendored
Normal file
315
OfficeWeb/3rdparty/touch/src/chart/series/Pie.js
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
/**
|
||||
* @class Ext.chart.series.Pie
|
||||
* @extends Ext.chart.series.Polar
|
||||
*
|
||||
* Creates a Pie Chart. A Pie Chart is a useful visualization technique to display quantitative information for different
|
||||
* categories that also have a meaning as a whole.
|
||||
* As with all other series, the Pie Series must be appended in the *series* Chart array configuration. See the Chart
|
||||
* documentation for more information. A typical configuration object for the pie series could be:
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.PolarChart({
|
||||
* animate: true,
|
||||
* interactions: ['rotate'],
|
||||
* colors: ["#115fa6", "#94ae0a", "#a61120", "#ff8809", "#ffd13e"],
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* series: [{
|
||||
* type: 'pie',
|
||||
* labelField: 'name',
|
||||
* xField: 'data3',
|
||||
* donut: 30
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*
|
||||
* In this configuration we set `pie` as the type for the series, set an object with specific style properties for highlighting options
|
||||
* (triggered when hovering elements). We also set true to `showInLegend` so all the pie slices can be represented by a legend item.
|
||||
* We set `data1` as the value of the field to determine the angle span for each pie slice. We also set a label configuration object
|
||||
* where we set the field name of the store field to be renderer as text for the label. The labels will also be displayed rotated.
|
||||
* We set `contrast` to `true` to flip the color of the label if it is to similar to the background color. Finally, we set the font family
|
||||
* and size through the `font` parameter.
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.chart.series.Pie', {
|
||||
extend: 'Ext.chart.series.Polar',
|
||||
requires: [
|
||||
"Ext.chart.series.sprite.PieSlice"
|
||||
],
|
||||
type: 'pie',
|
||||
alias: 'series.pie',
|
||||
seriesType: 'pieslice',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {String} labelField
|
||||
* The store record field name to be used for the pie slice labels.
|
||||
*/
|
||||
labelField: false,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean/Number} donut Whether to set the pie chart as donut chart.
|
||||
* Can be set to a particular percentage to set the radius of the donut chart.
|
||||
*/
|
||||
donut: false,
|
||||
|
||||
/**
|
||||
* @cfg {String} field
|
||||
* @deprecated Use xField directly
|
||||
*/
|
||||
field: null,
|
||||
|
||||
/**
|
||||
* @cfg {Number} rotation The starting angle of the pie slices.
|
||||
*/
|
||||
rotation: 0,
|
||||
|
||||
/**
|
||||
* @cfg {Number} [totalAngle=2*PI] The total angle of the pie series.
|
||||
*/
|
||||
totalAngle: Math.PI * 2,
|
||||
|
||||
/**
|
||||
* @cfg {Array} hidden Determines which pie slices are hidden.
|
||||
*/
|
||||
hidden: [],
|
||||
|
||||
style: {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
directions: ['X'],
|
||||
|
||||
setField: function (f) {
|
||||
return this.setXField(f);
|
||||
},
|
||||
|
||||
getField: function () {
|
||||
return this.getXField();
|
||||
},
|
||||
|
||||
updateLabelData: function () {
|
||||
var me = this,
|
||||
store = me.getStore(),
|
||||
items = store.getData().items,
|
||||
sprites = me.getSprites(),
|
||||
labelField = me.getLabelField(),
|
||||
i, ln, labels;
|
||||
if (sprites.length > 0 && labelField) {
|
||||
labels = [];
|
||||
for (i = 0, ln = items.length; i < ln; i++) {
|
||||
labels.push(items[i].get(labelField));
|
||||
}
|
||||
for (i = 0, ln = sprites.length; i < ln; i++) {
|
||||
sprites[i].setAttributes({label: labels[i]});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
coordinateX: function () {
|
||||
var me = this,
|
||||
store = me.getStore(),
|
||||
items = store.getData().items,
|
||||
length = items.length,
|
||||
field = me.getXField(),
|
||||
value, sum = 0,
|
||||
hidden = me.getHidden(),
|
||||
summation = [], i,
|
||||
lastAngle = 0,
|
||||
totalAngle = me.getTotalAngle(),
|
||||
sprites = me.getSprites();
|
||||
|
||||
if (!sprites) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
value = items[i].get(field);
|
||||
if (!hidden[i]) {
|
||||
sum += value;
|
||||
}
|
||||
summation[i] = sum;
|
||||
if (i >= hidden.length) {
|
||||
hidden[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (sum === 0) {
|
||||
return;
|
||||
}
|
||||
sum = totalAngle / sum;
|
||||
for (i = 0; i < length; i++) {
|
||||
sprites[i].setAttributes({
|
||||
startAngle: lastAngle,
|
||||
endAngle: lastAngle = summation[i] * sum,
|
||||
globalAlpha: 1
|
||||
});
|
||||
}
|
||||
for (; i < me.sprites.length; i++) {
|
||||
sprites[i].setAttributes({
|
||||
startAngle: totalAngle,
|
||||
endAngle: totalAngle,
|
||||
globalAlpha: 0
|
||||
});
|
||||
}
|
||||
me.getChart().refreshLegendStore();
|
||||
},
|
||||
|
||||
updateCenter: function (center) {
|
||||
this.setStyle({
|
||||
translationX: center[0] + this.getOffsetX(),
|
||||
translationY: center[1] + this.getOffsetY()
|
||||
});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
updateRadius: function (radius) {
|
||||
this.setStyle({
|
||||
startRho: radius * this.getDonut() * 0.01, // Percentage
|
||||
endRho: radius
|
||||
});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
updateDonut: function (donut) {
|
||||
var radius = this.getRadius();
|
||||
this.setStyle({
|
||||
startRho: radius * donut * 0.01, // Percentage
|
||||
endRho: radius
|
||||
});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
updateRotation: function (rotation) {
|
||||
this.setStyle({
|
||||
rotationRads: rotation
|
||||
});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
updateTotalAngle: function (totalAngle) {
|
||||
this.processData();
|
||||
},
|
||||
|
||||
getSprites: function () {
|
||||
var me = this,
|
||||
chart = this.getChart(),
|
||||
store = me.getStore();
|
||||
if (!chart || !store) {
|
||||
return[];
|
||||
}
|
||||
me.getColors();
|
||||
me.getSubStyle();
|
||||
var items = store.getData().items,
|
||||
length = items.length,
|
||||
animation = chart && chart.getAnimate(),
|
||||
center = me.getCenter(),
|
||||
offsetX = me.getOffsetX(),
|
||||
offsetY = me.getOffsetY(),
|
||||
sprites = me.sprites, sprite,
|
||||
i, spriteCreated = false;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
sprite = sprites[i];
|
||||
if (!sprite) {
|
||||
sprite = me.createSprite();
|
||||
if (me.getHighlightCfg()) {
|
||||
sprite.config.highlightCfg = me.getHighlightCfg();
|
||||
sprite.addModifier('highlight', true);
|
||||
}
|
||||
if (me.getLabelField()) {
|
||||
me.getLabel().getTemplate().setAttributes({
|
||||
labelOverflowPadding: this.getLabelOverflowPadding()
|
||||
});
|
||||
me.getLabel().getTemplate().fx.setCustomDuration({'callout': 200});
|
||||
sprite.bindMarker('labels', me.getLabel());
|
||||
}
|
||||
sprite.setAttributes(this.getStyleByIndex(i));
|
||||
spriteCreated = true;
|
||||
}
|
||||
sprite.fx.setConfig(animation);
|
||||
}
|
||||
if (spriteCreated) {
|
||||
me.doUpdateStyles();
|
||||
}
|
||||
return me.sprites;
|
||||
},
|
||||
|
||||
betweenAngle: function (x, a, b) {
|
||||
b -= a;
|
||||
x -= a;
|
||||
x %= Math.PI * 2;
|
||||
b %= Math.PI * 2;
|
||||
x += Math.PI * 2;
|
||||
b += Math.PI * 2;
|
||||
x %= Math.PI * 2;
|
||||
b %= Math.PI * 2;
|
||||
return x < b;
|
||||
},
|
||||
|
||||
getItemForPoint: function (x, y) {
|
||||
var me = this,
|
||||
sprites = me.getSprites();
|
||||
if (sprites) {
|
||||
var center = me.getCenter(),
|
||||
offsetX = me.getOffsetX(),
|
||||
offsetY = me.getOffsetY(),
|
||||
originalX = x - center[0] + offsetX,
|
||||
originalY = y - center[1] + offsetY,
|
||||
store = me.getStore(),
|
||||
donut = me.getDonut(),
|
||||
items = store.getData().items,
|
||||
direction = Math.atan2(originalY, originalX) - me.getRotation(),
|
||||
donutLimit = Math.sqrt(originalX * originalX + originalY * originalY),
|
||||
endRadius = me.getRadius(),
|
||||
startRadius = donut / 100 * endRadius,
|
||||
i, ln, attr;
|
||||
|
||||
for (i = 0, ln = items.length; i < ln; i++) {
|
||||
// Fortunately, the id of items equals the index of it in instances list.
|
||||
attr = sprites[i].attr;
|
||||
if (startRadius + attr.margin <= donutLimit && donutLimit + attr.margin <= endRadius) {
|
||||
if (this.betweenAngle(direction, attr.startAngle, attr.endAngle)) {
|
||||
return {
|
||||
series: this,
|
||||
sprite: sprites[i],
|
||||
index: i,
|
||||
record: items[i],
|
||||
field: this.getXField()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
provideLegendInfo: function (target) {
|
||||
var store = this.getStore();
|
||||
if (store) {
|
||||
var items = store.getData().items,
|
||||
labelField = this.getLabelField(),
|
||||
field = this.getField(),
|
||||
hidden = this.getHidden();
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
target.push({
|
||||
name: labelField ? String(items[i].get(labelField)) : (field && field[i]) || this.getId(),
|
||||
mark: this.getStyleByIndex(i).fillStyle || this.getStyleByIndex(i).strokeStyle || 'black',
|
||||
disabled: hidden[i],
|
||||
series: this.getId(),
|
||||
index: i
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
247
OfficeWeb/3rdparty/touch/src/chart/series/Pie3D.js
vendored
Normal file
247
OfficeWeb/3rdparty/touch/src/chart/series/Pie3D.js
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* @class Ext.chart.series.Pie3D
|
||||
* @extends Ext.chart.series.sprite.Polar
|
||||
*
|
||||
* Creates a 3D Pie Chart.
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.PolarChart({
|
||||
* animate: true,
|
||||
* interactions: ['rotate'],
|
||||
* colors: ["#115fa6", "#94ae0a", "#a61120", "#ff8809", "#ffd13e"],
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* series: [{
|
||||
* type: 'pie3d',
|
||||
* field: 'data3',
|
||||
* donut: 30
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*/
|
||||
Ext.define('Ext.chart.series.Pie3D', {
|
||||
requires: ['Ext.chart.series.sprite.Pie3DPart'],
|
||||
extend: 'Ext.chart.series.Polar',
|
||||
type: 'pie3d',
|
||||
seriesType: 'pie3d',
|
||||
alias: 'series.pie3d',
|
||||
config: {
|
||||
region: [0, 0, 0, 0],
|
||||
thickness: 35,
|
||||
distortion: 0.5,
|
||||
|
||||
/**
|
||||
* @cfg {String} field (required)
|
||||
* The store record field name to be used for the pie angles.
|
||||
* The values bound to this field name must be positive real numbers.
|
||||
*/
|
||||
field: false,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @cfg {String} lengthField
|
||||
* Not supported.
|
||||
*/
|
||||
lengthField: false,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean/Number} donut
|
||||
* Whether to set the pie chart as donut chart.
|
||||
* Can be set to a particular percentage to set the radius
|
||||
* of the donut chart.
|
||||
*/
|
||||
donut: false,
|
||||
|
||||
rotation: 0
|
||||
},
|
||||
|
||||
applyRotation: function (rotation) {
|
||||
var twoPie = Math.PI * 2;
|
||||
return (rotation % twoPie + twoPie) % twoPie;
|
||||
},
|
||||
|
||||
updateRotation: function (rotation) {
|
||||
var sprites = this.getSprites(),
|
||||
i, ln;
|
||||
for (i = 0, ln = sprites.length; i < ln; i++) {
|
||||
sprites[i].setAttributes({
|
||||
baseRotation: rotation
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
updateColors: function (colorSet) {
|
||||
this.setSubStyle({baseColor: colorSet});
|
||||
},
|
||||
|
||||
doUpdateStyles: function () {
|
||||
var sprites = this.getSprites(),
|
||||
i = 0, j = 0, ln = sprites && sprites.length;
|
||||
for (; i < ln; i += 5, j++) {
|
||||
sprites[i].setAttributes(this.getStyleByIndex(j));
|
||||
sprites[i + 1].setAttributes(this.getStyleByIndex(j));
|
||||
sprites[i + 2].setAttributes(this.getStyleByIndex(j));
|
||||
sprites[i + 3].setAttributes(this.getStyleByIndex(j));
|
||||
sprites[i + 4].setAttributes(this.getStyleByIndex(j));
|
||||
}
|
||||
},
|
||||
|
||||
processData: function () {
|
||||
var me = this,
|
||||
chart = me.getChart(),
|
||||
animation = chart && chart.getAnimate(),
|
||||
store = me.getStore(),
|
||||
items = store.getData().items,
|
||||
length = items.length,
|
||||
field = me.getField(),
|
||||
value, sum = 0, ratio,
|
||||
summation = [],
|
||||
i,
|
||||
sprites = this.getSprites(),
|
||||
lastAngle;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
value = items[i].get(field);
|
||||
sum += value;
|
||||
summation[i] = sum;
|
||||
}
|
||||
if (sum === 0) {
|
||||
return;
|
||||
}
|
||||
ratio = 2 * Math.PI / sum;
|
||||
for (i = 0; i < length; i++) {
|
||||
summation[i] *= ratio;
|
||||
}
|
||||
|
||||
for (i = 0; i < sprites.length; i++) {
|
||||
sprites[i].fx.setConfig(animation);
|
||||
}
|
||||
|
||||
for (i = 0, lastAngle = 0; i < length; i++) {
|
||||
var commonAttributes = {opacity: 1, startAngle: lastAngle, endAngle: summation[i]};
|
||||
sprites[i * 5].setAttributes(commonAttributes);
|
||||
sprites[i * 5 + 1].setAttributes(commonAttributes);
|
||||
sprites[i * 5 + 2].setAttributes(commonAttributes);
|
||||
sprites[i * 5 + 3].setAttributes(commonAttributes);
|
||||
sprites[i * 5 + 4].setAttributes(commonAttributes);
|
||||
lastAngle = summation[i];
|
||||
}
|
||||
},
|
||||
|
||||
getSprites: function () {
|
||||
var me = this,
|
||||
chart = this.getChart(),
|
||||
surface = me.getSurface(),
|
||||
store = me.getStore();
|
||||
if (!store) {
|
||||
return [];
|
||||
}
|
||||
var items = store.getData().items,
|
||||
length = items.length,
|
||||
animation = chart && chart.getAnimate(),
|
||||
region = chart.getMainRegion() || [0, 0, 1, 1],
|
||||
rotation = me.getRotation(),
|
||||
center = me.getCenter(),
|
||||
offsetX = me.getOffsetX(),
|
||||
offsetY = me.getOffsetY(),
|
||||
radius = Math.min((region[3] - me.getThickness() * 2) / me.getDistortion(), region[2]) / 2,
|
||||
commonAttributes = {
|
||||
centerX: center[0] + offsetX,
|
||||
centerY: center[1] + offsetY - me.getThickness() / 2,
|
||||
endRho: radius,
|
||||
startRho: radius * me.getDonut() / 100,
|
||||
thickness: me.getThickness(),
|
||||
distortion: me.getDistortion()
|
||||
}, sliceAttributes, twoPie = Math.PI * 2,
|
||||
topSprite, startSprite, endSprite, innerSideSprite, outerSideSprite,
|
||||
i;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
sliceAttributes = Ext.apply({}, this.getStyleByIndex(i), commonAttributes);
|
||||
topSprite = me.sprites[i * 5];
|
||||
if (!topSprite) {
|
||||
topSprite = surface.add({
|
||||
type: 'pie3dPart',
|
||||
part: 'top',
|
||||
startAngle: twoPie,
|
||||
endAngle: twoPie
|
||||
});
|
||||
startSprite = surface.add({
|
||||
type: 'pie3dPart',
|
||||
part: 'start',
|
||||
startAngle: twoPie,
|
||||
endAngle: twoPie
|
||||
});
|
||||
endSprite = surface.add({
|
||||
type: 'pie3dPart',
|
||||
part: 'end',
|
||||
startAngle: twoPie,
|
||||
endAngle: twoPie
|
||||
});
|
||||
innerSideSprite = surface.add({
|
||||
type: 'pie3dPart',
|
||||
part: 'inner',
|
||||
startAngle: twoPie,
|
||||
endAngle: twoPie,
|
||||
thickness: 0
|
||||
});
|
||||
outerSideSprite = surface.add({
|
||||
type: 'pie3dPart',
|
||||
part: 'outer',
|
||||
startAngle: twoPie,
|
||||
endAngle: twoPie,
|
||||
thickness: 0
|
||||
});
|
||||
topSprite.fx.setDurationOn('baseRotation', 0);
|
||||
startSprite.fx.setDurationOn('baseRotation', 0);
|
||||
endSprite.fx.setDurationOn('baseRotation', 0);
|
||||
innerSideSprite.fx.setDurationOn('baseRotation', 0);
|
||||
outerSideSprite.fx.setDurationOn('baseRotation', 0);
|
||||
topSprite.setAttributes(sliceAttributes);
|
||||
startSprite.setAttributes(sliceAttributes);
|
||||
endSprite.setAttributes(sliceAttributes);
|
||||
innerSideSprite.setAttributes(sliceAttributes);
|
||||
outerSideSprite.setAttributes(sliceAttributes);
|
||||
me.sprites.push(topSprite, startSprite, endSprite, innerSideSprite, outerSideSprite);
|
||||
} else {
|
||||
startSprite = me.sprites[i * 5 + 1];
|
||||
endSprite = me.sprites[i * 5 + 2];
|
||||
innerSideSprite = me.sprites[i * 5 + 3];
|
||||
outerSideSprite = me.sprites[i * 5 + 4];
|
||||
if (animation) {
|
||||
topSprite.fx.setConfig(animation);
|
||||
startSprite.fx.setConfig(animation);
|
||||
endSprite.fx.setConfig(animation);
|
||||
innerSideSprite.fx.setConfig(animation);
|
||||
outerSideSprite.fx.setConfig(animation);
|
||||
}
|
||||
topSprite.setAttributes(sliceAttributes);
|
||||
startSprite.setAttributes(sliceAttributes);
|
||||
endSprite.setAttributes(sliceAttributes);
|
||||
innerSideSprite.setAttributes(sliceAttributes);
|
||||
outerSideSprite.setAttributes(sliceAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
for (i *= 5; i < me.sprites.length; i++) {
|
||||
me.sprites[i].fx.setConfig(animation);
|
||||
me.sprites[i].setAttributes({
|
||||
opacity: 0,
|
||||
startAngle: twoPie,
|
||||
endAngle: twoPie,
|
||||
baseRotation: rotation
|
||||
});
|
||||
}
|
||||
|
||||
return me.sprites;
|
||||
}
|
||||
});
|
||||
103
OfficeWeb/3rdparty/touch/src/chart/series/Polar.js
vendored
Normal file
103
OfficeWeb/3rdparty/touch/src/chart/series/Polar.js
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Polar series.
|
||||
*/
|
||||
Ext.define('Ext.chart.series.Polar', {
|
||||
|
||||
extend: 'Ext.chart.series.Series',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @cfg {Number} rotation
|
||||
* The angle in degrees at which the first polar series item should start.
|
||||
*/
|
||||
rotation: 0,
|
||||
|
||||
/**
|
||||
* @cfg {Number} radius
|
||||
* The radius of the polar series. Set to `null` will fit the polar series to the boundary.
|
||||
*/
|
||||
radius: null,
|
||||
|
||||
/**
|
||||
* @cfg {Array} center for the polar series.
|
||||
*/
|
||||
center: [0, 0],
|
||||
|
||||
/**
|
||||
* @cfg {Number} offsetX
|
||||
* The x-offset of center of the polar series related to the center of the boundary.
|
||||
*/
|
||||
offsetX: 0,
|
||||
|
||||
/**
|
||||
* @cfg {Number} offsetY
|
||||
* The y-offset of center of the polar series related to the center of the boundary.
|
||||
*/
|
||||
offsetY: 0,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} showInLegend
|
||||
* Whether to add the series elements as legend items.
|
||||
*/
|
||||
showInLegend: true,
|
||||
|
||||
/**
|
||||
* @cfg {String} xField
|
||||
* The store record field name for the labels used in the radar series.
|
||||
*/
|
||||
xField: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} yField
|
||||
* The store record field name for the deflection of the graph in the radar series.
|
||||
*/
|
||||
yField: null,
|
||||
|
||||
xAxis: null,
|
||||
|
||||
yAxis: null
|
||||
},
|
||||
|
||||
directions: ['X', 'Y'],
|
||||
|
||||
fieldCategoryX: ['X'],
|
||||
fieldCategoryY: ['Y'],
|
||||
|
||||
getDefaultSpriteConfig: function () {
|
||||
return {
|
||||
type: this.seriesType,
|
||||
centerX: 0,
|
||||
centerY: 0,
|
||||
rotationCenterX: 0,
|
||||
rotationCenterY: 0,
|
||||
fx: {
|
||||
customDuration: {
|
||||
translationX: 0,
|
||||
translationY: 0,
|
||||
centerX: 0,
|
||||
centerY: 0,
|
||||
startRho: 0,
|
||||
endRho: 0,
|
||||
baseRotation: 0,
|
||||
rotationCenterX: 0,
|
||||
rotationCenterY: 0,
|
||||
rotationRads: 0
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
applyRotation: function (rotation) {
|
||||
var twoPie = Math.PI * 2;
|
||||
return (rotation % twoPie + Math.PI) % twoPie - Math.PI;
|
||||
},
|
||||
|
||||
updateRotation: function (rotation) {
|
||||
var sprites = this.getSprites();
|
||||
if (sprites && sprites[0]) {
|
||||
sprites[0].setAttributes({
|
||||
baseRotation: rotation
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
168
OfficeWeb/3rdparty/touch/src/chart/series/Radar.js
vendored
Normal file
168
OfficeWeb/3rdparty/touch/src/chart/series/Radar.js
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* @class Ext.chart.series.Radar
|
||||
* @extends Ext.chart.series.Polar
|
||||
*
|
||||
* Creates a Radar Chart. A Radar Chart is a useful visualization technique for comparing different quantitative values for
|
||||
* a constrained number of categories.
|
||||
* As with all other series, the Radar series must be appended in the *series* Chart array configuration. See the Chart
|
||||
* documentation for more information. A typical configuration object for the radar series could be:
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.PolarChart({
|
||||
* animate: true,
|
||||
* interactions: ['rotate'],
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* series: [{
|
||||
* type: 'radar',
|
||||
* xField: 'name',
|
||||
* yField: 'data4',
|
||||
* style: {
|
||||
* fillStyle: 'rgba(0, 0, 255, 0.1)',
|
||||
* strokeStyle: 'rgba(0, 0, 0, 0.8)',
|
||||
* lineWidth: 1
|
||||
* }
|
||||
* }],
|
||||
* axes: [
|
||||
* {
|
||||
* type: 'numeric',
|
||||
* position: 'radial',
|
||||
* fields: 'data4',
|
||||
* style: {
|
||||
* estStepSize: 10
|
||||
* },
|
||||
* grid: true
|
||||
* },
|
||||
* {
|
||||
* type: 'category',
|
||||
* position: 'angular',
|
||||
* fields: 'name',
|
||||
* style: {
|
||||
* estStepSize: 1
|
||||
* },
|
||||
* grid: true
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.chart.series.Radar', {
|
||||
extend: 'Ext.chart.series.Polar',
|
||||
type: "radar",
|
||||
seriesType: 'radar',
|
||||
alias: 'series.radar',
|
||||
requires: ['Ext.chart.series.Cartesian', 'Ext.chart.series.sprite.Radar'],
|
||||
/**
|
||||
* @cfg {Object} style
|
||||
* An object containing styles for overriding series styles from theming.
|
||||
*/
|
||||
|
||||
config: {
|
||||
|
||||
},
|
||||
|
||||
updateAngularAxis: function (axis) {
|
||||
axis.processData(this);
|
||||
},
|
||||
|
||||
updateRadialAxis: function (axis) {
|
||||
axis.processData(this);
|
||||
},
|
||||
|
||||
coordinateX: function () {
|
||||
return this.coordinate('X', 0, 2);
|
||||
},
|
||||
|
||||
coordinateY: function () {
|
||||
return this.coordinate('Y', 1, 2);
|
||||
},
|
||||
|
||||
updateCenter: function (center) {
|
||||
this.setStyle({
|
||||
translationX: center[0] + this.getOffsetX(),
|
||||
translationY: center[1] + this.getOffsetY()
|
||||
});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
updateRadius: function (radius) {
|
||||
this.setStyle({
|
||||
endRho: radius
|
||||
});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
updateRotation: function (rotation) {
|
||||
this.setStyle({
|
||||
rotationRads: rotation
|
||||
});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
updateTotalAngle: function (totalAngle) {
|
||||
this.processData();
|
||||
},
|
||||
|
||||
getItemForPoint: function (x, y) {
|
||||
var me = this,
|
||||
sprite = me.sprites && me.sprites[0],
|
||||
attr = sprite.attr,
|
||||
dataX = attr.dataX,
|
||||
dataY = attr.dataY,
|
||||
centerX = attr.centerX,
|
||||
centerY = attr.centerY,
|
||||
minX = attr.dataMinX,
|
||||
maxX = attr.dataMaxX,
|
||||
maxY = attr.dataMaxY,
|
||||
endRho = attr.endRho,
|
||||
startRho = attr.startRho,
|
||||
baseRotation = attr.baseRotation,
|
||||
i, length = dataX.length,
|
||||
store = me.getStore(),
|
||||
marker = me.getMarker(),
|
||||
item, th, r;
|
||||
|
||||
if (sprite && marker) {
|
||||
for (i = 0; i < length; i++) {
|
||||
th = (dataX[i] - minX) / (maxX - minX + 1) * 2 * Math.PI + baseRotation;
|
||||
r = dataY[i] / maxY * (endRho - startRho) + startRho;
|
||||
if (Math.abs(centerX + Math.cos(th) * r - x) < 22 && Math.abs(centerY + Math.sin(th) * r - y) < 22) {
|
||||
item = {
|
||||
series: this,
|
||||
sprite: sprite,
|
||||
index: i,
|
||||
record: store.getData().items[i],
|
||||
field: store.getFields().items[i]
|
||||
};
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.callSuper(arguments);
|
||||
},
|
||||
|
||||
getXRange: function () {
|
||||
return [this.dataRange[0], this.dataRange[2]];
|
||||
},
|
||||
|
||||
getYRange: function () {
|
||||
return [this.dataRange[1], this.dataRange[3]];
|
||||
}
|
||||
}, function () {
|
||||
var klass = this;
|
||||
// TODO: [HACK] Steal from cartesian series.
|
||||
klass.prototype.onAxesChanged = Ext.chart.series.Cartesian.prototype.onAxesChanged;
|
||||
klass.prototype.getSprites = Ext.chart.series.Cartesian.prototype.getSprites;
|
||||
});
|
||||
|
||||
97
OfficeWeb/3rdparty/touch/src/chart/series/Scatter.js
vendored
Normal file
97
OfficeWeb/3rdparty/touch/src/chart/series/Scatter.js
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @class Ext.chart.series.Scatter
|
||||
* @extends Ext.chart.series.Cartesian
|
||||
*
|
||||
* Creates a Scatter Chart. The scatter plot is useful when trying to display more than two variables in the same visualization.
|
||||
* These variables can be mapped into x, y coordinates and also to an element's radius/size, color, etc.
|
||||
* As with all other series, the Scatter Series must be appended in the *series* Chart array configuration. See the Chart
|
||||
* documentation for more information on creating charts. A typical configuration object for the scatter could be:
|
||||
*
|
||||
* @example preview
|
||||
* var chart = new Ext.chart.CartesianChart({
|
||||
* animate: true,
|
||||
* store: {
|
||||
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
||||
* data: [
|
||||
* {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
|
||||
* {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
|
||||
* {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
|
||||
* {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
|
||||
* {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
|
||||
* ]
|
||||
* },
|
||||
* axes: [{
|
||||
* type: 'numeric',
|
||||
* position: 'left',
|
||||
* fields: ['data1'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* },
|
||||
* grid: true,
|
||||
* minimum: 0
|
||||
* }, {
|
||||
* type: 'category',
|
||||
* position: 'bottom',
|
||||
* fields: ['name'],
|
||||
* title: {
|
||||
* text: 'Sample Values',
|
||||
* fontSize: 15
|
||||
* }
|
||||
* }],
|
||||
* series: [{
|
||||
* type: 'scatter',
|
||||
* highlight: {
|
||||
* size: 7,
|
||||
* radius: 7
|
||||
* },
|
||||
* fill: true,
|
||||
* xField: 'name',
|
||||
* yField: 'data3',
|
||||
* marker: {
|
||||
* type: 'circle',
|
||||
* fillStyle: 'blue',
|
||||
* radius: 10,
|
||||
* lineWidth: 0
|
||||
* }
|
||||
* }]
|
||||
* });
|
||||
* Ext.Viewport.setLayout('fit');
|
||||
* Ext.Viewport.add(chart);
|
||||
*
|
||||
* In this configuration we add three different categories of scatter series. Each of them is bound to a different field of the same data store,
|
||||
* `data1`, `data2` and `data3` respectively. All x-fields for the series must be the same field, in this case `name`.
|
||||
* Each scatter series has a different styling configuration for markers, specified by the `marker` object. Finally we set the left axis as
|
||||
* axis to show the current values of the elements.
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.chart.series.Scatter', {
|
||||
|
||||
extend: 'Ext.chart.series.Cartesian',
|
||||
|
||||
alias: 'series.scatter',
|
||||
|
||||
type: 'scatter',
|
||||
seriesType: 'scatterSeries',
|
||||
|
||||
requires: [
|
||||
'Ext.chart.series.sprite.Scatter'
|
||||
],
|
||||
|
||||
config: {
|
||||
itemInstancing: {
|
||||
fx: {
|
||||
customDuration: {
|
||||
translationX: 0,
|
||||
translationY: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
applyMarker: function (marker) {
|
||||
this.getItemInstancing();
|
||||
this.setItemInstancing(marker);
|
||||
}
|
||||
});
|
||||
|
||||
843
OfficeWeb/3rdparty/touch/src/chart/series/Series.js
vendored
Normal file
843
OfficeWeb/3rdparty/touch/src/chart/series/Series.js
vendored
Normal file
@@ -0,0 +1,843 @@
|
||||
/**
|
||||
* Series is the abstract class containing the common logic to all chart series. Series includes
|
||||
* methods from Labels, Highlights, Tips and Callouts mixins. This class implements the logic of
|
||||
* animating, hiding, showing all elements and returning the color of the series to be used as a legend item.
|
||||
*
|
||||
* ## Listeners
|
||||
*
|
||||
* The series class supports listeners via the Observable syntax. Some of these listeners are:
|
||||
*
|
||||
* - `itemmouseup` When the user interacts with a marker.
|
||||
* - `itemmousedown` When the user interacts with a marker.
|
||||
* - `itemmousemove` When the user interacts with a marker.
|
||||
* - (similar `item*` events occur for many raw mouse and touch events)
|
||||
* - `afterrender` Will be triggered when the animation ends or when the series has been rendered completely.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* series: [{
|
||||
* type: 'column',
|
||||
* axis: 'left',
|
||||
* listeners: {
|
||||
* 'afterrender': function() {
|
||||
* console('afterrender');
|
||||
* }
|
||||
* },
|
||||
* xField: 'category',
|
||||
* yField: 'data1'
|
||||
* }]
|
||||
*
|
||||
*/
|
||||
Ext.define('Ext.chart.series.Series', {
|
||||
|
||||
requires: ['Ext.chart.Markers', 'Ext.chart.label.Label'],
|
||||
|
||||
mixins: {
|
||||
observable: 'Ext.mixin.Observable'
|
||||
},
|
||||
|
||||
/**
|
||||
* @property {String} type
|
||||
* The type of series. Set in subclasses.
|
||||
* @protected
|
||||
*/
|
||||
type: null,
|
||||
|
||||
/**
|
||||
* @property {String} seriesType
|
||||
* Default series sprite type.
|
||||
*/
|
||||
seriesType: 'sprite',
|
||||
|
||||
identifiablePrefix: 'ext-line-',
|
||||
|
||||
observableType: 'series',
|
||||
|
||||
config: {
|
||||
/**
|
||||
* @private
|
||||
* @cfg {Object} chart The chart that the series is bound.
|
||||
*/
|
||||
chart: null,
|
||||
|
||||
/**
|
||||
* @cfg {String} title
|
||||
* The human-readable name of the series.
|
||||
*/
|
||||
title: null,
|
||||
|
||||
/**
|
||||
* @cfg {Function} renderer
|
||||
* A function that can be overridden to set custom styling properties to each rendered element.
|
||||
* Passes in (sprite, record, attributes, index, store) to the function.
|
||||
*
|
||||
* @param sprite The sprite affected by the renderer.
|
||||
* @param record The store record associated with the sprite.
|
||||
* @param attributes The list of attributes to be applied to the sprite.
|
||||
* @param index The index of the sprite.
|
||||
* @param store The store used by the series.
|
||||
* @return {*} The resultant attributes.
|
||||
*/
|
||||
renderer: function (sprite, record, attributes, index, store) {
|
||||
return attributes;
|
||||
},
|
||||
|
||||
/**
|
||||
* @cfg {Boolean} showInLegend
|
||||
* Whether to show this series in the legend.
|
||||
*/
|
||||
showInLegend: true,
|
||||
|
||||
//@private triggerdrawlistener flag
|
||||
triggerAfterDraw: false,
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Not supported.
|
||||
*/
|
||||
themeStyle: {},
|
||||
|
||||
/**
|
||||
* @cfg {Object} style Custom style configuration for the sprite used in the series.
|
||||
*/
|
||||
style: {},
|
||||
|
||||
/**
|
||||
* @cfg {Object} subStyle This is the cyclic used if the series has multiple sprites.
|
||||
*/
|
||||
subStyle: {},
|
||||
|
||||
/**
|
||||
* @cfg {Array} colors
|
||||
* An array of color values which will be used, in order, as the pie slice fill colors.
|
||||
*/
|
||||
colors: null,
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @cfg {Object} store The store of values used in the series.
|
||||
*/
|
||||
store: null,
|
||||
|
||||
/**
|
||||
* @cfg {Object} label
|
||||
* The style object for labels.
|
||||
*/
|
||||
label: {textBaseline: 'middle', textAlign: 'center', font: '14px Helvetica'},
|
||||
|
||||
/**
|
||||
* @cfg {Number} labelOverflowPadding
|
||||
* Extra distance value for which the labelOverflow listener is triggered.
|
||||
*/
|
||||
labelOverflowPadding: 5,
|
||||
|
||||
/**
|
||||
* @cfg {String} labelField
|
||||
* The store record field name to be used for the series labels.
|
||||
*/
|
||||
labelField: null,
|
||||
|
||||
/**
|
||||
* @cfg {Object} marker
|
||||
* The sprite template used by marker instances on the series.
|
||||
*/
|
||||
marker: null,
|
||||
|
||||
/**
|
||||
* @cfg {Object} markerSubStyle
|
||||
* This is cyclic used if series have multiple marker sprites.
|
||||
*/
|
||||
markerSubStyle: null,
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @cfg {Object} itemInstancing The sprite template used to create sprite instances in the series.
|
||||
*/
|
||||
itemInstancing: null,
|
||||
|
||||
/**
|
||||
* @cfg {Object} background Sets the background of the surface the series is attached.
|
||||
*/
|
||||
background: null,
|
||||
|
||||
/**
|
||||
* @cfg {Object} highlightItem The item currently highlighted in the series.
|
||||
*/
|
||||
highlightItem: null,
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @cfg {Object} surface The surface that the series is attached.
|
||||
*/
|
||||
surface: null,
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @cfg {Object} overlaySurface The surface that series markers are attached.
|
||||
*/
|
||||
overlaySurface: null,
|
||||
|
||||
/**
|
||||
* @cfg {Boolean|Array} hidden
|
||||
*/
|
||||
hidden: false,
|
||||
|
||||
/**
|
||||
* @cfg {Object} highlightCfg The sprite configuration used when highlighting items in the series.
|
||||
*/
|
||||
highlightCfg: null
|
||||
},
|
||||
|
||||
directions: [],
|
||||
|
||||
sprites: null,
|
||||
|
||||
getFields: function (fieldCategory) {
|
||||
var me = this,
|
||||
fields = [], fieldsItem,
|
||||
i, ln;
|
||||
for (i = 0, ln = fieldCategory.length; i < ln; i++) {
|
||||
fieldsItem = me['get' + fieldCategory[i] + 'Field']();
|
||||
fields.push(fieldsItem);
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
|
||||
updateColors: function (colorSet) {
|
||||
this.setSubStyle({fillStyle: colorSet});
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
applyHighlightCfg: function (highlight, oldHighlight) {
|
||||
return Ext.apply(oldHighlight || {}, highlight);
|
||||
},
|
||||
|
||||
applyItemInstancing: function (instancing, oldInstancing) {
|
||||
return Ext.merge(oldInstancing || {}, instancing);
|
||||
},
|
||||
|
||||
setAttributesForItem: function (item, change) {
|
||||
if (item && item.sprite) {
|
||||
if (item.sprite.itemsMarker && item.category === 'items') {
|
||||
item.sprite.putMarker(item.category, change, item.index, false, true);
|
||||
}
|
||||
if (item.sprite.isMarkerHolder && item.category === 'markers') {
|
||||
item.sprite.putMarker(item.category, change, item.index, false, true);
|
||||
} else if (item.sprite instanceof Ext.draw.sprite.Instancing) {
|
||||
item.sprite.setAttributesFor(item.index, change);
|
||||
} else {
|
||||
|
||||
item.sprite.setAttributes(change);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
applyHighlightItem: function (newHighlightItem, oldHighlightItem) {
|
||||
if (newHighlightItem === oldHighlightItem) {
|
||||
return;
|
||||
}
|
||||
if (Ext.isObject(newHighlightItem) && Ext.isObject(oldHighlightItem)) {
|
||||
if (newHighlightItem.sprite === oldHighlightItem.sprite &&
|
||||
newHighlightItem.index === oldHighlightItem.index
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return newHighlightItem;
|
||||
},
|
||||
|
||||
updateHighlightItem: function (newHighlightItem, oldHighlightItem) {
|
||||
this.setAttributesForItem(oldHighlightItem, {highlighted: false});
|
||||
this.setAttributesForItem(newHighlightItem, {highlighted: true});
|
||||
},
|
||||
|
||||
constructor: function (config) {
|
||||
var me = this;
|
||||
me.getId();
|
||||
me.sprites = [];
|
||||
me.dataRange = [];
|
||||
Ext.ComponentManager.register(me);
|
||||
me.mixins.observable.constructor.apply(me, arguments);
|
||||
},
|
||||
|
||||
applyStore: function (store) {
|
||||
return Ext.StoreManager.lookup(store);
|
||||
},
|
||||
|
||||
getStore: function () {
|
||||
return this._store || this.getChart() && this.getChart().getStore();
|
||||
},
|
||||
|
||||
updateStore: function (newStore, oldStore) {
|
||||
var me = this,
|
||||
chartStore = this.getChart() && this.getChart().getStore();
|
||||
newStore = newStore || chartStore;
|
||||
oldStore = oldStore || chartStore;
|
||||
|
||||
if (oldStore) {
|
||||
oldStore.un('updaterecord', 'onUpdateRecord', me);
|
||||
oldStore.un('refresh', 'refresh', me);
|
||||
}
|
||||
if (newStore) {
|
||||
newStore.on('updaterecord', 'onUpdateRecord', me);
|
||||
newStore.on('refresh', 'refresh', me);
|
||||
me.refresh();
|
||||
}
|
||||
},
|
||||
|
||||
onStoreChanged: function () {
|
||||
var store = this.getStore();
|
||||
if (store) {
|
||||
this.refresh();
|
||||
}
|
||||
},
|
||||
|
||||
coordinateStacked: function (direction, directionOffset, directionCount) {
|
||||
var me = this,
|
||||
store = me.getStore(),
|
||||
items = store.getData().items,
|
||||
axis = me['get' + direction + 'Axis'](),
|
||||
hidden = me.getHidden(),
|
||||
range = {min: 0, max: 0},
|
||||
directions = me['fieldCategory' + direction],
|
||||
fieldCategoriesItem,
|
||||
i, j, k, fields, field, data, dataStart = [], style = {},
|
||||
stacked = me.getStacked(),
|
||||
sprites = me.getSprites();
|
||||
|
||||
if (sprites.length > 0) {
|
||||
for (i = 0; i < directions.length; i++) {
|
||||
fieldCategoriesItem = directions[i];
|
||||
fields = me.getFields([fieldCategoriesItem]);
|
||||
for (j = 0; j < items.length; j++) {
|
||||
dataStart[j] = 0;
|
||||
}
|
||||
for (j = 0; j < fields.length; j++) {
|
||||
style = {};
|
||||
field = fields[j];
|
||||
if (hidden[j]) {
|
||||
style['dataStart' + fieldCategoriesItem] = dataStart;
|
||||
style['data' + fieldCategoriesItem] = dataStart;
|
||||
sprites[j].setAttributes(style);
|
||||
continue;
|
||||
}
|
||||
data = me.coordinateData(items, field, axis);
|
||||
if (stacked) {
|
||||
style['dataStart' + fieldCategoriesItem] = dataStart;
|
||||
dataStart = dataStart.slice(0);
|
||||
for (k = 0; k < items.length; k++) {
|
||||
dataStart[k] += data[k];
|
||||
}
|
||||
style['data' + fieldCategoriesItem] = dataStart;
|
||||
} else {
|
||||
style['dataStart' + fieldCategoriesItem] = dataStart;
|
||||
style['data' + fieldCategoriesItem] = data;
|
||||
}
|
||||
sprites[j].setAttributes(style);
|
||||
if (stacked) {
|
||||
me.getRangeOfData(dataStart, range);
|
||||
} else {
|
||||
me.getRangeOfData(data, range);
|
||||
}
|
||||
}
|
||||
}
|
||||
me.dataRange[directionOffset] = range.min;
|
||||
me.dataRange[directionOffset + directionCount] = range.max;
|
||||
style = {};
|
||||
style['dataMin' + direction] = range.min;
|
||||
style['dataMax' + direction] = range.max;
|
||||
for (i = 0; i < sprites.length; i++) {
|
||||
sprites[i].setAttributes(style);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
coordinate: function (direction, directionOffset, directionCount) {
|
||||
var me = this,
|
||||
store = me.getStore(),
|
||||
items = store.getData().items,
|
||||
axis = me['get' + direction + 'Axis'](),
|
||||
range = {min: Infinity, max: -Infinity},
|
||||
fieldCategory = me['fieldCategory' + direction] || [direction],
|
||||
fields = me.getFields(fieldCategory),
|
||||
i, field, data, style = {},
|
||||
sprites = me.getSprites();
|
||||
if (sprites.length > 0) {
|
||||
for (i = 0; i < fieldCategory.length; i++) {
|
||||
field = fields[i];
|
||||
data = me.coordinateData(items, field, axis);
|
||||
me.getRangeOfData(data, range);
|
||||
style['data' + fieldCategory[i]] = data;
|
||||
}
|
||||
me.dataRange[directionOffset] = range.min;
|
||||
me.dataRange[directionOffset + directionCount] = range.max;
|
||||
style['dataMin' + direction] = range.min;
|
||||
style['dataMax' + direction] = range.max;
|
||||
for (i = 0; i < sprites.length; i++) {
|
||||
sprites[i].setAttributes(style);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* This method will return an array containing data coordinated by a specific axis.
|
||||
* @param items
|
||||
* @param field
|
||||
* @param axis
|
||||
* @return {Array}
|
||||
*/
|
||||
coordinateData: function (items, field, axis) {
|
||||
var data = [],
|
||||
length = items.length,
|
||||
layout = axis && axis.getLayout(),
|
||||
coord = axis ? function (x, field, idx, items) {
|
||||
return layout.getCoordFor(x, field, idx, items);
|
||||
} : function (x) { return +x; },
|
||||
i;
|
||||
for (i = 0; i < length; i++) {
|
||||
data[i] = coord(items[i].data[field], field, i, items);
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
getRangeOfData: function (data, range) {
|
||||
var i, length = data.length,
|
||||
value, min = range.min, max = range.max;
|
||||
for (i = 0; i < length; i++) {
|
||||
value = data[i];
|
||||
if (value < min) {
|
||||
min = value;
|
||||
}
|
||||
if (value > max) {
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
range.min = min;
|
||||
range.max = max;
|
||||
},
|
||||
|
||||
updateLabelData: function () {
|
||||
var me = this,
|
||||
store = me.getStore(),
|
||||
items = store.getData().items,
|
||||
sprites = me.getSprites(),
|
||||
labelField = me.getLabelField(),
|
||||
i, ln, labels;
|
||||
if (sprites.length > 0 && labelField) {
|
||||
labels = [];
|
||||
for (i = 0, ln = items.length; i < ln; i++) {
|
||||
labels.push(items[i].get(labelField));
|
||||
}
|
||||
for (i = 0, ln = sprites.length; i < ln; i++) {
|
||||
sprites[i].setAttributes({labels: labels});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
processData: function () {
|
||||
if (!this.getStore()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var me = this,
|
||||
directions = this.directions,
|
||||
i, ln = directions.length,
|
||||
fieldCategory, axis;
|
||||
for (i = 0; i < ln; i++) {
|
||||
fieldCategory = directions[i];
|
||||
if (me['get' + fieldCategory + 'Axis']) {
|
||||
axis = me['get' + fieldCategory + 'Axis']();
|
||||
if (axis) {
|
||||
axis.processData(me);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (me['coordinate' + fieldCategory]) {
|
||||
me['coordinate' + fieldCategory]();
|
||||
}
|
||||
}
|
||||
me.updateLabelData();
|
||||
},
|
||||
|
||||
applyBackground: function (background) {
|
||||
if (this.getChart()) {
|
||||
this.getSurface().setBackground(background);
|
||||
return this.getSurface().getBackground();
|
||||
} else {
|
||||
return background;
|
||||
}
|
||||
},
|
||||
|
||||
updateChart: function (newChart, oldChart) {
|
||||
var me = this;
|
||||
if (oldChart) {
|
||||
oldChart.un("axeschanged", 'onAxesChanged', me);
|
||||
// TODO: destroy them
|
||||
me.sprites = [];
|
||||
me.setSurface(null);
|
||||
me.setOverlaySurface(null);
|
||||
me.onChartDetached(oldChart);
|
||||
}
|
||||
if (newChart) {
|
||||
me.setSurface(newChart.getSurface(this.getId() + '-surface', 'series'));
|
||||
me.setOverlaySurface(newChart.getSurface(me.getId() + '-overlay-surface', 'overlay'));
|
||||
me.getOverlaySurface().waitFor(me.getSurface());
|
||||
|
||||
newChart.on("axeschanged", 'onAxesChanged', me);
|
||||
if (newChart.getAxes()) {
|
||||
me.onAxesChanged(newChart);
|
||||
}
|
||||
me.onChartAttached(newChart);
|
||||
}
|
||||
|
||||
me.updateStore(me._store, null);
|
||||
},
|
||||
|
||||
onAxesChanged: function (chart) {
|
||||
var me = this,
|
||||
axes = chart.getAxes(), axis,
|
||||
directionMap = {}, directionMapItem,
|
||||
fieldMap = {}, fieldMapItem,
|
||||
directions = this.directions, direction,
|
||||
i, ln, j, ln2, k, ln3;
|
||||
|
||||
for (i = 0, ln = directions.length; i < ln; i++) {
|
||||
direction = directions[i];
|
||||
fieldMap[direction] = me.getFields(me['fieldCategory' + direction]);
|
||||
}
|
||||
|
||||
for (i = 0, ln = axes.length; i < ln; i++) {
|
||||
axis = axes[i];
|
||||
if (!directionMap[axis.getDirection()]) {
|
||||
directionMap[axis.getDirection()] = [axis];
|
||||
} else {
|
||||
directionMap[axis.getDirection()].push(axis);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0, ln = directions.length; i < ln; i++) {
|
||||
direction = directions[i];
|
||||
if (directionMap[direction]) {
|
||||
directionMapItem = directionMap[direction];
|
||||
for (j = 0, ln2 = directionMapItem.length; j < ln2; j++) {
|
||||
axis = directionMapItem[j];
|
||||
if (axis.getFields().length === 0) {
|
||||
me['set' + direction + 'Axis'](axis);
|
||||
} else {
|
||||
fieldMapItem = fieldMap[direction];
|
||||
if (fieldMapItem) {
|
||||
for (k = 0, ln3 = fieldMapItem.length; k < ln3; k++) {
|
||||
if (axis.fieldsMap[fieldMapItem[k]]) {
|
||||
me['set' + direction + 'Axis'](axis);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onChartDetached: function (oldChart) {
|
||||
this.fireEvent("chartdetached", oldChart);
|
||||
},
|
||||
|
||||
onChartAttached: function (chart) {
|
||||
var me = this;
|
||||
me.setBackground(me.getBackground());
|
||||
me.fireEvent("chartattached", chart);
|
||||
me.processData();
|
||||
},
|
||||
|
||||
updateOverlaySurface: function (overlaySurface) {
|
||||
var me = this;
|
||||
if (overlaySurface) {
|
||||
if (me.getLabel()) {
|
||||
me.getOverlaySurface().add(me.getLabel());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
applyLabel: function (newLabel, oldLabel) {
|
||||
if (!oldLabel) {
|
||||
oldLabel = new Ext.chart.Markers({zIndex: 10});
|
||||
oldLabel.setTemplate(new Ext.chart.label.Label(newLabel));
|
||||
} else {
|
||||
oldLabel.getTemplate().setAttributes(newLabel);
|
||||
}
|
||||
return oldLabel;
|
||||
},
|
||||
|
||||
createItemInstancingSprite: function (sprite, itemInstancing) {
|
||||
var me = this,
|
||||
template,
|
||||
markers = new Ext.chart.Markers();
|
||||
|
||||
markers.setAttributes({zIndex: 1e100});
|
||||
var config = Ext.apply({}, itemInstancing);
|
||||
if (me.getHighlightCfg()) {
|
||||
config.highlightCfg = me.getHighlightCfg();
|
||||
config.modifiers = ['highlight'];
|
||||
}
|
||||
markers.setTemplate(config);
|
||||
template = markers.getTemplate();
|
||||
template.setAttributes(me.getStyle());
|
||||
template.fx.on('animationstart', 'onSpriteAnimationStart', this);
|
||||
template.fx.on('animationend', 'onSpriteAnimationEnd', this);
|
||||
sprite.bindMarker("items", markers);
|
||||
|
||||
me.getSurface().add(markers);
|
||||
return markers;
|
||||
},
|
||||
|
||||
getDefaultSpriteConfig: function () {
|
||||
return {
|
||||
type: this.seriesType
|
||||
};
|
||||
},
|
||||
|
||||
createSprite: function () {
|
||||
var me = this,
|
||||
surface = me.getSurface(),
|
||||
itemInstancing = me.getItemInstancing(),
|
||||
marker, config,
|
||||
sprite = surface.add(me.getDefaultSpriteConfig());
|
||||
|
||||
sprite.setAttributes(this.getStyle());
|
||||
|
||||
if (itemInstancing) {
|
||||
sprite.itemsMarker = me.createItemInstancingSprite(sprite, itemInstancing);
|
||||
}
|
||||
|
||||
if (sprite.bindMarker) {
|
||||
if (me.getMarker()) {
|
||||
marker = new Ext.chart.Markers();
|
||||
config = Ext.merge({}, me.getMarker());
|
||||
if (me.getHighlightCfg()) {
|
||||
config.highlightCfg = me.getHighlightCfg();
|
||||
config.modifiers = ['highlight'];
|
||||
}
|
||||
marker.setTemplate(config);
|
||||
marker.getTemplate().fx.setCustomDuration({
|
||||
translationX: 0,
|
||||
translationY: 0
|
||||
});
|
||||
sprite.dataMarker = marker;
|
||||
sprite.bindMarker("markers", marker);
|
||||
me.getOverlaySurface().add(marker);
|
||||
}
|
||||
if (me.getLabelField()) {
|
||||
sprite.bindMarker("labels", me.getLabel());
|
||||
}
|
||||
}
|
||||
|
||||
if (sprite.setDataItems) {
|
||||
sprite.setDataItems(me.getStore().getData());
|
||||
}
|
||||
|
||||
sprite.fx.on('animationstart', 'onSpriteAnimationStart', me);
|
||||
sprite.fx.on('animationend', 'onSpriteAnimationEnd', me);
|
||||
|
||||
me.sprites.push(sprite);
|
||||
|
||||
return sprite;
|
||||
},
|
||||
|
||||
/**
|
||||
* Performs drawing of this series.
|
||||
*/
|
||||
getSprites: Ext.emptyFn,
|
||||
|
||||
onUpdateRecord: function () {
|
||||
// TODO: do something REALLY FAST.
|
||||
this.processData();
|
||||
},
|
||||
|
||||
refresh: function () {
|
||||
this.processData();
|
||||
},
|
||||
|
||||
isXType: function (xtype) {
|
||||
return xtype === 'series';
|
||||
},
|
||||
|
||||
getItemId: function () {
|
||||
return this.getId();
|
||||
},
|
||||
|
||||
applyStyle: function (style, oldStyle) {
|
||||
// TODO: Incremental setter
|
||||
var cls = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias('sprite.' + this.seriesType));
|
||||
if (cls && cls.def) {
|
||||
style = cls.def.normalize(style);
|
||||
}
|
||||
return Ext.apply(oldStyle || Ext.Object.chain(this.getThemeStyle()), style);
|
||||
},
|
||||
|
||||
applyMarker: function (marker, oldMarker) {
|
||||
var type = (marker && marker.type) || (oldMarker && oldMarker.type) || this.seriesType,
|
||||
cls;
|
||||
if (type) {
|
||||
cls = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias('sprite.' + type));
|
||||
if (cls && cls.def) {
|
||||
marker = cls.def.normalize(marker, true);
|
||||
marker.type = type;
|
||||
return Ext.merge(oldMarker || {}, marker);
|
||||
}
|
||||
return Ext.merge(oldMarker || {}, marker);
|
||||
}
|
||||
},
|
||||
|
||||
applyMarkerSubStyle: function (marker, oldMarker) {
|
||||
var type = (marker && marker.type) || (oldMarker && oldMarker.type) || this.seriesType,
|
||||
cls;
|
||||
if (type) {
|
||||
cls = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias('sprite.' + type));
|
||||
if (cls && cls.def) {
|
||||
marker = cls.def.batchedNormalize(marker, true);
|
||||
return Ext.merge(oldMarker || {}, marker);
|
||||
}
|
||||
return Ext.merge(oldMarker || {}, marker);
|
||||
}
|
||||
},
|
||||
|
||||
applySubStyle: function (subStyle, oldSubStyle) {
|
||||
var cls = Ext.ClassManager.get(Ext.ClassManager.getNameByAlias('sprite.' + this.seriesType));
|
||||
if (cls && cls.def) {
|
||||
subStyle = cls.def.batchedNormalize(subStyle, true);
|
||||
return Ext.merge(oldSubStyle || {}, subStyle);
|
||||
}
|
||||
return Ext.merge(oldSubStyle || {}, subStyle);
|
||||
},
|
||||
|
||||
updateHidden: function (hidden) {
|
||||
// TODO: remove this when jacky fix the problem.
|
||||
this.getColors();
|
||||
this.getSubStyle();
|
||||
this.setSubStyle({hidden: hidden});
|
||||
this.processData();
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Number} index
|
||||
* @param {Boolean} value
|
||||
*/
|
||||
setHiddenByIndex: function (index, value) {
|
||||
if (Ext.isArray(this.getHidden())) {
|
||||
this.getHidden()[index] = value;
|
||||
this.updateHidden(this.getHidden());
|
||||
} else {
|
||||
this.setHidden(value);
|
||||
}
|
||||
},
|
||||
|
||||
updateStyle: function () {
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
updateSubStyle: function () {
|
||||
this.doUpdateStyles();
|
||||
},
|
||||
|
||||
doUpdateStyles: function () {
|
||||
var sprites = this.sprites,
|
||||
itemInstancing = this.getItemInstancing(),
|
||||
i = 0, ln = sprites && sprites.length,
|
||||
markerCfg = this.getMarker(),
|
||||
style;
|
||||
for (; i < ln; i++) {
|
||||
style = this.getStyleByIndex(i);
|
||||
if (itemInstancing) {
|
||||
sprites[i].itemsMarker.getTemplate().setAttributes(style);
|
||||
} else {
|
||||
sprites[i].setAttributes(style);
|
||||
}
|
||||
if (markerCfg && sprites[i].dataMarker) {
|
||||
sprites[i].dataMarker.getTemplate().setAttributes(this.getMarkerStyleByIndex(i));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getMarkerStyleByIndex: function (i) {
|
||||
return this.getOverriddenStyleByIndex(i, this.getOverriddenStyleByIndex(i, this.getMarkerSubStyle(), this.getMarker()), this.getStyleByIndex(i));
|
||||
},
|
||||
|
||||
getStyleByIndex: function (i) {
|
||||
return this.getOverriddenStyleByIndex(i, this.getSubStyle(), this.getStyle());
|
||||
},
|
||||
|
||||
getOverriddenStyleByIndex: function (i, subStyle, baseStyle) {
|
||||
var subStyleItem,
|
||||
result = Ext.Object.chain(baseStyle || {});
|
||||
for (var name in subStyle) {
|
||||
subStyleItem = subStyle[name];
|
||||
if (Ext.isArray(subStyleItem)) {
|
||||
result[name] = subStyleItem[i % subStyle[name].length];
|
||||
} else {
|
||||
result[name] = subStyleItem;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* For a given x/y point relative to the main region, find a corresponding item from this
|
||||
* series, if any.
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @param {Object} [target] optional target to receive the result
|
||||
* @return {Object} An object describing the item, or null if there is no matching item. The exact contents of
|
||||
* this object will vary by series type, but should always contain at least the following:
|
||||
*
|
||||
* @return {Ext.data.Model} return.record the record of the item.
|
||||
* @return {Array} return.point the x/y coordinates relative to the chart box of a single point
|
||||
* for this data item, which can be used as e.g. a tooltip anchor point.
|
||||
* @return {Ext.draw.sprite.Sprite} return.sprite the item's rendering Sprite.
|
||||
* @return {Number} return.subSprite the index if sprite is an instancing sprite.
|
||||
*/
|
||||
getItemForPoint: Ext.emptyFn,
|
||||
|
||||
onSpriteAnimationStart: function (sprite) {
|
||||
this.fireEvent('animationstart', sprite);
|
||||
},
|
||||
|
||||
onSpriteAnimationEnd: function (sprite) {
|
||||
this.fireEvent('animationend', sprite);
|
||||
},
|
||||
|
||||
/**
|
||||
* Provide legend information to target array.
|
||||
*
|
||||
* @param {Array} target
|
||||
*
|
||||
* The information consists:
|
||||
* @param {String} target.name
|
||||
* @param {String} target.markColor
|
||||
* @param {Boolean} target.disabled
|
||||
* @param {String} target.series
|
||||
* @param {Number} target.index
|
||||
*/
|
||||
provideLegendInfo: function (target) {
|
||||
target.push({
|
||||
name: this.getTitle() || this.getId(),
|
||||
mark: 'black',
|
||||
disabled: false,
|
||||
series: this.getId(),
|
||||
index: 0
|
||||
});
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
Ext.ComponentManager.unregister(this);
|
||||
var store = this.getStore();
|
||||
if (store && store.getAutoDestroy()) {
|
||||
Ext.destroy(store);
|
||||
}
|
||||
this.setStore(null);
|
||||
this.callSuper();
|
||||
}
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user