Browse files

Docs, added Touch src

  • Loading branch information...
1 parent 5dc5a49 commit 0417ebddf3af9eebaff9c0728d1cee824b874694 Ed Spencer committed Feb 10, 2012
Showing with 34,385 additions and 43 deletions.
  1. +67 −20 app.js
  2. +6 −0 app/model/Picture.js
  3. +4 −7 app/view/Picture.js
  4. +0 −10 app/view/Title.js
  5. +6 −6 index.html
  6. +14,734 −0 touch/sencha-touch-debug.js
  7. +184 −0 touch/src/AbstractComponent.js
  8. +136 −0 touch/src/AbstractManager.js
  9. +60 −0 touch/src/ActionSheet.js
  10. +44 −0 touch/src/Ajax.js
  11. +628 −0 touch/src/Anim.js
  12. +136 −0 touch/src/Audio.js
  13. +768 −0 touch/src/Button.js
  14. +2,552 −0 touch/src/Component.js
  15. +100 −0 touch/src/ComponentManager.js
  16. +523 −0 touch/src/ComponentQuery.js
  17. +1,607 −0 touch/src/Container.js
  18. +1,334 −0 touch/src/DateExtras.js
  19. +160 −0 touch/src/Decorator.js
  20. +97 −0 touch/src/Evented.js
  21. +97 −0 touch/src/History.js
  22. +198 −0 touch/src/Img.js
  23. +14 −0 touch/src/ItemCollection.js
  24. +19 −0 touch/src/Label.js
  25. +210 −0 touch/src/LoadMask.js
  26. +339 −0 touch/src/Map.js
  27. +94 −0 touch/src/Mask.js
  28. +339 −0 touch/src/Media.js
  29. +736 −0 touch/src/MessageBox.js
  30. +210 −0 touch/src/Panel.js
  31. +300 −0 touch/src/SegmentedButton.js
  32. +158 −0 touch/src/Sheet.js
  33. +323 −0 touch/src/Sortable.js
  34. +144 −0 touch/src/Spacer.js
  35. +330 −0 touch/src/Template.js
  36. +23 −0 touch/src/Title.js
  37. +362 −0 touch/src/TitleBar.js
  38. +247 −0 touch/src/Toolbar.js
  39. +193 −0 touch/src/Video.js
  40. +358 −0 touch/src/XTemplate.js
  41. +337 −0 touch/src/XTemplateCompiler.js
  42. +238 −0 touch/src/XTemplateParser.js
  43. +136 −0 touch/src/app/Action.js
  44. +923 −0 touch/src/app/Application.js
  45. +646 −0 touch/src/app/Controller.js
  46. +106 −0 touch/src/app/History.js
  47. +252 −0 touch/src/app/Profile.js
  48. +209 −0 touch/src/app/Route.js
  49. +136 −0 touch/src/app/Router.js
  50. +12 −0 touch/src/behavior/Behavior.js
  51. +72 −0 touch/src/behavior/Draggable.js
  52. 0 touch/src/behavior/Droppable.js
  53. +88 −0 touch/src/behavior/Scrollable.js
  54. 0 touch/src/behavior/Sortable.js
  55. +70 −0 touch/src/behavior/Translatable.js
  56. +891 −0 touch/src/carousel/Carousel.js
  57. +118 −0 touch/src/carousel/Indicator.js
  58. +147 −0 touch/src/carousel/Infinite.js
  59. +12 −0 touch/src/carousel/Item.js
  60. +147 −0 touch/src/core/EventManager.js
  61. +1,294 −0 touch/src/core/Ext-more.js
  62. +614 −0 touch/src/core/Ext.js
  63. +97 −0 touch/src/core/History.js
Sorry, we could not display the entire diff because too many files (323) changed.
View
87 app.js
@@ -1,20 +1,40 @@
+/*
+ * This app uses a Carousel and a JSON-P proxy so make sure they're loaded first
+ */
Ext.require([
'Ext.carousel.Carousel',
'Ext.data.proxy.JsonP'
]);
+/**
+ * Our app is pretty simple - it just grabs the latest images from NASA's Astronomy Picture Of the Day
+ * (http://apod.nasa.gov/apod/astropix.html) and displays them in a Carousel. This file drives most of
+ * the application, but there's also:
+ *
+ * * A Store - app/store/Pictures.js - that fetches the data from the APOD RSS feed
+ * * A Model - app/model/Picture.js - that represents a single image from the feed
+ * * A View - app/view/Picture.js - that displays each image
+ *
+ * Our application's launch function is called automatically when everything is loaded.
+ */
Ext.application({
name: 'apod',
+
models: ['Picture'],
stores: ['Pictures'],
- views: ['Picture', 'Title'],
+ views: ['Picture'],
launch: function() {
- var carousel = Ext.create('Ext.Carousel', {
+ var titleVisible = false,
+ info, carousel;
+
+ /**
+ * The main carousel that drives our app. We're just telling it to use the Pictures store and
+ * to update the info bar whenever a new image is swiped to
+ */
+ carousel = Ext.create('Ext.Carousel', {
store: 'Pictures',
direction: 'horizontal',
- fullscreen: true,
- items: [],
listeners: {
activeitemchange: function(carousel, item) {
@@ -23,9 +43,31 @@ Ext.application({
}
});
- var store = Ext.getStore('Pictures');
+ /**
+ * This is just a reusable Component that we pin to the top of the page. This is hidden by default
+ * and appears when the user taps on the screen. The activeitemchange listener above updates the
+ * content of this Component whenever a new image is swiped to
+ */
+ info = Ext.create('Ext.Component', {
+ cls: 'apod-title',
+ top: 0,
+ left: 0,
+ right: 0
+ });
+
+ //add both of our views to the Viewport so they're rendered and visible
+ Ext.Viewport.add(carousel);
+ Ext.Viewport.add(info);
- store.load(function(pictures) {
+ /**
+ * The Pictures store (see app/store/Pictures.js) is set to not load automatically, so we load it
+ * manually now. This loads data from the APOD RSS feed and calls our callback function once it's
+ * loaded.
+ *
+ * All we do here is iterate over all of the data, creating an apodimage Component for each item.
+ * Then we just add those items to the Carousel and set the first item active.
+ */
+ Ext.getStore('Pictures').load(function(pictures) {
var items = [];
Ext.each(pictures, function(picture) {
@@ -43,20 +85,25 @@ Ext.application({
carousel.setActiveItem(0);
});
- var info = Ext.create('apod.view.Title');
-
- Ext.Viewport.add(info);
-
- var visible = false;
-
- carousel.element.on('tap', function() {
- console.log('feh');
- if (visible) {
- info.element.removeCls('apod-title-visible');
- visible = false;
- } else {
- info.element.addCls('apod-title-visible');
- visible = true;
+ /**
+ * The final thing is to add a tap listener that is called whenever the user taps on the screen.
+ * We do a quick check to make sure they're not tapping on the carousel indicators (tapping on
+ * those indicators moves you between items so we don't want to override that), then either hide
+ * or show the info Component.
+ *
+ * Note that to hide or show this Component we're adding or removing the apod-title-visible class.
+ * If you look at index.html you'll see the CSS rules style the info bar and also cause it to fade
+ * in and out when you tap.
+ */
+ Ext.Viewport.element.on('tap', function(e) {
+ if (!e.getTarget('.x-carousel-indicator')) {
+ if (titleVisible) {
+ info.element.removeCls('apod-title-visible');
+ titleVisible = false;
+ } else {
+ info.element.addCls('apod-title-visible');
+ titleVisible = true;
+ }
}
});
}
View
6 app/model/Picture.js
@@ -1,3 +1,9 @@
+/**
+ * Simple Model that represents an image from NASA's Astronomy Picture Of the Day. The only remarkable
+ * thing about this model is the 'image' field, which uses a regular expression to pull its value out
+ * of the main content of the RSS feed. Ideally the image url would have been presented in its own field
+ * in the RSS response, but as it wasn't we had to use this approach to parse it out
+ */
Ext.define('apod.model.Picture', {
extend: 'Ext.data.Model',
View
11 app/view/Picture.js
@@ -1,3 +1,6 @@
+/**
+ * Very simple specialization of Ext.Img, just saves the apod.model.Picture that was assigned to it
+ */
Ext.define('apod.view.Picture', {
extend: 'Ext.Img',
xtype: 'apodimage',
@@ -6,13 +9,7 @@ Ext.define('apod.view.Picture', {
/**
* @cfg {apod.model.Picture} picture The Picture to show
*/
- picture: null,
-
- /**
- * @private
- * @cfg {Boolean} infoVisible True if Picture information is currently visible
- */
- infoVisible: false
+ picture: null
},
updatePicture: function(picture) {
View
10 app/view/Title.js
@@ -1,10 +0,0 @@
-Ext.define('apod.view.Title', {
- extend: 'Ext.Component',
-
- config: {
- cls: 'apod-title',
- top: 0,
- left: 0,
- right: 0
- }
-});
View
12 index.html
@@ -6,10 +6,14 @@
<link rel="stylesheet" href="touch/resources/css/sencha-touch.css" type="text/css">
<script src='http://src.sencha.io/screen.js'></script>
- <script type="text/javascript" src="touch/sencha-touch.js"></script>
- <script type="text/javascript" src="app-all.js"></script>
+ <script type="text/javascript" src="touch/sencha-touch-debug.js"></script>
+ <script type="text/javascript" src="app.js"></script>
<style type="text/css" media="screen">
+ body {
+ background-color: #000;
+ }
+
.x-img {
background-position: center;
background-color: #000;
@@ -19,10 +23,6 @@
background-color: #000;
}
- body {
- background-color: #000;
- }
-
.x-carousel-indicator-dark span {
background-color: #eee;
opacity: 0.25;
View
14,734 touch/sencha-touch-debug.js
14,734 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
184 touch/src/AbstractComponent.js
@@ -0,0 +1,184 @@
+/**
+ * @private
+ * This is the abstract class for {@link Ext.Component}.
+ *
+ * This should never be overriden.
+ */
+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 (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;
+ }
+});
View
136 touch/src/AbstractManager.js
@@ -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 The scope to execute in. Defaults to `this`.
+ */
+ each: function(fn, scope){
+ this.all.each(fn, scope || this);
+ },
+
+ /**
+ * Gets the number of items in the collection.
+ * @return {Number} The number of items in the collection.
+ */
+ getCount: function(){
+ return this.all.getCount();
+ }
+});
View
60 touch/src/ActionSheet.js
@@ -0,0 +1,60 @@
+/**
+ * {@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: {
+ // @inherit
+ baseCls: Ext.baseCSSPrefix + 'sheet-action',
+
+ // @inherit
+ left: 0,
+
+ // @inherit
+ right: 0,
+
+ // @inherit
+ bottom: 0,
+
+ // @hide
+ centered: false,
+
+ // @inherit
+ height: 'auto',
+
+ // @inherit
+ defaultType: 'button'
+ }
+});
View
44 touch/src/Ajax.js
@@ -0,0 +1,44 @@
+/**
+ * A singleton instance of an {@link Ext.data.Connection}. This class
+ * is used to communicate with your server side code. It can be used as follows:
+ *
+ * Ext.Ajax.request({
+ * url: 'page.php',
+ * params: {
+ * id: 1
+ * },
+ * success: function(response){
+ * var text = response.responseText;
+ * // process server response here
+ * }
+ * });
+ *
+ * Default options for all requests can be set by changing a property on the Ext.Ajax class:
+ *
+ * Ext.Ajax.timeout = 60000; // 60 seconds
+ *
+ * Any options specified in the request method for the Ajax request will override any
+ * defaults set on the Ext.Ajax class. In the code sample below, the timeout for the
+ * request will be 60 seconds.
+ *
+ * Ext.Ajax.timeout = 120000; // 120 seconds
+ * Ext.Ajax.request({
+ * url: 'page.aspx',
+ * timeout: 60000
+ * });
+ *
+ * In general, this class will be used for all Ajax requests in your application.
+ * The main reason for creating a separate {@link Ext.data.Connection} is for a
+ * series of requests that share common settings that are different to all other
+ * requests in the application.
+ */
+Ext.define('Ext.Ajax', {
+ extend: 'Ext.data.Connection',
+ singleton: true,
+
+ /**
+ * @property {Boolean} autoAbort
+ * Whether a new request should abort any pending requests.
+ */
+ autoAbort : false
+});
View
628 touch/src/Anim.js
@@ -0,0 +1,628 @@
+/**
+ * Ext.Anim is used to excute 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.Anim = Ext.extend(Object, {
+ 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;
+
+ Ext.Anim.superclass.constructor.call(this);
+
+ 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;
+ },
+
+ 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];
+ }
+});
+
+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.el;
+ }
+
+ 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
+ * <p>Defines different types of animations. <strong>flip, cube, wipe</strong> animations do not work on Android.</p>
+ * <p>Please refer to {@link Ext.Anim} on how to use animations.</p>
+ * @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,
+ fromOpacity = 1,
+ toOpacity = 1,
+ 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;
+ toOpacity = 0.5;
+ toRotate = -90;
+ } else {
+ origin = '0% 0%';
+ fromZ = elW;
+ fromOpacity = 0.5;
+ 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.
+ * <p>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.</p>
+ */
+ 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
+ })
+};
View
136 touch/src/Audio.js
@@ -0,0 +1,136 @@
+/**
+ * {@link Ext.Audio} is a simple class which provides a container for the [HTML5 Audio element](http://www.w3schools.com/html5/tag_audio.asp).
+ *
+ * ## 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 #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 #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'
+ * }
+ * ]
+ * });
+ *
+ */
+Ext.define('Ext.Audio', {
+ extend: 'Ext.Media',
+ xtype : 'audio',
+
+ config: {
+ // @inherited
+ 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
+ * @markdown
+ */
+ },
+
+ // @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'
+ }]
+});
View
768 touch/src/Button.js
@@ -0,0 +1,768 @@
+/**
+ * {@link Ext.Button} is a simple class to display a button in Sencha Touch. There are various
+ * different styles of {@link Ext.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 an {@link Ext.Button} is it's simplist form:
+ *
+ * var button = Ext.create('Ext.Button', {
+ * text: 'Button'
+ * });
+ *
+ * ## Icons
+ *
+ * You can also create a {@link Ext.Button} with just an icon using the {@link #iconCls}
+ * configuration:
+ *
+ * var iconButton = Ext.create('Ext.Button', {
+ * iconCls: 'refresh',
+ * iconMask: true
+ * });
+ *
+ * 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
+ * - compose
+ * - delete
+ * - organize
+ * - refresh
+ * - reply
+ * - search
+ * - settings
+ * - star
+ * - trash
+ * - maps
+ * - locate
+ * - home
+ *
+ * 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,
+ * 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#$base-color $base-color} (dark blue by default)
+ * - **decline** - red
+ * - **confirm** - green
+ *
+ * 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.
+ *
+ * ## Examples
+ *
+ * This example shows a bunch of icons on the screen in two toolbars. When you click on the center
+ * button, it switches the 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-pressed',
+
+ /**
+ * @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
+ * The CSS class to add to the icon element as allowed by {@link #iconMask}.
+ * @accessor
+ */
+ iconMaskCls: Ext.baseCSSPrefix + 'icon-mask'
+ },
+
+ config: {
+ /**
+ * @cfg {String} badgeText
+ * Optional badge text.
+ * @accessor
+ */
+ badgeText: null,
+
+ /**
+ * @cfg {String} text
+ * The Button text.
+ * @accessor
+ */
+ text: null,
+
+ /**
+ * @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,
+
+ /**
+ * @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`, `botom`, `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 {@link #iconMaskCls} 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', 'back', 'round', 'action', 'confirm' and 'forward'.
+ * @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
+ */
+
+ // @inherit
+ 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',
+ touchmove : 'onTouchMove',
+ 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 (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 element = this.element,
+ pressedDelay = this.getPressedDelay(),
+ pressedCls = this.getPressedCls();
+
+ if (!this.getDisabled()) {
+ this.isPressed = true;
+
+ if (this.hasOwnProperty('releasedTimeout')) {
+ clearTimeout(this.releasedTimeout);
+ delete this.releasedTimeout;
+ }
+
+ if (pressedDelay > 0) {
+ this.pressedTimeout = setTimeout(function() {
+ if (element) {
+ element.addCls(pressedCls);
+ }
+ }, pressedDelay);
+ }
+ else {
+ element.addCls(pressedCls);
+ }
+ }
+ },
+
+ onTouchMove: function(e) {
+ return;
+ },
+
+ // @private
+ onRelease: function(e) {
+ this.fireAction('release', [this, e], 'doRelease');
+ },
+
+ // @private
+ doRelease: function(me, e) {
+ if (!me.isPressed) {
+ return;
+ }
+
+ me.isPressed = true;
+
+ if (me.hasOwnProperty('pressedTimeout')) {
+ clearTimeout(me.pressedTimeout);
+ delete me.pressedTimeout;
+ }
+
+ me.releasedTimeout = setTimeout(function() {
+ if (me && me.element) {
+ me.element.removeCls(me.getPressedCls());
+ }
+ }, 10);
+ },
+
+ // @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.
+ 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;
+ }
+ }
+
+ this.callParent([config]);
+ }
+ });
+
+ //</deprecated>
+});
View
2,552 touch/src/Component.js
@@ -0,0 +1,2552 @@
+(function(clsPrefix) {
+
+/**
+ * Most of the visual classes you interact with in Sencha Touch are Components. Every Component in Sencha Touch is a
+ * subclass of Ext.Component, which means they can all:
+ *
+ * * Render themselves onto the page using a template
+ * * Show and hide themselves at any time
+ * * Center themselves on the screen
+ * * Enable and disable themselves
+ *
+ * They can also do a few more advanced things:
+ *
+ * * Float above other components (windows, message boxes and overlays)
+ * * Change size and position on the screen with animation
+ * * Dock other Components inside themselves (useful for toolbars)
+ * * Align to other components, allow themselves to be dragged around, make their content scrollable & more
+ *
+ * ## Available Components
+ *
+ * There are many components available in Sencha Touch, separated into 4 main groups:
+ *
+ * ### Navigation components
+ * * {@link Ext.Toolbar}
+ * * {@link Ext.Button}
+ * * {@link Ext.TitleBar}
+ * * {@link Ext.SegmentedButton}
+ * * {@link Ext.Title}
+ * * {@link Ext.Spacer}
+ *
+ * ### Store-bound components
+ * * {@link Ext.dataview.DataView}
+ * * {@link Ext.Carousel}
+ * * {@link Ext.List}
+ * * {@link Ext.NestedList}
+ *
+ * ### Form components
+ * * {@link Ext.form.Panel}
+ * * {@link Ext.form.FieldSet}
+ * * {@link Ext.field.Checkbox}
+ * * {@link Ext.field.Hidden}
+ * * {@link Ext.field.Slider}
+ * * {@link Ext.field.Text}
+ * * {@link Ext.picker.Picker}
+ * * {@link Ext.picker.Date}
+ *
+ * ### General components
+ * * {@link Ext.Panel}
+ * * {@link Ext.tab.Panel}
+ * * {@link Ext.Viewport Ext.Viewport}
+ * * {@link Ext.Img}
+ * * {@link Ext.Map}
+ * * {@link Ext.Audio}
+ * * {@link Ext.Video}
+ * * {@link Ext.Sheet}
+ * * {@link Ext.ActionSheet}
+ * * {@link Ext.MessageBox}
+ *
+ *
+ * ## Instantiating Components
+ *
+ * Components are created the same way as all other classes in Sencha Touch - using Ext.create. Here's how we can
+ * create a Text field:
+ *
+ * var panel = Ext.create('Ext.Panel', {
+ * html: 'This is my panel'
+ * });
+ *
+ * This will create a {@link Ext.Panel Panel} instance, configured with some basic HTML content. A Panel is just a
+ * simple Component that can render HTML and also contain other items. In this case we've created a Panel instance but
+ * it won't show up on the screen yet because items are not rendered immediately after being instantiated. This allows
+ * us to create some components and move them around before rendering and laying them out, which is a good deal faster
+ * than moving them after rendering.
+ *
+ * To show this panel on the screen now we can simply add it to the global Viewport:
+ *
+ * Ext.Viewport.add(panel);
+ *
+ * Panels are also Containers, which means they can contain other Components, arranged by a layout. Let's revisit the
+ * above example now, this time creating a panel with two child Components and a hbox layout:
+ *
+ * @example
+ * var panel = Ext.create('Ext.Panel', {
+ * layout: 'hbox',
+ *
+ * items: [
+ * {
+ * xtype: 'panel',
+ * flex: 1,
+ * html: 'Left Panel, 1/3rd of total size',
+ * style: 'background-color: #5E99CC;'
+ * },
+ * {
+ * xtype: 'panel',
+ * flex: 2,
+ * html: 'Right Panel, 2/3rds of total size',
+ * style: 'background-color: #759E60;'
+ * }
+ * ]
+ * });
+ *
+ * Ext.Viewport.add(panel);
+ *
+ * This time we created 3 Panels - the first one is created just as before but the inner two are declared inline using
+ * an xtype. Xtype is a convenient way of creating Components without having to go through the process of using
+ * Ext.create and specifying the full class name, instead you can just provide the xtype for the class inside an object
+ * and the framework will create the components for you.
+ *
+ * We also specified a layout for the top level panel - in this case hbox, which splits the horizontal width of the
+ * parent panel based on the 'flex' of each child. For example, if the parent Panel above is 300px wide then the first
+ * child will be flexed to 100px wide and the second to 200px because the first one was given flex: 1 and the second
+ * flex: 2.
+ *
+ * ## Using xtype
+ *
+ * xtype is an easy way to create Components without using the full class name. This is especially useful when creating
+ * a {@link Ext.Container Container} that contains child Components. An xtype is simply a shorthand way of specifying a
+ * Component - for example you can use xtype: 'panel' instead of typing out Ext.panel.Panel.
+ *
+ * Sample usage:
+ *
+ * @example miniphone
+ * Ext.create('Ext.Container', {
+ * fullscreen: true,
+ * layout: 'fit',
+ *
+ * items: [
+ * {
+ * xtype: 'panel',
+ * html: 'This panel is created by xtype'
+ * },
+ * {
+ * xtype: 'toolbar',
+ * title: 'So is the toolbar',
+ * docked: 'top'
+ * }
+ * ]
+ * });
+ *