diff --git a/.travis.yml b/.travis.yml
index 065e17d82..855feb1f0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
-language: node_js
sudo: false
+language: node_js
node_js:
- - "0.12"
+ - "node"
cache:
directories:
- $HOME/.npm
\ No newline at end of file
diff --git a/docs/external.jsdoc b/docs/external.jsdoc
index 32bfdb9cb..38d0f28f8 100644
--- a/docs/external.jsdoc
+++ b/docs/external.jsdoc
@@ -153,11 +153,27 @@
* @glossary computed_property
*/
+/**
+* Methods and properties marked as private should not be used by developers. They may be changed or
+* removed without notice and their particular implementations should not be relied upon. Kinds and
+* modules marked as private are inteded for use only by the framework.
+*
+* @glossary private
+*/
+
+/**
+* Methods and properties marked as protected should only be used when subclassing a kind. They
+* represent the internal workings of a kind and should not be used by outside kinds. Protected kinds
+* and modules are not intended to be instantiated directly by developers.
+*
+* @glossary protected
+*/
+
///// Internally Documented Links (Glossary) /////
/**
* Binary (bitwise) operations.
-*
+*
* @glossary bitwise
* @see http://www.experts-exchange.com/Programming/Misc/A_1842-Binary-Bit-Flags-Tutorial-and-Usage-Tips.html
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators
@@ -166,7 +182,7 @@
/**
* Strict Equality. This comparison logic ensures not only that the value of the things being
* compared is the same, but also their types.
-*
+*
* @glossary ===
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Using_the_Equality_Operators
*/
@@ -176,25 +192,26 @@
* that don't support a native version of said method, in an effort to bring the
* browser up to the standards of modern browsers. This allows code that expects
* a modern browser to work properly in an older one.
-*
+*
* @glossary polyfill
* @see http://en.wikipedia.org/wiki/Polyfill
*/
/**
* The Document Object Model (DOM) is a programming interface for HTML and XML documents.
+*
* @glossary DOM
* @see https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model
*/
+///// Externally Documented Links /////
+
/**
* Inheritance
* @glossary inheritance
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain
*/
-///// Externally Documented Links /////
-
/**
* Universally Unique Identifier
* @glossary UUID
diff --git a/index.js b/index.js
index ca5e1a50e..b4dc77b26 100644
--- a/index.js
+++ b/index.js
@@ -1,4 +1,4 @@
'use strict';
exports = module.exports = require('./src/options');
-exports.version = '2.6.0-rc.1';
+exports.version = '2.7.0';
diff --git a/package.json b/package.json
index a899b0142..b34c69f1c 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"main": "index.js",
"moduleDir": "src",
"filename": "enyo.js",
- "version": "2.6.0-pre",
+ "version": "2.7.0",
"description": "Enyo is an open source object-oriented JavaScript framework emphasizing encapsulation and modularity. Enyo contains everything you need to create a fast, scalable mobile or web application.",
"homepage": "http://enyojs.com/",
"bugs": "http://jira.enyojs.com/",
@@ -26,12 +26,7 @@
"web": "http://enyojs.com/"
}
],
- "licenses": [
- {
- "type": "Apache-2.0",
- "url": "http://www.apache.org/licenses/LICENSE-2.0"
- }
- ],
+ "license": "Apache-2.0",
"scripts": {
"test": "./node_modules/.bin/gulp"
},
@@ -40,17 +35,17 @@
"url": "http://github.com/enyojs/enyo"
},
"devDependencies": {
- "chai": "^3.2.0",
- "enyo-dev": "^0.5.1",
+ "chai": "^3.5.0",
+ "enyo-dev": "^0.5.2",
"gulp": "^3.9.0",
"gulp-concat": "^2.6.0",
- "gulp-jshint": "^1.11.2",
- "gulp-mocha-phantomjs": "^0.9.0",
- "jshint": "^2.8.0",
- "jshint-stylish": "^2.0.1",
- "mocha": "^2.3.0",
- "sinon": "^1.16.1",
+ "gulp-jshint": "^2.0.0",
+ "gulp-mocha-phantomjs": "^0.10.1",
+ "jshint": "^2.9.1",
+ "jshint-stylish": "^2.1.0",
+ "mocha": "^2.4.4",
+ "sinon": "^1.17.3",
"sinon-chai": "^2.8.0",
- "through2": "^0.6.5"
+ "through2": "^2.0.0"
}
-}
+}
\ No newline at end of file
diff --git a/src/Ajax.js b/src/Ajax.js
index c3e282f41..c2c193d30 100644
--- a/src/Ajax.js
+++ b/src/Ajax.js
@@ -184,7 +184,7 @@ var Ajax = module.exports = kind(
}
utils.mixin(xhr_headers, this.headers);
// don't pass in headers structure if there are no headers defined as this messes
- // up CORS code for IE8-9
+ // up CORS code for IE9
if (utils.keys(xhr_headers).length === 0) {
xhr_headers = undefined;
}
@@ -278,7 +278,7 @@ var Ajax = module.exports = kind(
}
} else {
var text = '';
- // work around IE8-9 bug where accessing responseText will thrown error
+ // work around IE9 bug where accessing responseText will thrown error
// for binary requests.
if (typeof inXhr.responseText === 'string') {
text = inXhr.responseText;
@@ -337,25 +337,27 @@ var Ajax = module.exports = kind(
* @private
*/
updateProgress: function (event) {
- // IE8 doesn't properly support progress events and doesn't pass an object to the
- // handlers so we'll check that before continuing.
- if (event) {
- // filter out 'input' as it causes exceptions on some Firefox versions
- // due to unimplemented internal APIs
- var ev = {};
- for (var k in event) {
- if (k !== 'input') {
- ev[k] = event[k];
- }
+ // filter out 'input' as it causes exceptions on some Firefox versions
+ // due to unimplemented internal APIs
+ var ev = {};
+ for (var k in event) {
+ if (k !== 'input') {
+ ev[k] = event[k];
}
- this.sendProgress(event.loaded, 0, event.total, ev);
}
+ this.sendProgress(event.loaded, 0, event.total, ev);
},
/**
* @private
*/
- statics: {
+ statics: /** @lends module:enyo/Ajax~Ajax */ {
+ /**
+ * Takes an object and converts it to an encoded URI string. NOTE: It does not traverse into
+ * objects or arrays, so nested objects will be rendered as the string 'object Object', which
+ * is not terribly useful.
+ * @public
+ */
objectToQuery: function (/*Object*/ map) {
var enc = encodeURIComponent;
var pairs = [];
diff --git a/src/AjaxSource.js b/src/AjaxSource.js
index 5b2bc00fd..8bac1d4f8 100644
--- a/src/AjaxSource.js
+++ b/src/AjaxSource.js
@@ -11,6 +11,7 @@ var
var
XhrSource = require('./XhrSource'),
Ajax = require('./Ajax'),
+ States = require('./States'),
AjaxProperties = require('./AjaxProperties');
/**
@@ -73,7 +74,7 @@ module.exports = kind(
* @public
*/
commit: function (model, opts) {
- opts.method = model.isNew? 'POST': 'PUT';
+ opts.method = (model.status & States.NEW) ? 'POST': 'PUT';
opts.url = this.buildUrl(model, opts);
opts.postBody = opts.postBody || model.toJSON();
this.go(opts);
diff --git a/src/AnimationSupport/AnimationSupport.js b/src/AnimationSupport/AnimationSupport.js
new file mode 100644
index 000000000..b923fd991
--- /dev/null
+++ b/src/AnimationSupport/AnimationSupport.js
@@ -0,0 +1,308 @@
+require('enyo');
+
+var
+ kind = require('../kind'),
+ scene = require('../scene'),
+ utils = require('../utils');
+
+var extend = kind.statics.extend;
+
+kind.concatenated.push('scene');
+
+var AnimationSupport = {
+
+ id: utils.uid("@"),
+
+ handleLayers: false,
+
+ /**
+ * An exposed property to know if know the animating state of this scene.
+ * 'true' - the scene is asked for animation(doesn't mean animation is happening)
+ * 'false' - the scene is not active(has completed or its actors are not visible)
+ * @type {Boolean}
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ animating: false,
+
+ /**
+ * An exposed property to know if the scene is ready with actors performing action.
+ * 'true' - the scene actors are ready for action
+ * 'false' - some or all actors are not ready
+ * @type {Boolean}
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ active: this && this.generated,
+
+
+ /**
+ * @private
+ */
+ timeline: 0,
+ /**
+ * @private
+ */
+ _cachedValue: 0,
+ /**
+ * @private
+ */
+ speed: 0,
+ /**
+ * @private
+ */
+ seekInterval: 0,
+ /**
+ * @private
+ */
+ repeat: false,
+ /**
+ * @private
+ */
+ cache: function(actor) {
+ actor = actor || this;
+ if(actor.speed === 0){
+ actor.speed = actor._cachedValue;
+ }
+ this.animating = true;
+ },
+
+ /**
+ * Starts the animation of the actor
given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be started.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ play: function (actor) {
+ actor = actor || this;
+ actor.speed = 1;
+ if (isNaN(actor.timeline) || !actor.timeline) {
+ actor.timeline = 0;
+ }
+ this.trigger();
+ actor._cachedValue = actor.speed;
+ this.animating = true;
+ },
+
+ /**
+ * Replays the animation of the actor
given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be started.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ replay: function (actor) {
+ this.stop();
+ this.play();
+ },
+ /**
+ * Resumes the paused animation of the actor
given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be resumed.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ resume: function(actor) {
+ this.cache(actor);
+ actor = actor || this;
+ actor.speed *= 1;
+ },
+
+ /**
+ * Pauses the animation of the actor
given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be paused.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ pause: function (actor) {
+ actor = actor || this;
+ actor._cachedValue = actor.speed;
+ actor.speed = 0;
+ },
+
+ /**
+ * Reverses the animation of the actor
given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be reversed.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ reverse: function (actor) {
+ this.cache(actor);
+ actor = actor || this;
+ actor._cachedValue = actor.speed;
+ actor.speed *= -1;
+ },
+
+ /**
+ * fast description goes here
+ * @param {Number} mul description goes here
+ * @param [Component]{@link module:enyo/Component~Component} actor description goes here
+ * @public
+ */
+ fast: function (mul, actor) {
+ this.cache(actor);
+ actor = actor || this;
+ actor.speed *= mul;
+ },
+
+ /**
+ * slow description goes here
+ * @param {Number} mul description goes here
+ * @param [Component]{@link module:enyo/Component~Component} actor description goes here
+ * @public
+ */
+ slow: function (mul, actor) {
+ this.cache(actor);
+ actor = actor || this;
+ actor.speed *= mul;
+ },
+
+ /**
+ * Changes the speed of the animation.
+ * Speed of the animation changed based on the factor
.
+ * To slow down the speed use values between 0 and 1. For Example 0.5 to reduce the speed by 50%.
+ * To increase the speed use values above 1. For Example 2 to increase the speed by 200%.
+ * Animation will be paused if factor is 0. To pause the animation use {@link enyo/AnimationSupport/Editor.pause pause}
API.
+ * Speed will not be affected incase of negative multiplication factor.
+ * @param {Number} factor Multiplication factor which changes the speed
+ * @param [Component {@link module:enyo/Component~Component}] actor The component whose animating speed should be changed
+ * @public
+ */
+ // speed: function(mul, actor) {
+ // if (mul < 0) return;
+ // this.cache(actor);
+ // actor = actor || this;
+ // actor.speed *= mul;
+ // },
+
+ /**
+ * Stops the animation of the actor given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be stopped.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ stop: function (actor) {
+ actor = actor || this;
+ actor._cachedValue = 1;
+ actor.speed = 0;
+ actor.timeline = 0;
+ // this.animating = false;
+ // this.cancel();
+ },
+
+ /**
+ * Seeks the animation of the actor
to the position provided in seek
+ * The value of seek
should be between 0 to duration
of the animation.
+ * @param {Number} seek Value in seek where the animation has to be seeked
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ seek: function(seek, actor) {
+ actor = actor || this;
+ actor.timeline = seek;
+ },
+
+ /**
+ * Seeks actor
with animation to the position provided in seek
+ * The value of seek
should be between 0 to duration
of the animation.
+ * @param {Number} seek Value in seek where the animation has to be seeked
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ seekAnimate: function(seek, actor) {
+ actor = actor || this;
+ if (seek >= 0 ) {
+ if (!this.animating)
+ this.play(actor);
+ actor.speed = 1;
+ }else{
+ actor.speed = -1;
+ }
+ actor.seekInterval = actor.timeline + seek;
+ if (actor.seekInterval < 0) {
+ actor.speed = 0;
+ actor.seekInterval = 0;
+ }
+ },
+
+ //TODO: Move these events to Event Delegator
+ /**
+ * Event to identify when the scene has done animating.
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ completed: function() {},
+
+ /**
+ * Event to identify when the scene has done a step(rAF updatation of time) in the animation.
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ step: function() {}
+};
+
+module.exports = AnimationSupport;
+
+/**
+ * Adds animation from a scene to other scene
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ * @return {Object} An instance of the constructor
+ */
+function sceneToScene (src) {
+ if (!src) return;
+ if (!src.id) extend(AnimationSupport, src);
+
+ var i, l = src.length(),
+ anim;
+
+ for (i = 0; i < l; i++) {
+ anim = utils.mixin({}, src.getAnimation(i));
+ this.addAnimation(anim.animate, anim.animate.duration);
+ }
+
+ var span = src.span + this.span;
+ src.rolePlays.push({
+ actor: this,
+ span: span,
+ dur: this.span
+ });
+ return this;
+}
+
+/**
+ * Add animations within a scene
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ * @return {Object} An instance of the constructor
+ */
+function updateScene (props) {
+ if (!props) return;
+
+ var anims = utils.isArray(props) ? props : [props];
+ for (var i = 0; i < anims.length; i++) {
+ this.addAnimation(anims[i], anims[i].duration || 0);
+ }
+ return this;
+}
+
+
+
+/**
+ Hijacking original behaviour as in other Enyo supports.
+*/
+var sup = kind.concatHandler;
+
+/**
+* @private
+*/
+kind.concatHandler = function (ctor, props, instance) {
+ sup.call(this, ctor, props, instance);
+ if (props.scene) {
+ var fn,
+ proto = ctor.prototype || ctor,
+ sctor = scene.create(proto);
+
+ extend(AnimationSupport, sctor);
+ fn = props.scene.isScene ? sceneToScene : updateScene;
+ proto.scene = fn.call(sctor, props.scene);
+ }
+};
\ No newline at end of file
diff --git a/src/AnimationSupport/Director.js b/src/AnimationSupport/Director.js
deleted file mode 100644
index 719199534..000000000
--- a/src/AnimationSupport/Director.js
+++ /dev/null
@@ -1,169 +0,0 @@
-require('enyo');
-
-var tween = require('./Tween'),
- utils = require('../utils');
-
-var pose, dur, tm, t;
-
-/**
-* Contains the declaration for the {@link module:enyo/AnimationSupport/Director} module.
-* This modules exposes the features to support 'Director' approach.
-* @module enyo/AnimationSupport/Director
-*/
-module.exports = {
-
- /**
- * This method checks if all the actors of the given {@link @module enyo/AnimationSupport/Scene} object
- * is rendered. If the actors are rendered then all them are initialized and prepared to be ready for animation.
- * @param {@link @module enyo/AnimationSupport/Scene} scene Scene which contains actors to be prepared for animation.
- * @return {boolean} Returns true
if all the actors
- * of the scene is active and ready for action,
- * otherwise false
- */
- roll: function (scene) {
- var actor,
- actors = scene.rolePlays ? scene.rolePlays[scene.getID()]: [],
- l = actors ? actors.length: 0,
- active = true;
-
- for (var i = 0; i < l; i++) {
- actor = actors[i];
- if(actor.generated) {
- tween.init(actor);
- active = false;
- }
- }
- scene.active = active;
- },
-
- /**
- * take
method is invloved in time based animation. This method will
- * be executed continuously in order tween the actor for every frame until the animation
- * is completed (i.e. until elapsed time is equal to the duration).
- * be animated based on the delta and the acceleration.
- * @param {@link @module enyo/AnimationSupport/Scene} scene Scene on which the animation will be performed
- * @param {Number} ts Elapsed time since the animation of this pose has started (ratio in factor of 1)
- */
- take: function (scene, ts) {
- dur = scene.span;
- tm = scene.timeline;
-
- if (isNaN(tm) || tm < 0) return;
- if (tm <= dur) {
- pose = scene.action(ts, pose);
- } else {
- scene.timeline = dur;
- scene.animating = false;
- }
- },
-
- /**
- * action
is the primary method which triggers the animation of the actor for every frame.
- * This method calculates the start and end animation positions and the elapsed time since the animation
- * has started and tweens the actor based on the these values.
- * @param {Object} pose Animation poses
- * @param {@link module:enyo/Component~Component} actor Component
on which the animation should be performed
- * @param {Number} since Elapsed time since the animation of this pose has started
- * @param {Number} dur Total duration of this pose
- */
- action: function (pose, actor, since, dur) {
- if (!pose._startAnim) tween.init(actor, pose);
-
- if (since < 0) since = 0;
- if (since <= dur && dur !== 0) {
- t = since / dur;
- tween.step(actor, pose, ( t > 0.98) ? 1 : t, dur);
- } else {
- tween.step(actor, pose, 1, dur);
- }
- },
-
- /**
- * Casts an actor or all the actors in the array to the given scene.
- * @param {@link module:enyo/Component~Component} actors actor or Array of actors which needs to be casted in the scene.
- * @param {@link @module enyo/AnimationSupport/Scene} scene Scene to which the actors has to be connected.
- */
- cast: function (actors, scene) {
- var acts = utils.isArray(actors) ? actors : [actors],
- id = scene.getID(),
- rolePlays = scene.rolePlays || {};
-
- if (!rolePlays[id]) {
- rolePlays[id] = acts;
- } else {
- rolePlays[id] = acts.reduce(function(actors, actor) {
- actors.push( actor );
- return actors;
- }, rolePlays[id]);
- }
- scene.rolePlays = rolePlays;
- },
-
- /**
- * Disconnects actor or Array of actors from the scene
- * @param {Array.} actors actor or Array of actors which needs to be casted in the scene.
- * @param {@link @module enyo/AnimationSupport/Scene} scene Scene from which the actors has to be removed.
- */
- reject: function (scene, actors) {
- var id = scene.getID(), acts,
- rolePlays = scene.rolePlays || [];
- actors = actors || rolePlays[id];
- acts = utils.isArray(actors) ? actors : [actors];
- if (rolePlays[id]) {
- rolePlays[id] = acts.reduce(function(actors, actor) {
- var i = actors.indexOf(actor);
- if (i >= 0) actors.splice(i, 1);
- return actors;
- }, rolePlays[id]);
- }
- scene.rolePlays = rolePlays;
- },
-
- /**
- * shot
method is invloved in distance based animation in which the distance definite and
- * indefinite (Event based animations). This method calculates the distance to which the actor has to
- * be animated based on the delta and the acceleration.
- * @param {@link module:enyo/Component~Component} actor Component
on which the animation should be performed
- * @param {Number} ts delta distance
- * @return {Number} The distance to which the actor has to be transformed
- */
- shot: function(actor, ts) {
- var v1, s, a, v = 0,
- t = ts,
- dt = actor.getAnimationDelta(),
- dir = this.angle(actor.direction),
- v0 = dt.velocity || 0;
-
- v1 = dt[dir] / t;
- if (v1 === 0) {
- dt[dir] = 0;
- dt.velocity = 0;
- } else {
- a = (v1 - v0) / t;
- s = 0.5 * a * t * t;
- v = (a < 0 ? -s : s);
- dt[dir] = dt[dir] - v;
- if (a > -0.001 && a < 0.001) {
- dt[dir] = 0;
- }
- dt.velocity = v1;
- }
- return dt[dir] > 0 ? v : -v;
- },
-
- /**
- * @private
- */
- angle: function (direction) {
- switch(direction) {
- case "X" :
- return "dX";
- case "Y" :
- return "dY";
- case "Z" :
- return "dZ";
- default:
- return "dX";
- }
- }
-};
\ No newline at end of file
diff --git a/src/AnimationSupport/Easings.js b/src/AnimationSupport/Easings.js
deleted file mode 100644
index 8ec19ab99..000000000
--- a/src/AnimationSupport/Easings.js
+++ /dev/null
@@ -1,635 +0,0 @@
-/**
- * Beginning time
- * @type {number}
- */
-var b = 0,
- /**
- * Change in time
- * @type {number}
- */
- c = 1,
- temp = null,
- tempProp = null,
- tempOldState = [],
- tempNewState = [];
-/**
- * This module provdes an interface to achieve various types of Easings in animations
- *
- * @module enyo/AnimationSupport/Easings
- */
-var easings = module.exports = {
-
- /**
- * Use this function to check whether the ease object has changed or not.
- * @public
- * @param {object} currentEase - ease object which we want to check
- * @return {boolean} - Boolean value for easechanged.
- * True - Yes. The ease object got changed.
- * False - No. The ease object has not changed.
- */
- easeChanged: function(currentEase) {
-
- if (temp === null) { // setting the values for the first time
- temp = currentEase;
- return false;
- } else {
-
- if (JSON.stringify(temp) === JSON.stringify(currentEase)) { // compare the values
- return false;
- } else {
- temp = currentEase;
- return true;
- }
-
- }
- },
-
- /**
- * Use this function to check whether the animating property of the object has changed or not
- * @public
- * @param {string} currentProp - Name of the animating property like - "Translate/Opacity/Scale/Rotate"
- * @return {boolean} - Boolean value for propChange. Either True or False
- */
- propChange: function(currentProp) {
-
- if (tempProp === null) { // setting the values for the first time
- tempProp = currentProp;
- return false;
- } else {
-
- if (tempProp === currentProp) { // compare the values
- return false;
- } else {
- tempProp = currentProp;
- return true;
- }
-
- }
- },
-
- /**
- * Use this function to check whether the oldState of the object has changed or not
- * @public
- * @param {object} currentOldState - currentOldState object
- * @return {boolean} - Boolean value for oldStateChange. Either True or False
- */
- oldStateChange: function(currentOldState) {
-
- if (tempOldState === null) { // setting the values for the first time
- tempOldState = currentOldState;
- return false;
- } else {
- var compareValue = easings.compareStates(tempOldState, currentOldState);
- if (compareValue === true) { // compare the values
- return false;
- } else {
- tempOldState = currentOldState;
- return true;
- }
-
- }
-
- },
-
- /**
- * Use this function to check whether the newStateChange of the object has changed or not
- * @public
- * @param {object} currentNewState -currentNewState object
- * @return {boolean} - Boolean value for newStateChange. Either True or False
- */
- newStateChange: function(currentNewState) {
-
- if (tempNewState === null) { // setting the values for the first time
- tempNewState = currentNewState;
- return false;
- } else {
- var compareValue = easings.compareStates(tempNewState, currentNewState);
- if (compareValue === true) { // compare the values
- return false;
- } else {
- tempNewState = currentNewState;
- return true;
- }
-
- }
-
- },
-
- /**
- * Use this function to compare the states which are arrays
- * @public
- * @param {Number[]} x - old array of the same
- * @param {Number[]} y - current array of the same
- * @return {boolean} - True/ False after comparing the parameters
- */
- compareStates: function(x, y) {
- var xLen = x.length;
- var yLen = y.length;
- if (xLen != yLen) {
- return false;
- }
- for (var i = 0; i < xLen; i++) {
- if (x[i] instanceof Array && y[i] instanceof Array) {
- // recurse into the nested arrays
- if (x[i].length != y[i].length) {
- return false;
- }
- var recursiveValue = easings.compareStates(x[i], y[i]);
- if (recursiveValue === false) {
- return false;
- }
- } else {
- if (x[i] != y[i]) {
- return false;
- }
- }
- }
- return true;
- },
-
- /**
- * This function returns the coefficents based on the order and the current position
- * @private
- * @param {number} n - order
- * @param {number} k - current position
- * @return {object} - coefficients
- */
- getCoeff: function(n, k) {
- n = parseInt(n, 10);
- k = parseInt(k, 10);
- // Credits
- // https://math.stackexchange.com/questions/202554/how-do-i-compute-binomial-coefficients-efficiently#answer-927064
- if (isNaN(n) || isNaN(k))
- return void 0;
- if ((n < 0) || (k < 0))
- return void 0;
- if (k > n)
- return void 0;
- if (k === 0)
- return 1;
- if (k === n)
- return 1;
- if (k > n / 2)
- return this.getCoeff(n, n - k);
-
- return n * this.getCoeff(n - 1, k - 1) / k;
- },
-
- /**
- * Function to get the bezier coeffients based on the time and order
- * @public
- * @param {number} t - time
- * @param {number} n - order
- * @return {object} - bezier coefficients
- */
- getBezierValues: function(t, n) {
- t = parseFloat(t, 10),
- n = parseInt(n, 10);
-
- if (isNaN(t) || isNaN(n))
- return void 0;
- if ((t < 0) || (n < 0))
- return void 0;
- if (t > 1)
- return void 0;
-
- var c,
- values = [],
-
- x = (1 - t),
- y = t;
- //
- // Binomial theorem to expand (x+y)^n
- //
- for (var k = 0; k <= n; k++) {
- c = this.getCoeff(n, k) * Math.pow(x, (n - k)) * Math.pow(y, k);
- values.push(c);
- }
-
- return values;
- },
-
- /**
- * Current time multiplied with duration
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} - time
- */
- timeCheck: function(t, d) {
- t = t * d;
- return t;
- },
-
- /**
- * EaseInQuad
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} - calculated time
- */
- easeInQuad: function(t, d) {
- t = easings.timeCheck(t, d);
- return c * (t /= d) * t + b;
- },
-
- /**
- * EaseOutQuad
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeOutQuad: function(t, d) {
- t = easings.timeCheck(t, d);
- return -c * (t /= d) * (t - 2) + b;
- },
-
- /**
- * EaseInOutQuad
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInOutQuad: function(t, d) {
- t = easings.timeCheck(t, d);
- if ((t /= d / 2) < 1) return c / 2 * t * t + b;
- return -c / 2 * ((--t) * (t - 2) - 1) + b;
- },
-
- /**
- * EaseInCubic
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInCubic: function(t, d) {
- t = easings.timeCheck(t, d);
- return c * (t /= d) * t * t + b;
- },
-
- /**
- * EaseOutCubic
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeOutCubic: function(t, d) {
- t = easings.timeCheck(t, d);
- return c * ((t = t / d - 1) * t * t + 1) + b;
- },
-
- /**
- * EaseInOutCubic
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInOutCubic: function(t, d) {
- t = easings.timeCheck(t, d);
- if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
- return c / 2 * ((t -= 2) * t * t + 2) + b;
- },
-
- /**
- * EaseInQuart
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInQuart: function(t, d) {
- t = easings.timeCheck(t, d);
- return c * (t /= d) * t * t * t + b;
- },
-
- /**
- * EaseOutQuart
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeOutQuart: function(t, d) {
- t = easings.timeCheck(t, d);
- return -c * ((t = t / d - 1) * t * t * t - 1) + b;
- },
-
- /**
- * EaseInOutQuart
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInOutQuart: function(t, d) {
- t = easings.timeCheck(t, d);
- if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
- return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
- },
-
- /**
- * EaseInQuint
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInQuint: function(t, d) {
- t = easings.timeCheck(t, d);
- return c * (t /= d) * t * t * t * t + b;
- },
- /**
- * EaseOutQuint
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeOutQuint: function(t, d) {
- t = easings.timeCheck(t, d);
- return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
- },
-
- /**
- * EaseInOutQuint
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInOutQuint: function(t, d) {
- t = easings.timeCheck(t, d);
- if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
- return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
- },
-
- /**
- * EaseInSine
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInSine: function(t, d) {
- t = easings.timeCheck(t, d);
- return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
- },
-
- /**
- * EaseOutSine
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeOutSine: function(t, d) {
- t = easings.timeCheck(t, d);
- return c * Math.sin(t / d * (Math.PI / 2)) + b;
- },
-
- /**
- * EaseInOutSine
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInOutSine: function(t, d) {
- t = easings.timeCheck(t, d);
- return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
- },
-
- /**
- * EaseInExpo
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInExpo: function(t, d) {
- t = easings.timeCheck(t, d);
- return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
- },
-
- /**
- * EaseOutExpo
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeOutExpo: function(t, d) {
- t = easings.timeCheck(t, d);
- return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
- },
-
- /**
- * EaseInOutExpo
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInOutExpo: function(t, d) {
- t = easings.timeCheck(t, d);
- if (t === 0) return b;
- if (t === d) return b + c;
- if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
- return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
- },
-
- /**
- * EaseInCirc
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInCirc: function(t, d) {
- t = easings.timeCheck(t, d);
- return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
- },
-
- /**
- * EaseOutCirc
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeOutCirc: function(t, d) {
- t = easings.timeCheck(t, d);
- return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
- },
-
- /**
- * EaseInOutCirc
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInOutCirc: function(t, d) {
- t = easings.timeCheck(t, d);
- if ((t /= d / 2) < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
- return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
- },
-
- /**
- * EaseInElastic
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInElastic: function(t, d) {
- var a = c,
- p = 0,
- s = 1.70158;
- t = easings.timeCheck(t, d);
- if (t === 0) return b;
- if ((t /= d) === 1) return b + c;
- if (!p) p = d * 0.3;
- if (a < Math.abs(c)) {
- a = c;
- s = p / 4;
- } else s = p / (2 * Math.PI) * Math.asin(c / a);
- return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
- },
-
- /**
- * EaseOutElastic
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeOutElastic: function(t, d) {
- var a = c,
- p = 0,
- s = 1.70158;
- t = easings.timeCheck(t, d);
- if (t === 0) return b;
- if ((t /= d) === 1) return b + c;
- if (!p) p = d * 0.3;
- if (a < Math.abs(c)) {
- a = c;
- s = p / 4;
- } else s = p / (2 * Math.PI) * Math.asin(c / a);
- return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
- },
-
- /**
- * EaseInOutElastic
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInOutElastic: function(t, d) {
- var a = c,
- p = 0,
- s = 1.70158;
- t = easings.timeCheck(t, d);
- if (t === 0) return b;
- if ((t /= d / 2) === 2) return b + c;
- if (!p) p = d * (0.3 * 1.5);
- if (a < Math.abs(c)) {
- a = c;
- s = p / 4;
- } else s = p / (2 * Math.PI) * Math.asin(c / a);
- if (t < 1) return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
- return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
- },
-
- /**
- * EaseInBack
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInBack: function(t, d, s) {
- t = easings.timeCheck(t, d);
- if (!s) s = 1.70158;
- return c * (t /= d) * t * ((s + 1) * t - s) + b;
- },
-
- /**
- * EaseOutBack
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeOutBack: function(t, d, s) {
- t = easings.timeCheck(t, d);
- if (s === undefined) s = 1.70158;
- return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
- },
-
- /**
- * EaseInOutBack
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInOutBack: function(t, d, s) {
- t = easings.timeCheck(t, d);
- if (s === undefined) s = 1.70158;
- if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
- return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
- },
-
- /**
- * EaseInBounce
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInBounce: function(t, d) {
- t = easings.timeCheck(t, d);
- return c - easings.easeOutBounce((d - t) / d, d) + b;
- },
-
- /**
- * EaseOutBounce
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeOutBounce: function(t, d) {
- t = easings.timeCheck(t, d);
- if ((t /= d) < (1 / 2.75)) {
- return c * (7.5625 * t * t) + b;
- } else if (t < (2 / 2.75)) {
- return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
- } else if (t < (2.5 / 2.75)) {
- return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
- } else {
- return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
- }
- },
-
- /**
- * EaseInOutBounce
- * @public
- * @param {number} t - current time
- * @param {number} d - duration
- * @return {number} calculated time
- */
- easeInOutBounce: function(t, d) {
- t = easings.timeCheck(t, d);
- if (t < d / 2) return easings.easeInBounce((t * 2) / d, d) * 0.5 + b;
- return easings.easeOutBounce((t * 2 - d) / d, d) * 0.5 + c * 0.5 + b;
- }
-
-};
diff --git a/src/AnimationSupport/Frame.js b/src/AnimationSupport/Frame.js
deleted file mode 100644
index 57a3a2bb5..000000000
--- a/src/AnimationSupport/Frame.js
+++ /dev/null
@@ -1,398 +0,0 @@
-/*jslint white: true*/
-require('enyo');
-
-var
- Dom = require('../dom'),
- Vector = require('./Vector'),
- utils = require('../utils'),
- Matrix = require('./Matrix');
-
-var
- COLOR = {color: 1, backgroundColor: 1},
- INT_UNIT = {zIndex: 1},
- TRANSFORM = {translate: 1, translateX: 1, translateY: 1, translateZ: 1, rotateX: 1, rotateY: 1, rotateZ: 1, rotate: 1, skew: 1, scale: 1, perspective: 1};
-
-/**
- * Frame is a module responsible for providing animation features required for a frame.
- * This module exposes bunch of animation API's like matrix calculation,
- * fetching initial DOM properties and also applying style updates to DOM.
- *
- * These methods need to be merged with DOM API's of enyo.
- *
- * @module enyo/AnimationSupport/Frame
- */
-var frame = module.exports = {
- /**
- * Calculate matrix3d of a frame based on transformation vectors.
- * @public
- * @param {Number[]} trns Translate vector
- * @param {Number[]} rot Rotate quaternion vector
- * @param {Number[]} sc Scale vector
- * @param {Number[]} sq Skew vector
- * @param {Number[]} per Perspective vector
- * @return {Number[]} Final Matrix3d for particular frame
- */
- recomposeMatrix: function (trns, rot, sc, sq, per) {
- var i,
- x = rot[0],
- y = rot[1],
- z = rot[2],
- w = rot[3],
- m = Matrix.identity(),
- sM = Matrix.identity(),
- rM = Matrix.identity();
-
- // apply perspective
- if(per) {
- m[3] = per[0];
- m[7] = per[1];
- m[11] = per[2];
- m[15] = per[3];
- }
-
- m[12] = trns[0];
- m[13] = trns[1];
- m[14] = trns[2];
-
- // apply rotate
- rM[0] = 1 - 2 * (y * y + z * z);
- rM[1] = 2 * (x * y - z * w);
- rM[2] = 2 * (x * z + y * w);
- rM[4] = 2 * (x * y + z * w);
- rM[5] = 1 - 2 * (x * x + z * z);
- rM[6] = 2 * (y * z - x * w);
- rM[8] = 2 * (x * z - y * w);
- rM[9] = 2 * (y * z + x * w);
- rM[10] = 1 - 2 * (x * x + y * y);
-
- m = Matrix.multiply(m, rM);
-
- // apply skew
- if (sq[2]) {
- sM[9] = sq[2];
- m = Matrix.multiply(m, sM);
- }
-
- if (sq[1]) {
- sM[9] = 0;
- sM[8] = sq[1];
- m = Matrix.multiply(m, sM);
- }
-
- if (sq[0]) {
- sM[8] = 0;
- sM[4] = sq[0];
- m = Matrix.multiply(m, sM);
- }
-
- // apply scale
- for (i = 0; i < 12; i += 4) {
- m[0 + i] *= sc[0];
- m[1 + i] *= sc[1];
- m[2 + i] *= sc[2];
- }
- return m;
- },
-
- /**
- * Decompose transformation vectors into various properties out of matrix3d.
- * @public
- * @param {Number[]} matrix Matrix3d
- * @param {Object} ret To store various transformation properties like translate, rotate, scale, skew and perspective.
- * @return {Boolean} true, if matrix exists else false.
- */
- decomposeMatrix: function (matrix, ret) {
- var i,
- tV = [],
- rV = [],
- pV = [],
- skV = [],
- scV = [],
- row = [],
- pdum3 = {};
-
- if (matrix[15] === 0) return false;
-
- for (i = 0; i < 16; i++)
- matrix[0] /= matrix[15];
-
- //TODO: decompose perspective
- pV = [0, 0, 0, 0];
-
- for (i = 0; i < 3; i++)
- tV[i] = matrix[12 + i];
-
- for (i = 0; i < 12; i += 4) {
- row.push([
- matrix[0 + i],
- matrix[1 + i],
- matrix[2 + i]
- ]);
- }
-
- scV[0] = Vector.len(row[0]);
- row[0] = Vector.normalize(row[0]);
- skV[0] = Vector.dot(row[0], row[1]);
- row[1] = Vector.combine(row[1], row[0], 1.0, -skV[0]);
-
- scV[1] = Vector.len(row[1]);
- row[1] = Vector.normalize(row[1]);
- skV[0] /= scV[1];
-
- // Compute XZ and YZ shears, orthogonalized 3rd row
- skV[1] = Vector.dot(row[0], row[2]);
- row[2] = Vector.combine(row[2], row[0], 1.0, -skV[1]);
- skV[2] = Vector.dot(row[1], row[2]);
- row[2] = Vector.combine(row[2], row[1], 1.0, -skV[2]);
-
- // Next, get Z scale and normalize 3rd row.
- scV[2] = Vector.len(row[2]);
- row[2] = Vector.normalize(row[2]);
- skV[1] /= scV[2];
- skV[2] /= scV[2];
-
- pdum3 = Vector.cross(row[1], row[2]);
- if (Vector.dot(row[0], pdum3) < 0) {
- for (i = 0; i < 3; i++) {
- scV[i] *= -1;
- row[i][0] *= -1;
- row[i][1] *= -1;
- row[i][2] *= -1;
- }
- }
-
- rV[0] = 0.5 * Math.sqrt(Math.max(1 + row[0][0] - row[1][1] - row[2][2], 0));
- rV[1] = 0.5 * Math.sqrt(Math.max(1 - row[0][0] + row[1][1] - row[2][2], 0));
- rV[2] = 0.5 * Math.sqrt(Math.max(1 - row[0][0] - row[1][1] + row[2][2], 0));
- rV[3] = 0.5 * Math.sqrt(Math.max(1 + row[0][0] + row[1][1] + row[2][2], 0));
-
- if (row[2][1] > row[1][2]) rV[0] = -rV[0];
- if (row[0][2] > row[2][0]) rV[1] = -rV[1];
- if (row[1][0] > row[0][1]) rV[2] = -rV[2];
-
- ret.translate = tV;
- ret.rotate = rV;
- ret.scale = scV;
- ret.skew = skV;
- ret.perspective = pV;
- return true;
- },
-
- /**
- * Clones an array based on offset value.
- * @public
- * @param {Object} v Object with transformation properties like translate, rotate, scale, skew and perspective.
- * @param {Number} offset Determine how many Object to copy.
- * @return {Number[]} Array with sliced value based on offset.
- */
- copy: function (v, offset) {
- return Array.prototype.slice.call(v, offset || 0);
- },
-
- /**
- * Validates if property is a transform property.
- * @public
- * @param {String} transform Any transform property, for which we want to identify whether or not the property is transform.
- * @return {Number} Value of the required transform property.
- */
- isTransform: function (transform) {
- return TRANSFORM[transform];
- },
-
- /**
- * Applies transformation to DOM element with the Matrix3d values.
- * @public
- * @param {enyo.Component} actor Component to be animated.
- * @param {Number[]} m Matrix3d
- */
- accelerate: function (actor, m) {
- m = m ? m : Matrix.identity();
- frame.setTransformProperty(actor, m);
- },
-
- /**
- * Reform matrix 2D to 3D
- * @public
- * @param {Number[]} v Matrix(2d)
- * @return {Number[]} Matrix3d
- */
- parseMatrix: function (v) {
- var m = Matrix.identity();
- v = v.replace(/^\w*\(/, '').replace(')', '');
- v = this.parseValue(v);
- if (v.length <= 6) {
- m[0] = v[0];
- m[1] = v[1];
- m[4] = v[2];
- m[5] = v[3];
- m[12] = v[4];
- m[13] = v[5];
- } else {
- m = v;
- }
- return m;
- },
-
- /**
- * Converts comma separated values to array.
- * @public
- * @param {String} val Value of required animation in any property.
- * @return {Number[]} Create array from val.
- */
- parseValue: function (val) {
- return val.toString().split(",").map(function(v) {
- return parseFloat(v, 10);
- });
- },
-
- /**
- * Gets a matrix for DOM element.
- * @public
- * @param {HTMLElement} style CSS style declaration.
- * @return {Number[]} Matrix3d
- */
- getMatrix: function (style) {
- var m = style.getPropertyValue('transform') ||
- style.getPropertyValue('-moz-transform') ||
- style.getPropertyValue('-webkit-transform') ||
- style.getPropertyValue('-ms-transform') ||
- style.getPropertyValue('-o-transform');
- if (m === undefined || m === null || m == "none") {
- return "";
- }
- return this.parseMatrix(m);
- },
-
- /**
- * Gets a style property applied from the DOM element.
- * @public
- * @param {HTMLElement} style Computed style of a DOM.
- * @param {String} key Property name for which style has to be fetched.
- * @return {Number|HTMLElement}
- */
- getStyleValue: function (style, key) {
- var v = style.getPropertyValue(key) || style[key];
- if (v === undefined || v === null || v == "auto") {
- return 0;
- }
- if (COLOR[key]) {
- return v.replace(/^\w*\(/, '').replace(')', '');
- }
- if (isNaN(v)) {
- return 0;
- }
- v = parseFloat(v, 10);
- return v;
- },
-
- /**
- * Applies style property to DOM element.
- * @public
- * @param {enyo.Component} actor Component to be animated.
- * @param {String} prop CSS property to be applied.
- * @param {Number} val Value of the property applied.
- */
- setProperty: function (actor, prop, val) {
- if (COLOR[prop]) {
- val = val.map(function(v) { return parseInt(v, 10);});
- val = 'rgb('+ val + ')';
- } else if(INT_UNIT[prop]) {
- val = parseInt(val[0], 10);
- } else if (prop == 'opacity') {
- val = val[0].toFixed(6);
- val = (val <= 0) ? '0.000001' : val;
- } else {
- val = val[0] + 'px';
- }
-
- actor.addStyles(prop + ':' + val + ';');
- },
-
- /**
- * Applies transform property to DOM element.
- * @public
- * @param {enyo.Component} actor Component to be animated.
- * @param {Number[]} matrix Matrix3d
- */
- setTransformProperty: function (actor, matrix) {
- var mat = Matrix.toString(matrix);
- /*element.style.transform = mat;
- element.style.webkitTransform = mat;
- element.style.MozTransform = mat;
- element.style.msTransform = mat;
- element.style.OTransform = mat;*/
- actor.addStyles('transform:' + mat + ';'
- + 'webkitTransform:' + mat + ';'
- + 'MozTransform:' + mat + ';'
- + 'msTransform' + mat + ';'
- + 'OTransform' + mat + ';');
- },
-
- /**
- * Get DOM node animation properties.
- * @public
- * @param {HTMLElement} node DOM node
- * @param {Object} props Properties to fetch from DOM.
- * @param {Object} initial Default properties to be applied.
- * @return {Object} Object with various animation properties.
- */
- getComputedProperty: function (node, props, initial) {
- if(!node) return;
-
- var eP = {},
- sP = initial ? utils.mixin({}, initial) : {},
- tP = {},
- dP = {},
- m, k, v,
- s = initial ? undefined : Dom.getComputedStyle(node);
-
- for (k in props) {
- v = sP[k];
- if (!this.isTransform(k)) {
- v = v || this.getStyleValue(s || Dom.getComputedStyle(node), k);
- eP[k] = this.parseValue(props[k]);
- sP[k] = this.parseValue(v);
- } else {
- v = this.parseValue(props[k]);
- //tP[k] = k == 'rotate' ? Vector.toQuant(v) : v;
- tP[k] = v;
- }
- }
-
- if (initial) {
- dP.translate = initial.translate;
- dP.rotate = initial.rotate.length < 4 ? Vector.toQuant(initial.rotate) : initial.rotate;
- dP.scale = initial.scale;
- dP.skew = initial.skew;
- dP.perspective = initial.perspective;
- } else {
- m = this.getMatrix(s || Dom.getComputedStyle(node)) || Matrix.identity();
- this.decomposeMatrix(m, dP);
- }
-
- for(k in dP) {
- sP[k] = dP[k];
- eP[k] = tP[k] || dP[k];
- }
- return {_startAnim: sP, _endAnim: eP, _transform: dP, currentState: dP, matrix: m, props: props};
- },
-
- /**
- * Get DOM node animation distance.
- * @public
- * @param {HTMLElement} prop DOM node properties.
- * @param {Object} initalProp Initial properties to fetch from DOM.
- * @param {Object} finalProp Final properties to be applied.
- * @return {Object} Total computed distance to animate.
- */
- getComputedDistance: function (prop, initalProp, finalProp) {
- var k, sV, eV, dst, tot = 0;
- for (k in prop) {
- sV = (k === 'rotate' ? Vector.quantToVector(initalProp[k]) : initalProp[k]);
- eV = finalProp[k];
- dst = Vector.distance(eV, sV);
- tot += dst;
- }
- return tot;
- }
-};
\ No newline at end of file
diff --git a/src/AnimationSupport/Matrix.js b/src/AnimationSupport/Matrix.js
deleted file mode 100644
index 9befb02c4..000000000
--- a/src/AnimationSupport/Matrix.js
+++ /dev/null
@@ -1,279 +0,0 @@
-require('enyo');
-
-/**
- * Matrix module for matrix related calculation
- *
- * @module enyo/AnimationSupport/Matrix
- */
-module.exports = {
- /**
- * To create Identity Matrix3d (4X4 order).
- * @public
- * @return {Number[]} Identity Matrix3d
- */
- identity: function() {
- return [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];
- },
-
- /**
- * To translate in any dimension based on co-ordinates.
- * @public
- * @param {Number} x Translate value in X axis
- * @param {Number} y Translate value in Y axis
- * @param {Number} z Translate value in Z axis
- * @return {Number[]} Matrix3d
- */
- translate: function (x, y, z) {
- return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y ? y : 0, z ? z : 0, 1];
- },
-
- /**
- * To translate in x dimension
- * @public
- * @param {Number} x Translate value in X axis
- * @return {Number[]} Matrix3d
- */
- translateX: function (x) {
- return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x ? x : 0, 0, 0, 1];
- },
-
- /**
- * To translate in y dimension
- * @public
- * @param {Number} y Translate value in Y axis
- * @return {Number[]} Matrix3d
- */
- translateY: function (y) {
- return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, y ? y : 0, 0, 1];
- },
-
- /**
- * To translate in z dimension
- * @public
- * @param {Number} z Translate value in Z axis
- * @return {Number[]} Matrix3d
- */
- translateZ: function (z) {
- return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, z ? z : 0, 1];
- },
-
- /**
- * To scale in any dimension
- * @public
- * @param {Number} x Scale value in X axis
- * @param {Number} y Scale value in Y axis
- * @param {Number} z Scale value in Z axis
- * @return {Number[]} Matrix3d
- */
- scale: function (x, y, z) {
- return [x, 0, 0, 0, 0, y ? y : 1, 0, 0, 0, 0, z ? z : 1, 0, 0, 0, 0, 1];
- },
-
- /**
- * To skew in any dimension (skew can only happen in 2d)
- * @public
- * @param {Number} a Skew value in X axis
- * @param {Number} b Skew value in Y axis
- * @return {Number[]} Matrix3d
- */
- skew: function (a, b) {
- a = a ? Math.tan(a * Math.PI / 180): 0;
- b = b ? Math.tan(b * Math.PI / 180): 0;
- return [1, b, 0, 0, a, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
- },
-
- /**
- * To rotate in x-axis
- * @public
- * @param {Number} a Rotate value in X axis
- * @return {Number[]} Matrix3d
- */
- rotateX: function (a) {
- var cosa, sina;
- a = a * Math.PI / 180;
- cosa = Math.cos(a);
- sina = Math.sin(a);
- return [1, 0, 0, 0, 0, cosa, -sina, 0, 0, sina, cosa, 0, 0, 0, 0, 1];
- },
-
- /**
- * To rotate in y-axis
- * @public
- * @param {Number} b Rotate value in Y axis
- * @return {Number[]} Matrix3d
- */
- rotateY: function (b) {
- var cosb, sinb;
- b = b * Math.PI / 180;
- cosb = Math.cos(b);
- sinb = Math.sin(b);
- return [cosb, 0, sinb, 0, 0, 1, 0, 0, -sinb, 0, cosb, 0, 0, 0, 0, 1];
- },
-
- /**
- * To rotate in z-axis
- * @public
- * @param {Number} g Rotate value in Z axis
- * @return {Number[]} Matrix3d
- */
- rotateZ: function (g) {
- var cosg, sing;
- g = g * Math.PI / 180;
- cosg = Math.cos(g);
- sing = Math.sin(g);
- return [cosg, -sing, 0, 0, sing, cosg, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
- },
-
- /**
- * To rotate in any dimension
- * @public
- * @param {Number} a Rotate value in X axis
- * @param {Number} b Rotate value in Y axis
- * @param {Number} g Rotate value in Z axis
- * @return {Number[]} Matrix3d
- */
- rotate: function (a, b, g) {
- a = a * Math.PI / 180;
- b = b * Math.PI / 180;
- g = g * Math.PI / 180;
- var ca = Math.cos(a);
- var sa = Math.sin(a);
- var cb = Math.cos(b);
- var sb = Math.sin(b);
- var cg = Math.cos(g);
- var sg = Math.sin(g);
- var m = [
- cb * cg,
- ca * sg + sa * sb * cg,
- sa * sg - ca * sb * cg,
- 0,
- -cb * sg,
- ca * cg - sa * sb * sg,
- sa * cg + ca * sb * sg,
- 0,
- sb,
- -sa * cb,
- ca * cb,
- 0,
- 0, 0, 0, 1
- ];
- return m;
- },
-
- /**
- * To multiply 2 Martix3d (4x4 order)
- * @public
- * @param {Number[]} m1 1st Matrix3d
- * @param {Number[]} m2 2nd Matrix3d
- * @return {Number[]} Resultant Matrix3d
- */
- multiply: function(m1, m2) {
- return [
- m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2],
- m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2],
- m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2],
- 0,
- m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6],
- m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6],
- m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6],
- 0,
- m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10],
- m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10],
- m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10],
- 0,
- m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12],
- m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13],
- m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14],
- 1
- ];
- },
-
- /**
- * To multiply 2 matrices (NxN order)
- * @public
- * @param {Number[]} m1 1st Matrix of order N
- * @param {Number[]} m2 2nd Matrix of order N
- * @return {Number[]} Resultant Matrix of order N
- */
- multiplyN: function(m1, m2) {
- var i, j, sum,
- m = [],
- l1 = m1.length,
- l2 = m2.length;
-
- for (i = 0; i < l1; i++) {
- sum = 0;
- for (j = 0; j < l2; j++) {
- sum += m1[i][j] * m2[j];
- }
- m.push(sum);
- }
- return m;
- },
-
- /**
- * To inverse matrix of order N
- * @public
- * @param {Number[]} matrix Matrix (NxN order)
- * @param {Number} n Order of the matrix
- * @return {Number[]} Inverted Matrix
- */
- inverseN: function(matrix, n) {
- var i, j, k, r, t,
- precision = 100000,
- result = [],
- row = [];
- for (i = 0; i < n; i++) {
- for (j = n; j < 2 * n; j++) {
- if (i == (j - n)) matrix[i][j] = 1.0;
- else matrix[i][j] = 0.0;
- }
- }
-
- for (i = 0; i < n; i++) {
- for (j = 0; j < n; j++) {
- if (i != j) {
- r = matrix[j][i] / matrix[i][i];
- r = Math.round(r * precision) / precision;
- for (k = 0; k < 2 * n; k++) {
- t = Math.round(matrix[j][k] * precision) / precision;
- t -= Math.round((r * matrix[i][k]) * precision) / precision;
- matrix[j][k] = t;
- }
- }
- }
- }
-
- for (i = 0; i < n; i++) {
- t = matrix[i][i];
- for (j = 0; j < 2 * n; j++) {
- matrix[i][j] = matrix[i][j] / t;
- }
- }
-
- for (i = 0; i < n; i++) {
- row = [];
- for (k = 0, j = n; j < 2 * n; j++, k++) {
- row.push(matrix[i][j]);
- }
- result.push(row);
- }
-
- return result;
- },
-
- /**
- * Convert Matrix3d array to Matrix3d String
- * @public
- * @param {Number[]} m Matrix3d Array
- * @return {String} Matrix3d String
- */
- toString: function (m) {
- var ms = 'matrix3d(';
- for (var i = 0; i < 15; i++) {
- ms += (m[i] < 0.000001 && m[i] > -0.000001) ? '0,' : m[i] + ',';
- }
- ms += m[15] + ')';
- return ms;
- }
-};
\ No newline at end of file
diff --git a/src/AnimationSupport/Scene.js b/src/AnimationSupport/Scene.js
deleted file mode 100644
index 3be48f4b9..000000000
--- a/src/AnimationSupport/Scene.js
+++ /dev/null
@@ -1,388 +0,0 @@
-var
- editor = require('./SceneEditor'),
- director = require('./Director'),
- animation = require('../animation'),
- utils = require('../utils');
-
-/**
- * This module exports "Scene" which is a class/constructor so that we can create an instance of the same.
- * We can define all the animation properties we want in the application in the instance of the "Scene".
- *
- * @module enyo/AnimationSupport/Scene
- */
-var Scene = module.exports = function(props) {
- var scene = Scene.create(),
- dur = props.duration || 0;
-
- utils.mixin(scene, editor);
-
- if (props.animation) {
- var anims = utils.isArray(props.animation) ? props.animation : [props.animation];
-
- for (var i = 0; i < anims.length; i++) {
- scene.addAnimation(anims[i], anims[i].span || anims[i].duration || dur);
- delete anims[i].duration;
- }
- delete props.animation;
- delete props.duration;
- }
-
- utils.mixin(scene, props);
- utils.mixin(scene, SceneAction);
- return scene;
-};
-
-
-/**
- * Creates a empty instance of scene.
- * Can be used for runtime creation of animations
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- * @return {Object} An instance of the constructor
- */
-Scene.create = function() {
- return new sceneConstructor(utils.uid("@"));
-};
-
-
-/**
- * Connects an actor/s to a scene.
- * All the actors should be added before initiating animation otherwise actors will animate for remaining time span
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- * @param {Object} actors - The elements which needs to be animated
- * @param {Object} scene - The instance of the Scene we've created in the application
- */
-Scene.link = function(actors, scene) {
- director.cast(actors, scene);
-};
-
-
-/**
- * Disconnects an actor/s from a scene.
- * (Actors could be delinked during the animation
- * however they will current their state when delinked)
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- * @param {Object} actors - The elements which needs to be animated
- * @param {Object} scene - The instance of the Scene we've created in the application
- */
-Scene.delink = function(actors, scene) {
- director.reject(scene, actors);
-};
-
-
-/**
- * Function to construct all the scenes instantiated from the Scene
- * @memberOf module:enyo/AnimationSupport/Scene
- * @private
- * @param {number} id - id of the scene generated when created
- * @return {object} Constructed instance
- */
-var sceneConstructor = function(id) {
- var
- _ts, _wasts, _req,
- _framerate = 16.6,
- /**
- * Stores the id of the instance created
- * @memberOf module:enyo/AnimationSupport/Scene
- * @private
- * @type {Array}
- */
- _id = id,
-
- /**
- * Holds refereneces of the all animations added to this scene.
- * @memberOf module:enyo/AnimationSupport/Scene
- * @private
- * @type {Array}
- */
- _poses = [],
-
- /**
- * Holds old animation time span, useful for scenarios where same
- * time span is expected to be added for the latest added animation.
- * This provides the felxibility to add animation without duration.
- *
- * Like: scene.addAnimation({translate: '50,0,0'});
- *
- * As no duration is mentioned the old animations duration is taken.
- * @type {Number}
- * @memberOf module:enyo/AnimationSupport/Scene
- * @private
- */
- _prevDur = 0;
-
- /**
- * An exposed property to know if know the animating state of this scene.
- * 'true' - the scene is asked for animation(doesn't mean animation is happening)
- * 'false' - the scene is not active(has completed or its actors are not visible)
- * @type {Boolean}
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.animating = false;
-
- /**
- * An exposed property to know if the scene is ready with actors performing action.
- * 'true' - the scene actors are ready for action
- * 'false' - some or all actors are not ready
- * @type {Boolean}
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.active = false;
-
- /**
- * Holds refereneces of complete time span for this scene.
- * @type {Number}
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.span = 0;
-
-
- /**
- * Function used to loop in all the animations in a scene
- * @memberOf module:enyo/AnimationSupport/Scene
- * @private
- */
- function loop() {
- if (this.animating) {
- _ts = utils.perfNow();
- _ts = _ts - (_wasts !== undefined ? _wasts : _ts);
- _ts = (_ts > _framerate) ? _framerate : _ts;
- director.take(this, _ts);
- _wasts = _ts;
- this.trigger(true);
- } else {
- _wasts = undefined;
- this.cancel();
- this.completed && this.completed();
- }
- }
- /**
- * Function used to make start the animation if it is "true" for animating.
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.ready = function() {
- if (this.animating) {
- if (!this.active) {
- director.roll(this);
- }
- return this.active;
- }
- return false;
- };
-
- /**
- * Cancel the animation
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.cancel = function() {
- animation.cancelRequestAnimationFrame(_req);
- };
-
-
- /**
- * Triggers the Request Animation Frame
- * @param {boolean} force - A boolean value for letting the rAF start.
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.trigger = function(force) {
- if (force || !this.animating) {
- _req = animation.requestAnimationFrame(utils.bindSafely(this, loop));
- }
- };
-
-
- /**
- * Gets the unique ID assigned to this sceen.
- * @return {number} - id
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.getID = function() {
- return _id;
- };
-
-
- /**
- * Returns the life span/duration of this sceen.
- * @return {number} life span/duration of this sceen
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.totalSpan = function() {
- return this.span;
- };
-
- /**
- * Adds new animation on already existing animation for this character.
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.addAnimation = function(newProp, span) {
- if (_prevDur === 0 && span === 0) {
- _poses[0] = {
- animate: newProp,
- span: 0
- };
- } else {
- _prevDur = span || _prevDur;
- this.span += _prevDur;
- _poses.push({
- animate: newProp,
- span: this.span
- });
- }
- };
- /**
- * Function which returns the length of the poses.
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- * @return {number} - length of the poses
- */
- this.length = function() {
- return _poses.length;
- };
- /**
- * Returns animation pose index for a particular
- * instance of time from the list of
- * animations added to the scene.
- * @param {number} span - Time span from the animation timeline
- * @return {number} - index of the animation
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.animateAtTime = function(span) {
- var startIndex = 0,
- stopIndex = _poses.length - 1,
- middle = Math.floor((stopIndex + startIndex) / 2);
-
- if (span === 0) {
- return startIndex;
- }
-
- while (_poses[middle].span != span && startIndex < stopIndex) {
- if (span < _poses[middle].span) {
- stopIndex = middle;
- } else if (span > _poses[middle].span) {
- startIndex = middle + 1;
- }
-
- middle = Math.floor((stopIndex + startIndex) / 2);
- }
- return (_poses[middle].span != span) ? startIndex : middle;
- };
-
- /**
- * Clears/removes the animation
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.clearAnimation = function() {
- for (var i = 0; i < _poses.length; i++) {
- _poses[i]._startAnim = undefined;
- }
- };
-
- /**
- * Returns animation pose based on index from the list of
- * animations added to this scene.
- * @param {number} index - animation's index from the list of animations
- * @return {Object} pose of the animation based on the index in the list
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.getAnimation = function(index) {
- return index < 0 || _poses[index];
- };
-
- /**
- * Sets the newly added animation to the poses
- * @param {Numner} index - index to which the new animation should set
- * @param {Object} pose - newly added animation
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.setAnimation = function(index, pose) {
- _poses[index] = pose;
- };
-
-
- //TODO: Move these events to Event Delegator
- /**
- * Event to identify when the scene has done animating.
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.completed = function() {};
-
- /**
- * Event to identify when the scene has done a step(rAF updatation of time) in the animation.
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.step = function() {};
-
- /**
- * Event to identify when the actor has done animating.
- * @param {Object} actor - animating element
- * @memberOf module:enyo/AnimationSupport/Scene
- * @public
- */
- this.actorCompleted = function(actor) {};
-};
-
-/**
- * SceneAction exposes the api which performs the action on the animation in a given scene
- * @type {Object}
- * @memberOf module:enyo/AnimationSupport/Scene
- * @private
- */
-var SceneAction = {
- /**
- * This function initiates action on the animation
- * from the list of animations for a given scene.
- * @param {number} ts - timespan
- * @param {Object} pose - pose from the animation list
- * @return {Object} - pose
- * @memberOf module:enyo/AnimationSupport/Scene
- * @private
- */
- action: function(ts, pose) {
- var past,
- actor,
- actors,i,
- tm = this.rolePlay(ts),
- index = this.animateAtTime(tm);
-
- if (index < 0) {
- return;
- }
- pose = this.getAnimation(index);
- past = pose.animate;
-
- if (past instanceof sceneConstructor) {
- past._frameSpeed = this._frameSpeed;
- director.take(past, ts);
- } else {
- past = index ? this.getAnimation(index - 1).span : 0;
- actors = this.rolePlays[this.getID()];
- for (i = 0; (actor = actors[i]); i++) {
- if (actor.generated) {
- director.action(pose,
- actors[i],
- tm - past,
- pose.span - past);
- this.step && this.step(actor);
- }
- }
- }
- return pose;
- }
-};
\ No newline at end of file
diff --git a/src/AnimationSupport/SceneActor.js b/src/AnimationSupport/SceneActor.js
deleted file mode 100644
index 81eb194fd..000000000
--- a/src/AnimationSupport/SceneActor.js
+++ /dev/null
@@ -1,65 +0,0 @@
-var
- Scene = require('./Scene'),
- director = require('./Director'),
- utils = require('../utils');
-
-var
- tm, actor, actors, len, dur;
-
-var CharacterAction = {
- /**
- * Overridden function initiates action on the animation
- * for the given scene actor.
- * @param {number} ts - timespan
- * @param {Object} pose - pose from the animation list
- * @return {Object} - pose
- * @memberOf module:enyo/AnimationSupport/SceneActor
- * @private
- * @override
- */
- action: function (ts, pose) {
- var i, past, index;
-
- actors = this.rolePlays[this.getID()];
- len = actors.length;
- dur = this.span;
- for (i = 0; (actor = actors[i]); i++) {
- //give priority to individual actor than scene.
- if (!actor._frameSpeed) {
- actor._frameSpeed = this._frameSpeed;
- }
-
- if (actor.generated && actor._frameSpeed) {
- tm = this.rolePlay(ts, actor);
- if (isNaN(tm) || tm < 0) continue;
- else if (tm <= dur) {
- index = this.animateAtTime(tm);
- pose = this.getAnimation(index);
- past = index ? this.getAnimation(index - 1).span : 0;
- director.action(pose, actor, tm - past, pose.span - past);
- this.step && this.step(actor);
- } else {
- actor.timeline = dur;
- actor._frameSpeed = 0;
- this.actorCompleted && this.actorCompleted(actor);
- }
- }
- }
- return pose;
- }
-};
-
-/**
- * Scene Actor is used to individually manage all the actors
- * The Scene Actor is similar to Scene but can receive
- * an actor for playing the animation.
- * Scene Actor's play when called without the actor,
- * it works same as Scene playing all the actors.
- * Usage - SceneActorInstance.play(actor)
- * @module enyo/AnimationSupport/SceneActor
- */
-module.exports = function(props) {
- var scene = Scene(props);
- utils.mixin(scene, CharacterAction);
- return scene;
-};
diff --git a/src/AnimationSupport/SceneEditor.js b/src/AnimationSupport/SceneEditor.js
deleted file mode 100644
index 14824613a..000000000
--- a/src/AnimationSupport/SceneEditor.js
+++ /dev/null
@@ -1,192 +0,0 @@
-require('enyo');
-
-/**
-* @module enyo/AnimationSupport/SceneEditor
-*/
-
-/**
-* This modules exposes API's for controlling animations.
-* @private
-*/
-module.exports = {
- /**
- * @private
- */
- timeline: 0,
- /**
- * @private
- */
- _cachedValue: 0,
- /**
- * @private
- */
- _frameSpeed: 0,
- /**
- * @private
- */
- _startTime: 0,
-
- /**
- * @private
- */
- cache: function(actor) {
- actor = actor || this;
- if(actor._frameSpeed === 0){
- actor._frameSpeed = actor._cachedValue;
- }
- this.animating = true;
- },
-
- /**
- * Starts the animation of the actor
given in argument.
- * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be started.
- * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
- * @public
- */
- play: function (actor) {
- actor = actor || this;
- actor._frameSpeed = 1;
- if (isNaN(actor.timeline) || !actor.timeline) {
- actor.timeline = 0;
- }
- this.trigger();
- this.animating = true;
- },
-
- /**
- * Resumes the paused animation of the actor
given in argument.
- * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be resumed.
- * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
- * @public
- */
- resume: function(actor) {
- this.cache(actor);
- actor = actor || this;
- actor._frameSpeed *= 1;
- },
-
- /**
- * Pauses the animation of the actor
given in argument.
- * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be paused.
- * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
- * @public
- */
- pause: function (actor) {
- actor = actor || this;
- actor._cachedValue = actor._frameSpeed;
- actor._frameSpeed = 0;
- },
-
- /**
- * Reverses the animation of the actor
given in argument.
- * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be reversed.
- * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
- * @public
- */
- reverse: function (actor) {
- this.cache(actor);
- actor = actor || this;
- actor._frameSpeed *= -1;
- },
-
- /**
- * fast description goes here
- * @param {Number} mul description goes here
- * @param [Component]{@link module:enyo/Component~Component} actor description goes here
- * @public
- */
- fast: function (mul, actor) {
- this.cache(actor);
- actor = actor || this;
- actor._frameSpeed *= mul;
- },
-
- /**
- * slow description goes here
- * @param {Number} mul description goes here
- * @param [Component]{@link module:enyo/Component~Component} actor description goes here
- * @public
- */
- slow: function (mul, actor) {
- this.cache(actor);
- actor = actor || this;
- actor._frameSpeed *= mul;
- },
-
- /**
- * Changes the speed of the animation.
- * Speed of the animation changed based on the factor
.
- * To slow down the speed use values between 0 and 1. For Example 0.5 to reduce the speed by 50%.
- * To increase the speed use values above 1. For Example 2 to increase the speed by 200%.
- * Animation will be paused if factor is 0. To pause the animation use {@link enyo/AnimationSupport/SceneEditor.pause pause}
API.
- * Speed will not be affected incase of negative multiplication factor.
- * @param {Number} factor Multiplication factor which changes the speed
- * @param [Component {@link module:enyo/Component~Component}] actor The component whose animating speed should be changed
- * @public
- */
- speed: function(mul, actor) {
- if (mul < 0) return;
- this.cache(actor);
- actor = actor || this;
- actor._frameSpeed *= mul;
- },
-
- /**
- * Stops the animation of the actor given in argument.
- * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be stopped.
- * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
- * @public
- */
- stop: function (actor) {
- actor = actor || this;
- actor._cachedValue = 1;
- actor._frameSpeed = 0;
- actor.timeline = 0;
- this.animating = false;
- this.cancel();
- },
-
- /**
- * Seeks the animation of the actor
to the position provided in timeline
- * The value of timeline
should be between 0 to duration
of the animation.
- * @param {Number} timeline Value in timeline where the animation has to be seeked
- * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
- * @public
- */
- seek: function(timeline, actor) {
- actor = actor || this;
- if (this.animating !== true) {
- this.play(actor);
- this.pause(actor);
- }
- actor.timeline = timeline;
- },
-
- /**
- * rolePlay
updated the timeline of the actor which is currently animating.
- * @param {Number} t Elapsed time since the animation of this pose has started (ratio in factor of 1)
- * @param {@link module:enyo/Component~Component} actor The component which is animating
- * @return {Number} Returns the updated timeline of the actor
- * @access public
- */
- rolePlay: function (t, actor) {
- actor = actor || this;
- if (actor.timeline === undefined || actor.timeline < 0)
- actor.timeline = 0;
-
- if(actor.delay > 0) {
- actor.delay -= _rolePlay(t, actor._frameSpeed);
- } else {
- actor.timeline += _rolePlay(t, actor._frameSpeed);
- }
- return actor.timeline;
- }
-};
-
-/**
- * Returns the time based on the current speed of animation.
- * @private
- */
-function _rolePlay(t, mul) {
- return mul * t;
-}
\ No newline at end of file
diff --git a/src/AnimationSupport/SceneEvent.js b/src/AnimationSupport/SceneEvent.js
index 0a13e1040..f379c824d 100644
--- a/src/AnimationSupport/SceneEvent.js
+++ b/src/AnimationSupport/SceneEvent.js
@@ -1,6 +1,5 @@
var
- Scene = require('./Scene'),
- director = require('./Director'),
+ Scene = require('../scene'),
dispatcher = require('../dispatcher'),
emitter = require('../EventEmitter'),
utils = require('../utils');
@@ -188,8 +187,8 @@ var EventAction = {
/**
* To get event changes captured, for delta values of x, y and z.
- * @return {Object} delta - pose
- * @memberOf module:enyo/AnimationSupport/SceneEvent
+ * @return {Object} delta - pose
+ * @memberOf module:enyo/AnimationSupport/SceneEvent
* @public
*/
getAnimationDelta: function() {
@@ -198,8 +197,8 @@ var EventAction = {
/**
* To be when an virtual event has to be triggered for the last event captured.
- * @return {void}
- * @memberOf module:enyo/AnimationSupport/SceneEvent
+ * @return {void}
+ * @memberOf module:enyo/AnimationSupport/SceneEvent
* @public
*/
triggerEvent: function() {
@@ -211,9 +210,9 @@ var EventAction = {
* To be used when an actor is registerd for event tracking.
* Its keeps track of only on actor which is refered as
* the originator.
- * @param {Object} actor - Component on which events will be captured.
- * @return {void}
- * @memberOf module:enyo/AnimationSupport/SceneEvent
+ * @param {Object} actor - Component on which events will be captured.
+ * @return {void}
+ * @memberOf module:enyo/AnimationSupport/SceneEvent
* @public
*/
register: function (actor) {
@@ -224,19 +223,19 @@ var EventAction = {
},
/**
- * Overridden function initiates action on the animation
- * for the given scene event.
- * @param {number} ts - timespan
- * @param {Object} pose - pose from the animation list
- * @return {Object} - pose
- * @memberOf module:enyo/AnimationSupport/SceneEvent
- * @private
- * @override
- */
+ * Overridden function initiates action on the animation
+ * for the given scene event.
+ * @param {number} ts - timespan
+ * @param {Object} pose - pose from the animation list
+ * @return {Object} - pose
+ * @memberOf module:enyo/AnimationSupport/SceneEvent
+ * @private
+ * @override
+ */
action: function (ts, pose) {
if (_isTriggered && _triggerer && this.handlers && this.handlers[_triggerer] !== undefined) {
if (this.handlers[_triggerer] === "") {
- ts = director.shot(this, ts);
+ ts = this.shot(this, ts);
pose = sup.call(this, ts, pose);
if(ts === 0) _isTriggered = false;
} else {
@@ -244,6 +243,54 @@ var EventAction = {
}
}
return pose;
+ },
+
+ /**
+ * shot
method is invloved in distance based animation in which the distance definite and
+ * indefinite (Event based animations). This method calculates the distance to which the actor has to
+ * be animated based on the delta and the acceleration.
+ * @param {@link module:enyo/AnimationSupport/Scene} scene scene
applied for achieving animation
+ * @param {Number} ts delta distance
+ * @return {Number} The distance to which the actor has to be transformed
+ */
+ shot: function(scene, ts) {
+ var v1, s, a, v = 0,
+ t = ts,
+ dt = scene.getAnimationDelta(),
+ dir = this.angle(scene.direction),
+ v0 = dt.velocity || 0;
+
+ v1 = dt[dir] / t;
+ if (v1 === 0) {
+ dt[dir] = 0;
+ dt.velocity = 0;
+ } else {
+ a = (v1 - v0) / t;
+ s = 0.5 * a * t * t;
+ v = (a < 0 ? -s : s);
+ dt[dir] = dt[dir] - v;
+ if (a > -0.001 && a < 0.001) {
+ dt[dir] = 0;
+ }
+ dt.velocity = v1;
+ }
+ return dt[dir] > 0 ? v : -v;
+ },
+
+ /**
+ * @private
+ */
+ angle: function (direction) {
+ switch(direction) {
+ case "X" :
+ return "dX";
+ case "Y" :
+ return "dY";
+ case "Z" :
+ return "dZ";
+ default:
+ return "dX";
+ }
}
};
diff --git a/src/AnimationSupport/Vector.js b/src/AnimationSupport/Vector.js
deleted file mode 100644
index 9f0db08e3..000000000
--- a/src/AnimationSupport/Vector.js
+++ /dev/null
@@ -1,317 +0,0 @@
-require('enyo');
-
-/**
- * Vector module for vector related calculations.
- * Also provides API's for Quaternion vectors for rotation.
- *
- * @module enyo/AnimationSupport/Vector
- */
-module.exports = {
- /**
- * Divides vector with a scalar value.
- * @param {Number[]} v - vector
- * @param {Number} s - scalar value to divide
- * @return {Number[]} resultant vector
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- divide: function (v, s) {
- return [v[0] / s, v[1] / s, v[2] / s];
- },
-
- /**
- * Add vector/quant with a vector/quant.
- * @param {Number[]} q1 - vector/quant
- * @param {Number[]} q2 - vector/quant
- * @return {Number[]} added vector/quant
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- add: function (q1, q2) {
- var q3 = [];
- q3[0] = q1[0] + q2[0];
- q3[1] = q1[1] + q2[1];
- q3[2] = q1[2] + q2[2];
- if (q1.length > 3 && q2.length > 3) q3[3] = q1[3] + q2[3];
- return q3;
- },
-
- /**
- * Sub vector/quant with a vector/quant.
- * @param {Number[]} q1 - vector/quant
- * @param {Number[]} q2 - vector/quant
- * @return {Number[]} subracted vector/quant
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- subtract: function (q1, q2) {
- var q3 = [];
- q3[0] = q1[0] - q2[0];
- q3[1] = q1[1] - q2[1];
- q3[2] = q1[2] - q2[2];
- if (q1.length > 3 && q2.length > 3) q3[3] = q1[3] - q2[3];
- return q3;
- },
-
- /**
- * Multiply vector/quant with a vector/quant.
- * @param {Number[]} v - vector
- * @param {Number} s - scalar value to divide
- * @return {Number[]} resultant vector
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- multiply: function (q, s) {
- q[0] *= s;
- q[1] *= s;
- q[2] *= s;
- if (q.length > 3) q[3] *= s;
- return q;
- },
-
- /**
- * Limits the vector/quant between a maximum and minimum value.
- * @param {Number[]} q - vector/quant
- * @param {Number} max - maximum range value
- * @param {Number} min - minimum range value
- * @return {Number[]} resultant vector/quant
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- range: function (q, max, min) {
- for (var i = 0; i < q.length; i++) {
- q[i] = q[i] < min ? Math.max(q[i], min) : q[i] > max ? Math.min(q[i], max) : q[i];
- }
- },
-
- /**
- * Evaluates the gap between two vector values.
- * Returns the absolute distance between two vectors.
- * @param {Number[]} v1 - vector
- * @param {Number[]} v2 - vector
- * @param {Number} d - distance between vector
- * @return {Number} distance between vector
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- distance: function (v1, v2, d) {
- d = Math.sqrt(
- (v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]) + (v1[2] - v2[2]) * (v1[2] - v2[2]));
- return (d < 0.01 && d > -0.01) ? 0 : d;
- },
-
- /**
- * Evaluates the gap between two quanterions values
- * Returns the absolute distance between two quanterions.
- * @param {Number[]} v1 - quant
- * @param {Number[]} v2 - quant
- * @param {Number} d - distance between quant
- * @return {Number} distance between quant
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- quantDistance: function (q1, q2, d) {
- d = Math.sqrt(
- (q1[0] - q2[0]) * (q1[0] - q2[0]) + (q1[1] - q2[1]) * (q1[1] - q2[1]) + (q1[2] - q2[2]) * (q1[2] - q2[2]) + (q1[3] - q2[3]) * (q1[3] - q2[3]));
- return (d < 0.0001 && d > -0.0001) ? 0 : d;
- },
-
- /**
- * Gives the direction of motion from one vector to other.
- * Returns true if moving towards positive direction.
- * @param {Number[]} v1 - quant
- * @param {Number[]} v2 - quant
- * @return {boolean} true if positive, false otherwise.
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- direction: function (q1, q2) {
- return (q1[0] - q2[0]) < 0 || (q1[1] - q2[1]) < 0 || (q1[2] - q2[2]) < 0;
- },
-
- /**
- * Retunns an inverse of a quanterion.
- * @param {Number[]} q - quant
- * @return {Number[]} resultant quant
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- quantInverse: function (q) {
- // var d = (q[0] * q[0]) + (q[1] * q[1]) + (q[2] * q[2]) + (q[3] * q[3]);
- return [-q[0], -q[1], -q[2], q[3]];
- },
-
- /**
- * Length of a vector
- * @param {Number[]} v - vetor
- * @return {Number} resultant length
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- len: function (v) {
- return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
- },
-
- /**
- * Dot product of 3D vectors
- * @param {Number[]} v1 - vetor
- * @param {Number[]} v2 - vetor
- * @return {Number} resultant dot product
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- dot: function (v1, v2) {
- return (v1[0] * v2[0]) + (v1[1] * v2[1]) + (v1[2] * v2[2]) + (v1[3] !== undefined && v2[3] !== undefined ? (v1[3] * v2[3]) : 0);
- },
-
- /**
- * Dot product of 3D quanterion
- * @param {Number[]} q1 - quanterion
- * @param {Number[]} q2 - quanterion
- * @return {Number} resultant dot product
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- quantDot: function (q1, q2) {
- return (q1[0] * q2[0]) + (q1[1] * q2[1]) + (q1[2] * q2[2]) + (q1[3] * q2[3]);
- },
-
- /**
- * Quant Cross product of 3D quanterion
- * @param {Number[]} q1 - quanterion
- * @param {Number[]} q2 - quanterion
- * @return {Number[]} resultant cross product
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- quantCross: function (q1, q2) {
- return [
- q1[3] * q2[0] + q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1],
- q1[3] * q2[1] - q1[0] * q2[2] + q1[1] * q2[3] + q1[2] * q2[0],
- q1[3] * q2[2] + q1[0] * q2[1] - q1[1] * q2[0] + q1[2] * q2[3],
- q1[3] * q2[3] - q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2]
- ];
- },
-
- /**
- * Cross product of two vectors
- * @param {Number[]} v1 - vetor
- * @param {Number[]} v2 - vetor
- * @return {Number[]} resultant cross product
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- cross: function (v1, v2) {
- return [
- v1[1] * v2[2] - v1[2] * v2[1],
- v1[2] * v2[0] - v1[0] * v2[2],
- v1[0] * v2[1] - v1[1] * v2[0]
- ];
- },
-
- /**
- * Normalizing a vector is obtaining another unit vector in the same direction.
- * To normalize a vector, divide the vector by its magnitude.
- * @param {Number[]} q1 - quanterion
- * @return {Number[]} resultant quanterion
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- normalize: function (q) {
- return this.divide(q, this.len(q));
- },
-
- /**
- * Combine scalar values with two vectors.
- * Required during parsing scaler values matrix.
- * @param {Number[]} a - first vector
- * @param {Number[]} b - second vector
- * @param {Number[]} ascl - first vector scalar
- * @param {Number[]} ascl - second vector scalar
- * @return {Number[]} resultant vector
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- combine: function (a, b, ascl, bscl) {
- return [
- (ascl * a[0]) + (bscl * b[0]), (ascl * a[1]) + (bscl * b[1]), (ascl * a[2]) + (bscl * b[2])
- ];
- },
-
- /**
- * Converts a quaternion vector to a rotation vector.
- * @param {Number[]} rv - quanterion
- * @return {Number[]} resultant rotation vector
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- toVector: function (rv) {
- var r = 2 * Math.acos(rv[3]);
- var sA = Math.sqrt(1.0 - rv[3] * rv[3]);
- if (Math.abs(sA) < 0.0005) sA = 1;
- return [rv[0] / sA, rv[1] / sA, rv[2] / sA, r * 180 / Math.PI];
- },
-
- /**
- * Converts a rotation vector to a quaternion vector.
- * @param {Number[]} v - vector
- * @return {Number[]} resultant quaternion
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- toQuant: function (v) {
- if (!v) v = [];
- var q = [],
- p = parseFloat(v[1] || 0) * Math.PI / 360,
- y = parseFloat(v[2] || 0) * Math.PI / 360,
- r = parseFloat(v[0] || 0) * Math.PI / 360,
- c1 = Math.cos(p),
- c2 = Math.cos(y),
- c3 = Math.cos(r),
- s1 = Math.sin(p),
- s2 = Math.sin(y),
- s3 = Math.sin(r);
-
- q[3] = Math.round((c1 * c2 * c3 - s1 * s2 * s3) * 100000) / 100000;
- q[0] = Math.round((s1 * s2 * c3 + c1 * c2 * s3) * 100000) / 100000;
- q[1] = Math.round((s1 * c2 * c3 + c1 * s2 * s3) * 100000) / 100000;
- q[2] = Math.round((c1 * s2 * c3 - s1 * c2 * s3) * 100000) / 100000;
- return q;
- },
-
- /**
- * Converts a quaternion vector vector to a rotation vector.
- * @param {Number[]} q - quaternion
- * @return {Number[]} resultant vector
- * @memberOf module:enyo/AnimationSupport/Vector
- * @public
- */
- quantToVector: function (q) {
- var vector = [], h, a, b,
- x2 = q[0] * q[0],
- y2 = q[1] * q[1],
- z2 = q[2] * q[2],
- test = q[0] * q[1] + q[2] * q[3];
- if (test > 0.499) {
- vector[1] = 360 / Math.PI * Math.atan2(q[0], q[3]);
- vector[2] = 90;
- vector[0] = 0;
- return;
- }
- if (test < -0.499) {
- vector[1] = -360 / Math.PI * Math.atan2(q[0], q[3]);
- vector[2] = -90;
- vector[0] = 0;
- return;
- }
- h = Math.atan2(2 * q[1] * q[3] - 2 * q[0] * q[2], 1 - 2 * y2 - 2 * z2);
- a = Math.asin(2 * q[0] * q[1] + 2 * q[2] * q[3]);
- b = Math.atan2(2 * q[0] * q[3] - 2 * q[1] * q[2], 1 - 2 * x2 - 2 * z2);
- vector[1] = Math.round(h * 180 / Math.PI);
- vector[2] = Math.round(a * 180 / Math.PI);
- vector[0] = Math.round(b * 180 / Math.PI);
-
- return vector;
- }
- //TODO: Acheive the same fucntionality for other 11 choices XYX, XZX, XZY, YXY, YXZ, YZX, YZY, ZXY, ZXZ, ZYX, ZYZ
-};
\ No newline at end of file
diff --git a/src/Animator.js b/src/Animator.js
index fbb8df5a1..8431a48ec 100644
--- a/src/Animator.js
+++ b/src/Animator.js
@@ -8,6 +8,7 @@ require('enyo');
var
kind = require('./kind'),
utils = require('./utils'),
+ easing = require('./easing'),
animation = require('./animation');
var
@@ -59,13 +60,13 @@ var
* to [endValue]{@link module:enyo/Animator~Animator#endValue} during the animation, based on the
* [function]{@glossary Function} referenced by the
* [easingFunction]{@link module:enyo/Animator~Animator#easingFunction} property.
-*
+*
* Event handlers may be specified as functions. If specified, the handler function will
* be used to handle the event directly, without sending the event to its
* [owner]{@link module:enyo/Component~Component#owner} or [bubbling]{@link module:enyo/Component~Component#bubble} it.
* The [context]{@link module:enyo/Animator~Animator#context} property may be used to call the supplied
* event functions in a particular `this` context.
-*
+*
* During animation, an {@link module:enyo/jobs} priority of 5 is registered to defer low priority
* tasks.
*
@@ -79,14 +80,14 @@ module.exports = kind(
/**
* A context in which to run the specified {@glossary event} handlers. If this is
* not specified or is falsy, then the [global object]{@glossary global} is used.
- *
+ *
* @name context
* @type {Object}
* @default undefined
* @memberOf module:enyo/Animator~Animator.prototype
* @public
*/
-
+
name: 'enyo.Animator',
/**
@@ -97,10 +98,10 @@ module.exports = kind(
/**
* @private
*/
- published:
+ published:
/** @lends module:enyo/Animator~Animator.prototype */ {
-
- /**
+
+ /**
* Animation duration in milliseconds
*
* @type {Number}
@@ -109,7 +110,7 @@ module.exports = kind(
*/
duration: 350,
- /**
+ /**
* Value of [value]{@link module:enyo/Animator~Animator#value} property at the beginning of an animation.
*
* @type {Number}
@@ -118,7 +119,7 @@ module.exports = kind(
*/
startValue: 0,
- /**
+ /**
* Value of [value]{@link module:enyo/Animator~Animator#value} property at the end of an animation.
*
* @type {Number}
@@ -127,8 +128,8 @@ module.exports = kind(
*/
endValue: 1,
- /**
- * Node that must be visible in order for the animation to continue. This reference is
+ /**
+ * Node that must be visible in order for the animation to continue. This reference is
* destroyed when the animation ceases.
*
* @type {Object}
@@ -137,17 +138,17 @@ module.exports = kind(
*/
node: null,
- /**
- * [Function]{@glossary Function} that determines how the animation progresses from
+ /**
+ * [Function]{@glossary Function} that determines how the animation progresses from
* [startValue]{@link module:enyo/Animator~Animator#startValue} to [endValue]{@link module:enyo/Animator~Animator#endValue}.
- *
+ *
* @type {Function}
* @default module:enyo/easing~easing.cubicOut
* @public
*/
- easingFunction: animation.easing.cubicOut
+ easingFunction: easing.cubicOut
},
-
+
/*
* @private
*/
@@ -179,7 +180,7 @@ module.exports = kind(
};
}),
- /**
+ /**
* Plays the animation.
*
* @param {Object} props - As a convenience, this [hash]{@glossary Object} will be mixed
@@ -203,7 +204,7 @@ module.exports = kind(
return this;
},
- /**
+ /**
* Stops the animation and fires the associated {@glossary event}.
*
* @fires module:enyo/Animator~Animator#onStop
@@ -235,9 +236,9 @@ module.exports = kind(
return this;
},
- /**
+ /**
* Reverses the direction of a running animation.
- *
+ *
* @return {this} The callee for chaining.
* @public
*/
@@ -277,7 +278,7 @@ module.exports = kind(
* @private
*/
cancel: function () {
- animation.cancelRequestAnimationFrame(this.job);
+ animation.cancelAnimationFrame(this.job);
this.node = null;
this.job = null;
diff --git a/src/BackgroundTaskManager.js b/src/BackgroundTaskManager.js
index 58fa189c6..039e21c89 100644
--- a/src/BackgroundTaskManager.js
+++ b/src/BackgroundTaskManager.js
@@ -2,6 +2,7 @@ require('enyo');
/**
* Returns the BackgroundTaskManager singleton.
+* @wip
* @module enyo/BackgroundTaskManager
*/
diff --git a/src/Binding.js b/src/Binding.js
index 79aeafc4b..1d627e60a 100644
--- a/src/Binding.js
+++ b/src/Binding.js
@@ -95,8 +95,13 @@ function ready (binding) {
/*jshint +W093 */
}
+
+/**
+* @class PassiveBinding
+* @public
+*/
var PassiveBinding = kind(
- /** @lends enyo.PassiveBinding.prototype */ {
+ /** @lends module:enyo/Binding~PassiveBinding.prototype */ {
name: 'enyo.PassiveBinding',
@@ -680,4 +685,8 @@ exports.DIRTY_TO = DIRTY_TO;
*/
exports.defaultBindingKind = exports;
+/**
+* The kind declaration for the [PassiveBinding]{@link module:enyo/Binding~PassiveBinding} kind
+* @public
+*/
exports.PassiveBinding = PassiveBinding;
diff --git a/src/Checkbox/Checkbox.js b/src/Checkbox/Checkbox.js
index d58885aa8..812988201 100644
--- a/src/Checkbox/Checkbox.js
+++ b/src/Checkbox/Checkbox.js
@@ -7,8 +7,7 @@ require('enyo');
var
kind = require('../kind'),
- utils = require('../utils'),
- platform = require('../platform');
+ utils = require('../utils');
var
Input = require('../Input');
@@ -60,36 +59,36 @@ module.exports = kind(
/**
* @private
*/
- published:
+ published:
/** @lends module:enyo/Checkbox~Checkbox.prototype */ {
-
+
/**
* Value of the checkbox; will be `true` if checked.
- *
+ *
* @type {Boolean}
* @default false
* @public
*/
checked: false,
-
+
/**
* A [Group API]{@link module:enyo/Group~Group} requirement for determining the selected item.
- *
+ *
* @type {Boolean}
* @default false
* @public
*/
active: false,
-
+
/**
* @private
*/
type: 'checkbox'
},
-
+
/**
* Disable classes inherited from {@link module:enyo/Input~Input}.
- *
+ *
* @private
*/
kindClasses: "",
@@ -98,8 +97,7 @@ module.exports = kind(
* @private
*/
handlers: {
- onchange: 'change',
- onclick: 'click'
+ onchange: 'change'
},
/**
@@ -129,7 +127,7 @@ module.exports = kind(
* The [active]{@link module:enyo/Checkbox~Checkbox#active} property and `onActivate`
* {@glossary event} are part of the [GroupItem]{@link module:enyo/GroupItem~GroupItem}
* interface supported by this [object]{@glossary Object}.
- *
+ *
* @private
*/
activeChanged: function () {
@@ -139,7 +137,7 @@ module.exports = kind(
},
/**
- * All [input]{@link module:enyo/Input~Input} type [controls]{@link module:enyo/Control~Control} support the
+ * All [input]{@link module:enyo/Input~Input} type [controls]{@link module:enyo/Control~Control} support the
* [value]{@link module:enyo/Input~Input#value} property.
*
* @param {Boolean} val - Whether or not the [checkbox]{@link module:enyo/Checkbox~Checkbox} should
@@ -167,32 +165,19 @@ module.exports = kind(
* @private
*/
valueChanged: function () {
+ // inherited behavior is to set "value" attribute and node-property
+ // which does not apply to checkbox (uses "checked") so
+ // we squelch the inherited method
+ },
/**
* @private
*/
- // inherited behavior is to set "value" attribute and node-property
- // which does not apply to checkbox (uses "checked") so
- // we squelch the inherited method
- },
change: function () {
var nodeChecked = utils.isTrue(this.getNodeProperty('checked'));
this.setActive(nodeChecked);
},
- /**
- * @private
- */
- click: function (sender, e) {
- // Various versions of IE (notably IE8) do not fire 'onchange' for
- // checkboxes, so we discern change via 'click'.
- // Note: keyboard interaction (e.g. pressing space when focused) fires
- // a click event.
- if (platform.ie <= 8) {
- this.bubble('onchange', e);
- }
- },
-
// Accessibility
/**
diff --git a/src/Collection.js b/src/Collection.js
index 21241f53a..d3df3b700 100644
--- a/src/Collection.js
+++ b/src/Collection.js
@@ -157,7 +157,7 @@ var BaseCollection = kind({
* {@link module:enyo/Collection~Collection#options}. Note that some properties have different
* meanings in different contexts. Please review the descriptions below to see
* how each property is used in this context.
-*
+*
* @typedef {module:enyo/Collection~Options} module:enyo/Collection~AddOptions
* @property {Boolean} merge - Update existing [models]{@link module:enyo/Model~Model} when found.
* @property {Boolean} purge - Remove existing models not in the new dataset.
@@ -186,7 +186,7 @@ var BaseCollection = kind({
* {@link module:enyo/Collection~Options}. Note that some properties have different
* meanings in different contexts. Please review the descriptions below to see
* how each property is used in this context.
-*
+*
* @typedef {module:enyo/Collection~Options} module:enyo/Collection~RemoveOptions
* @property {Boolean} silent - Emit [events]{@glossary event} and notifications.
* @property {Boolean} commit - [Commit]{@link module:enyo/Collection~Collection#commit} changes to the
@@ -250,7 +250,7 @@ var BaseCollection = kind({
/**
* An array-like structure designed to store instances of {@link module:enyo/Model~Model}.
-*
+*
* @class Collection
* @extends module:enyo/Component~Component
* @mixes module:enyo/StateSupport~StateSupport
@@ -259,19 +259,19 @@ var BaseCollection = kind({
*/
exports = module.exports = kind(
/** @lends module:enyo/Collection~Collection.prototype */ {
-
+
name: 'enyo.Collection',
-
+
/**
* @private
*/
kind: BaseCollection,
-
+
/**
* @private
*/
-
+
/**
* Used by various [sources]{@link module:enyo/Collection~Collection#source} as part of the
* [URI]{@glossary URI} from which they may be [fetched]{@link module:enyo/Collection~Collection#fetch},
@@ -287,7 +287,7 @@ exports = module.exports = kind(
* @public
*/
url: '',
-
+
/**
* Implement this method to be used by [sources]{@link module:enyo/Model~Model#source} to
* dynamically derive the [URI]{@glossary URI} from which they may be
@@ -307,19 +307,19 @@ exports = module.exports = kind(
* @public
*/
getUrl: null,
-
+
/**
* The [kind]{@glossary kind) of {@link module:enyo/Model~Model} that this
* [collection]{@link module:enyo/Collection~Collection} will contain. This is important to set properly so
* that when [fetching]{@link module:enyo/Collection~Collection#fetch}, the returned data will be instanced
* as the correct model [subkind]{@glossary subkind}.
- *
- * @type {(module:enyo/Model~Model|String)}
+ *
+ * @type module:enyo/Model~Model
* @default module:enyo/Model~Model
* @public
*/
model: Model,
-
+
/**
* A special type of [array]{@glossary Array} used internally by
* {@link module:enyo/Collection~Collection}. The array should not be modified directly, nor
@@ -335,7 +335,7 @@ exports = module.exports = kind(
* @protected
*/
models: null,
-
+
/**
* The current [state]{@link module:enyo/States} of the [collection]{@link module:enyo/Collection~Collection}.
* This value changes automatically and may be observed for more complex state
@@ -348,14 +348,14 @@ exports = module.exports = kind(
* @see module:enyo/StateSupport
*/
status: States.READY,
-
+
/**
* The configurable default [options]{@link module:enyo/Collection~Options}. These values will be
* used to modify the behavior of the [collection]{@link module:enyo/Collection~Collection} unless additional
* options are passed into the methods that use them. When modifying these values in a
* [subkind]{@glossary subkind} of {@link module:enyo/Collection~Collection}, they will be merged with
* existing values.
- *
+ *
* @type {module:enyo/Collection~Options}
* @public
*/
@@ -373,7 +373,7 @@ exports = module.exports = kind(
fetch: false,
modelEvents: true
},
-
+
/**
* Modifies the structure of data so that it can be used by the
* [add()]{@link module:enyo/Collection~Collection#add} method. This method will only be used
@@ -383,7 +383,7 @@ exports = module.exports = kind(
* data coming from a [source]{@link module:enyo/Collection~Collection#source} that requires
* modification before it can be added to the [collection]{@link module:enyo/Collection~Collection}.
* This is a virtual method and must be implemented.
- *
+ *
* @param {*} data - The incoming data passed to the
* [constructor]{@link module:enyo/Collection~Collection#constructor} or returned by a successful
* [fetch]{@link module:enyo/Collection~Collection#fetch}.
@@ -395,7 +395,7 @@ exports = module.exports = kind(
parse: function (data) {
return data;
},
-
+
/**
* Adds data to the [collection]{@link module:enyo/Collection~Collection}. This method can add an
* individual [model]{@link module:enyo/Model~Model} or an [array]{@glossary Array} of models.
@@ -406,7 +406,7 @@ exports = module.exports = kind(
* optimized for batch operations on arrays of models. For better performance,
* ensure that loops do not consecutively call this method but instead
* build an array to pass as the first parameter.
- *
+ *
* @fires module:enyo/Collection~Collection#add
* @param {(Object|Object[]|module:enyo/Model~Model|module:enyo/Model~Model[])} models The data to add to the
* {@link module:enyo/Collection~Collection} that can be a [hash]{@glossary Object}, an array of
@@ -428,16 +428,16 @@ exports = module.exports = kind(
, idx = len
, removedBeforeIdx = 0
, added, keep, removed, model, attrs, found, id;
-
+
// for backwards compatibility with earlier api standards we allow the
// second paramter to be the index and third param options when
// necessary
!isNaN(opts) && (idx = opts);
arguments.length > 2 && (opts = arguments[2]);
-
+
// normalize options so we have values
opts = opts? utils.mixin({}, [options, opts]): options;
-
+
// our flags
var merge = opts.merge
, purge = opts.purge
@@ -449,50 +449,50 @@ exports = module.exports = kind(
, create = opts.create !== false
, modelOpts = opts.modelOptions
, index = opts.index;
-
+
idx = !isNaN(index) ? Math.max(0, Math.min(len, index)) : idx;
/*jshint -W018 */
sort && !(typeof sort == 'function') && (sort = this.comparator);
/*jshint +W018 */
-
+
// for a special case purge to remove records that aren't in the current
// set being added
-
+
if (parse) models = this.parse(models);
-
+
// we treat all additions as an array of additions
!(models instanceof Array) && (models = [models]);
-
+
for (var i=0, end=models.length; i -1) it._waiting.splice(idx, 1);
if (!it._waiting.length) it._waiting = null;
}
-
+
// continue the operation this time with commit false explicitly
if (!it._waiting) {
options.commit = options.source = null;
@@ -999,9 +1011,9 @@ exports = module.exports = kind(
}
if (opts && opts.success) opts.success(this, opts, res, source);
};
-
+
options.error = function (source, res) {
-
+
if (it._waiting) {
idx = it._waiting.findIndex(function (ln) {
return (ln instanceof Source ? ln.name : ln) == source;
@@ -1009,38 +1021,39 @@ exports = module.exports = kind(
if (idx > -1) it._waiting.splice(idx, 1);
if (!it._waiting.length) it._waiting = null;
}
-
+
// continue the operation this time with commit false explicitly
if (!it._waiting) {
options.commit = options.source = null;
it.destroy(options);
}
-
- // we don't bother setting the error state if we aren't waiting because
+
+ // we don't bother setting the error state if we aren't waiting because
// it will be cleared to DESTROYED and it would be pointless
else this.errored('DESTROYING', opts, res, source);
};
-
+
this.set('status', (this.status | States.DESTROYING) & ~States.READY);
-
+
Source.execute('destroy', this, options);
} else if (this.status & States.ERROR) this.errored(this.status, opts);
-
+
// we don't allow the destroy to take place and we don't forcibly break-down
// the collection errantly so there is an opportuniy to resolve the issue
// before we lose access to the collection's content!
return this;
}
-
- if (this.length && options.destroy) this.empty(options);
-
+
+ // remove the models from the collection which will also remove the its event listeners
+ if (this.length) this.empty(options);
+
// set the final resting state of this collection
this.set('status', States.DESTROYED);
-
+
sup.apply(this, arguments);
};
}),
-
+
/**
* This is a virtual method that, when provided, will be used for sorting during
* [add()]{@link module:enyo/Collection~Collection#add} when the `sort` flag is `true` or when the
@@ -1055,7 +1068,7 @@ exports = module.exports = kind(
* @public
*/
comparator: null,
-
+
/**
* Used during [add()]{@link module:enyo/Collection~Collection#add} when `create` is `true` and
* the data is a [hash]{@glossary Object}.
@@ -1066,19 +1079,19 @@ exports = module.exports = kind(
var Ctor = this.model
, options = this.options
, model;
-
+
attrs instanceof Ctor && (model = attrs);
if (!model) {
opts = opts || {};
opts.noAdd = true;
model = new Ctor(attrs, null, opts);
}
-
+
if (options.modelEvents) model.on('*', this._modelEvent, this);
-
+
return model;
},
-
+
/**
* When a [commit]{@link module:enyo/Collection~Collection#commit} has completed successfully, it is returned
* to this method. This method handles special and important behavior; it should not be
@@ -1099,7 +1112,7 @@ exports = module.exports = kind(
*/
committed: function (opts, res, source) {
var idx;
-
+
if (this._waiting) {
idx = this._waiting.findIndex(function (ln) {
return (ln instanceof Source ? ln.name : ln) == source;
@@ -1107,15 +1120,15 @@ exports = module.exports = kind(
if (idx > -1) this._waiting.splice(idx, 1);
if (!this._waiting.length) this._waiting = null;
}
-
+
if (opts && opts.success) opts.success(this, opts, res, source);
-
+
// clear the state
if (!this._waiting) {
this.set('status', (this.status | States.READY) & ~States.COMMITTING);
}
},
-
+
/**
* When a [fetch]{@link module:enyo/Collection~Collection#fetch} has completed successfully, it is returned
* to this method. This method handles special and important behavior; it should not be
@@ -1136,7 +1149,7 @@ exports = module.exports = kind(
*/
fetched: function (opts, res, source) {
var idx;
-
+
if (this._waiting) {
idx = this._waiting.findIndex(function (ln) {
return (ln instanceof Source ? ln.name : ln) == source;
@@ -1144,22 +1157,22 @@ exports = module.exports = kind(
if (idx > -1) this._waiting.splice(idx, 1);
if (!this._waiting.length) this._waiting = null;
}
-
+
// if there is a result we add it to the collection passing it any per-fetch options
// that will override the defaults (e.g. parse) we don't do that here as it will
// be done in the add method -- also note we reassign the result to whatever was
// actually added and pass that to any other success callback if there is one
if (res) res = this.add(res, opts);
-
+
// now look for an additional success callback
if (opts && opts.success) opts.success(this, opts, res, source);
-
+
// clear the state
if (!this._waiting) {
this.set('status', (this.status | States.READY) & ~States.FETCHING);
}
},
-
+
/**
* If an error is encountered while [fetching]{@link module:enyo/Collection~Collection#fetch},
* [committing]{@link module:enyo/Collection~Collection#commit}, or [destroying]{@link module:enyo/Collection~Collection#destroy}
@@ -1168,7 +1181,7 @@ exports = module.exports = kind(
* property and then checks to see if there is a provided
* [error handler]{@link module:enyo/Collection~Collection~Error}. If the error handler
* exists, it will be called.
- *
+ *
* @param {String} action - The name of the action that failed,
* one of `'FETCHING'` or `'COMMITTING'`.
* @param {module:enyo/Collection~Collection~ActionOptions} opts - The options hash originally
@@ -1180,25 +1193,25 @@ exports = module.exports = kind(
*/
errored: function (action, opts, res, source) {
var stat;
-
+
// if the error action is a status number then we don't need to update it otherwise
// we set it to the known state value
if (typeof action == 'string') {
-
+
// all built-in errors will pass this as their values are > 0 but we go ahead and
// ensure that no developer used the 0x00 for an error code
stat = States['ERROR_' + action];
} else stat = action;
-
+
if (isNaN(stat) || !(stat & States.ERROR)) stat = States.ERROR_UNKNOWN;
-
+
// if it has changed give observers the opportunity to respond
this.set('status', (this.status | stat) & ~States.READY);
-
+
// we need to check to see if there is an options handler for this error
if (opts && opts.error) opts.error(this, action, opts, res, source);
},
-
+
/**
* Overloaded version of the method to call [set()]{@link module:enyo/Collection~Collection#set}
* instead of simply assigning the value. This allows it to
@@ -1211,7 +1224,7 @@ exports = module.exports = kind(
clearError: function () {
return this.set('status', States.READY);
},
-
+
/**
* @private
*/
@@ -1225,7 +1238,7 @@ exports = module.exports = kind(
break;
}
},
-
+
/**
* Responds to changes to the [models]{@link module:enyo/Collection~Collection#models} property.
*
@@ -1237,12 +1250,12 @@ exports = module.exports = kind(
modelsChanged: function (was, is, prop) {
var models = this.models.copy(),
len = models.length;
-
+
if (len != this.length) this.set('length', len);
-
+
this.emit('reset', {models: models, collection: this});
},
-
+
/**
* Initializes the [collection]{@link module:enyo/Collection~Collection}.
*
@@ -1259,48 +1272,51 @@ exports = module.exports = kind(
constructor: kind.inherit(function (sup) {
return function (recs, props, opts) {
// opts = opts? (this.options = enyo.mixin({}, [this.options, opts])): this.options;
-
+
// if properties were passed in but not a records array
props = recs && !(recs instanceof Array)? recs: props;
if (props === recs) recs = null;
// initialize our core records
// this.models = this.models || new ModelList();
!this.models && (this.set('models', new ModelList()));
-
+
// this is backwards compatibility
if (props && props.records) {
recs = recs? recs.concat(props.records): props.records.slice();
delete props.records;
}
-
+
if (props && props.models) {
recs = recs? recs.concat(props.models): props.models.slice();
delete props.models;
}
-
+
if (props && props.options) {
this.options = utils.mixin({}, [this.options, props.options]);
delete props.options;
+ } else {
+ // ensure we have our own copy of options
+ this.options = utils.clone(this.options);
}
-
+
opts = opts? utils.mixin({}, [this.options, opts]): this.options;
-
+
// @TODO: For now, while there is only one property we manually check for it
// if more options arrise that should be configurable this way it may need to
// be modified
opts.fetch && (this.options.fetch = opts.fetch);
-
+
this.length = this.models.length;
this.euid = utils.uid('c');
-
+
sup.call(this, props);
-
+
typeof this.model == 'string' && (this.model = kind.constructorForKind(this.model));
this.store = this.store || Store;
recs && recs.length && this.add(recs, opts);
};
}),
-
+
/**
* @method
* @private
@@ -1308,12 +1324,12 @@ exports = module.exports = kind(
constructed: kind.inherit(function (sup) {
return function () {
sup.apply(this, arguments);
-
+
// automatically attempt a fetch after initialization is complete
if (this.options.fetch) this.fetch();
};
})
-
+
});
/**
@@ -1323,7 +1339,7 @@ exports = module.exports = kind(
*/
exports.concat = function (ctor, props) {
var proto = ctor.prototype || ctor;
-
+
if (props.options) {
proto.options = utils.mixin({}, [proto.options, props.options]);
delete props.options;
diff --git a/src/Component.js b/src/Component.js
index 541d5cbd0..ea9cf0f77 100644
--- a/src/Component.js
+++ b/src/Component.js
@@ -14,6 +14,7 @@ var
CoreObject = require('./CoreObject'),
ApplicationSupport = require('./ApplicationSupport'),
ComponentBindingSupport = require('./ComponentBindingSupport'),
+ AnimationSupport = require('./AnimationSupport/AnimationSupport'),
Jobs = require('./jobs');
var
@@ -43,7 +44,7 @@ var
* var c = new Component({
* name: 'me',
* components: [
-* {kind: 'Component', name: 'other'}
+* {kind: Component, name: 'other'}
* ]
* });
*
@@ -55,7 +56,7 @@ var
* var c = new Component({
* name: 'me',
* components: [
-* {kind: 'Component', name: 'other'}
+* {kind: Component, name: 'other'}
* ]
* });
*
@@ -83,7 +84,7 @@ var
* var c = new Component({
* name: 'me',
* components: [
-* {kind: 'Component', name: 'other', publish: true}
+* {kind: Component, name: 'other', publish: true}
* ]
* });
*
diff --git a/src/Control/fullscreen.js b/src/Control/fullscreen.js
index 82e128bd5..8a6144b84 100644
--- a/src/Control/fullscreen.js
+++ b/src/Control/fullscreen.js
@@ -236,12 +236,9 @@ module.exports = function (Control) {
* @private
*/
ready(function() {
- // no need for IE8 fallback, since it won't ever send this event
- if (document.addEventListener) {
- document.addEventListener('webkitfullscreenchange', utils.bind(fullscreen, 'detectFullscreenChangeEvent'), false);
- document.addEventListener('mozfullscreenchange', utils.bind(fullscreen, 'detectFullscreenChangeEvent'), false);
- document.addEventListener('fullscreenchange', utils.bind(fullscreen, 'detectFullscreenChangeEvent'), false);
- }
+ document.addEventListener('webkitfullscreenchange', utils.bind(fullscreen, 'detectFullscreenChangeEvent'), false);
+ document.addEventListener('mozfullscreenchange', utils.bind(fullscreen, 'detectFullscreenChangeEvent'), false);
+ document.addEventListener('fullscreenchange', utils.bind(fullscreen, 'detectFullscreenChangeEvent'), false);
});
/**
diff --git a/src/DataGridList/DataGridList.js b/src/DataGridList/DataGridList.js
index ba2c9e5ad..c63193485 100644
--- a/src/DataGridList/DataGridList.js
+++ b/src/DataGridList/DataGridList.js
@@ -80,7 +80,7 @@ var DataGridList = module.exports = kind(
* @method
* @private
*/
- constructor: kind.inherit(function (sup) {
+ create: kind.inherit(function (sup) {
return function () {
var o = this.orientation;
// this will only remap _vertical_ and _horizontal_ meaning it is still possible to
diff --git a/src/DataList/DataList.js b/src/DataList/DataList.js
index 7bce1a45e..d65eb00dc 100644
--- a/src/DataList/DataList.js
+++ b/src/DataList/DataList.js
@@ -643,7 +643,12 @@ var DataList = module.exports = kind(
*
* @private
*/
- statics: {delegates: {vertical: VerticalDelegate, horizontal: HorizontalDelegate}},
+ statics: /** @lends module:enyo/DataList~DataList */ {
+ /**
+ * @private
+ */
+ delegates: {vertical: VerticalDelegate, horizontal: HorizontalDelegate}
+ },
/**
* An [array]{@glossary Array} of the actual page references for easier access.
diff --git a/src/DataRepeater.js b/src/DataRepeater.js
index 49de3d17c..059988bea 100644
--- a/src/DataRepeater.js
+++ b/src/DataRepeater.js
@@ -769,19 +769,36 @@ var DataRepeater = module.exports = kind(
childMixins: [RepeaterChildSupport],
/**
- * @private
+ * The name of the container specified in
+ * [containerOptions]{@link module:enyo/DataRepeater~DataRepeater#containerOptions}. This may or
+ * may not have the same value as
+ * [controlParentName]{@link module:enyo/DataRepeater~DataRepeater#controlParentName}.
+ *
+ * @type {String}
+ * @default 'container'
+ * @public
*/
- controlParentName: 'container',
+ containerName: 'container',
/**
- * @private
+ * A [Kind]{@glossary Kind} definition that will be used as the chrome for the container
+ * of the DataRepeater. When specifying a custom definition be sure to include a container
+ * component that has the name specified in
+ * [controlParentName]{@link module:enyo/DataRepeater~DataRepeater#controlParentName}.
+ *
+ * @type {Object}
+ * @default {name: 'container', classes: 'enyo-fill enyo-data-repeater-container'}
+ * @public
*/
- containerName: 'container',
+ containerOptions: {name: 'container', classes: 'enyo-fill enyo-data-repeater-container'},
/**
- * @private
+ * See {@link module:enyo/UiComponent~UiComponent#controlParentName}
+ * @type {String}
+ * @default 'container'
+ * @public
*/
- containerOptions: {name: 'container', classes: 'enyo-fill enyo-data-repeater-container'},
+ controlParentName: 'container',
/**
* @private
diff --git a/src/EventEmitter.js b/src/EventEmitter.js
index 954f67968..38bb50135 100644
--- a/src/EventEmitter.js
+++ b/src/EventEmitter.js
@@ -6,6 +6,7 @@
require('enyo');
var
+ kind = require('./kind'),
utils = require('./utils');
var
@@ -21,7 +22,7 @@ function addListener(obj, e, fn, ctx) {
method: fn,
ctx: ctx || obj
});
-
+
return obj;
}
@@ -31,14 +32,14 @@ function addListener(obj, e, fn, ctx) {
function removeListener(obj, e, fn, ctx) {
var listeners = obj.listeners()
, idx;
-
+
if (listeners.length) {
idx = listeners.findIndex(function (ln) {
return ln.event == e && ln.method === fn && (ctx? ln.ctx === ctx: true);
});
idx >= 0 && listeners.splice(idx, 1);
}
-
+
return obj;
}
@@ -49,7 +50,7 @@ function emit(obj, args) {
var len = args.length
, e = args[0]
, listeners = obj.listeners(e);
-
+
if (listeners.length) {
if (len > 1) {
args = utils.toArray(args);
@@ -59,10 +60,10 @@ function emit(obj, args) {
}
for (var i=0, ln; (ln=listeners[i]); ++i) ln.method.apply(ln.ctx, args);
-
+
return true;
}
-
+
return false;
}
@@ -70,29 +71,29 @@ function emit(obj, args) {
* {@link module:enyo/EventEmitter~EventEmitter} is a {@glossary mixin} that adds support for
* registered {@glossary event} listeners. These events are different from
* bubbled events (e.g., DOM events and [handlers]{@link module:enyo/Component~Component#handlers}).
-* When [emitted]{@link module:enyo/EventEmitter~EventEmitter#emit}, these events **do not bubble**
-* and will only be handled by [registered listeners]{@link module:enyo/EventEmitter~EventEmitter#on}.
+* When [emitted]{@link module:enyo/EventEmitter~EventEmitter.emit}, these events **do not bubble**
+* and will only be handled by [registered listeners]{@link module:enyo/EventEmitter~EventEmitter.on}.
*
* @mixin
* @public
*/
var EventEmitter = {
-
+
/**
* @private
*/
name: 'EventEmitter',
-
+
/**
* @private
*/
_silenced: false,
-
+
/**
* @private
*/
_silenceCount: 0,
-
+
/**
* Disables propagation of [events]{@glossary event}. This is a counting
* semaphor and [unsilence()]{@link module:enyo/EventEmitter~EventEmitter.unsilence} will need to
@@ -107,7 +108,7 @@ var EventEmitter = {
this._silenceCount++;
return this;
},
-
+
/**
* Enables propagation of [events]{@glossary event}. This is a counting
* semaphor and this method will need to be called the same number of times
@@ -127,7 +128,7 @@ var EventEmitter = {
}
return this;
},
-
+
/**
* Determines whether the callee is currently [silenced]{@link module:enyo/EventEmitter~EventEmitter.silence}.
*
@@ -138,20 +139,19 @@ var EventEmitter = {
isSilenced: function () {
return this._silenced;
},
-
+
/**
- * @alias enyo.EventEmitter.on
- * @deprecated
+ * @deprecated Replaced by {@link module:enyo/EventEmitter~EventEmitter.on}
* @public
*/
addListener: function (e, fn, ctx) {
return addListener(this, e, fn, ctx);
},
-
+
/**
* Adds an {@glossary event} listener. Until [removed]{@link module:enyo/EventEmitter~EventEmitter.off},
* this listener will fire every time the event is
- * [emitted]{@link module:enyo/EventEmitter~EventEmitter#emit}.
+ * [emitted]{@link module:enyo/EventEmitter~EventEmitter.emit}.
*
* @param {String} e - The {@glossary event} name to register for.
* @param {Function} fn - The listener.
@@ -162,16 +162,15 @@ var EventEmitter = {
on: function (e, fn, ctx) {
return addListener(this, e, fn, ctx);
},
-
+
/**
- * @alias enyo.EventEmitter.off
- * @deprecated
+ * @deprecated Replaced by {@link module:enyo/EventEmitter~EventEmitter.off}
* @public
*/
removeListener: function (e, fn, ctx) {
return removeListener(this, e, fn, ctx);
},
-
+
/**
* Removes an {@glossary event} listener.
*
@@ -185,7 +184,7 @@ var EventEmitter = {
off: function (e, fn, ctx) {
return removeListener(this, e, fn, ctx);
},
-
+
/**
* Removes all listeners, or all listeners for a given {@glossary event}.
*
@@ -195,20 +194,20 @@ var EventEmitter = {
removeAllListeners: function (e) {
var euid = this.euid
, loc = euid && eventTable[euid];
-
+
if (loc) {
if (e) {
eventTable[euid] = loc.filter(function (ln) {
return ln.event != e;
});
} else {
- eventTable[euid] = null;
+ delete eventTable[euid];
}
}
-
+
return this;
},
-
+
/**
* Primarily intended for internal use, this method returns an immutable copy
* of all listeners, or all listeners for a particular {@glossary event} (if any).
@@ -222,21 +221,20 @@ var EventEmitter = {
listeners: function (e) {
var euid = this.euid || (this.euid = utils.uid('e'))
, loc = eventTable[euid] || (eventTable[euid] = []);
-
+
return !e? loc: loc.filter(function (ln) {
return ln.event == e || ln.event == '*';
});
},
-
+
/**
- * @alias enyo.EventEmitter.emit
- * @deprecated
+ * @deprecated Replaced by {@link module:enyo/EventEmitter~EventEmitter.emit}
* @public
*/
triggerEvent: function () {
return !this._silenced? emit(this, arguments): false;
},
-
+
/**
* Emits the named {@glossary event}. All subsequent arguments will be passed
* to the event listeners.
@@ -248,7 +246,17 @@ var EventEmitter = {
*/
emit: function () {
return !this._silenced? emit(this, arguments): false;
- }
+ },
+
+ /**
+ * @private
+ */
+ destroy: kind.inherit(function (sup) {
+ return function () {
+ sup.apply(this, arguments);
+ this.removeAllListeners();
+ };
+ })
};
module.exports = EventEmitter;
diff --git a/src/Filter.js b/src/Filter.js
index a8927993c..755d75541 100644
--- a/src/Filter.js
+++ b/src/Filter.js
@@ -14,7 +14,7 @@ var Collection = require('./Collection');
/**
* Used internally (re-use) for filters that do not have a valid filter. This means they will
* always keep a mirrored copy of the entire current dataset of the parent filter.
-*
+*
* @private
*/
function alwaysTrue () {
@@ -28,31 +28,31 @@ function alwaysTrue () {
* collection, which keeps its own set of [model]{@link module:enyo/Model~Model} instances (and can
* create, remove, or destroy them), an {@link module:enyo/Filter~Filter} uses another instance of
* `enyo.Collection` as its dataset and safely proxies its models as a complete set or
-* according to the needs of its subkind. `enyo.Filter` is not intended to communicate
+* according to the needs of its subkind. `enyo/Filter` is not intended to communicate
* with [sources]{@link module:enyo/Source~Source} (e.g., via [fetch()]{@link module:enyo/Collection~Collection#fetch}).
* It maintains an implementation-specific API (from its subkinds) and propagates the
-* events and APIs inherited from `enyo.Collection` that are needed to interact with
+* events and APIs inherited from `enyo/Collection` that are needed to interact with
* [controls]{@link module:enyo/Control~Control}.
-*
+*
* @class Filter
* @extends module:enyo/Collection~Collection
* @protected
*/
var Filter = module.exports = kind(
/** @lends module:enyo/Filter~Filter.prototype */ {
-
+
name: 'enyo.Filter',
-
+
/**
* @private
*/
kind: Collection,
-
+
/**
* @private
*/
-
+
/**
* Provide a filter-method that will be applied to each [model]{@link module:enyo/Model~Model} in the
* current set of models. This method will accept parameters according to those supplied
@@ -64,37 +64,37 @@ var Filter = module.exports = kind(
* @public
*/
method: null,
-
+
/**
* The actual {@link module:enyo/Collection~Collection} content to proxy. How the collection is
* used varies depending on the [subkind]{@glossary subkind} implementing the
* feature.
- *
+ *
* @type module:enyo/Collection~Collection
* @default null
* @public
*/
collection: null,
-
+
/**
* Once all components have been created, those that are [filters]{@link module:enyo/Filter~Filter}
* (or [subkinds]{@glossary subkind}) will be added to this [array]{@glossary Array}.
* This array is primarily for internal use and should not be modified directly.
- *
+ *
* @type Array
* @default null
* @readonly
* @public
*/
filters: null,
-
+
/**
* @private
*/
defaultProps: {
kind: null // replaced after the fact
},
-
+
/**
* @private
*/
@@ -102,23 +102,23 @@ var Filter = module.exports = kind(
return function (props) {
// all filters are public...always...except when they aren't...
if (props.publish !== false) props.publish = true;
-
+
sup.apply(this, arguments);
-
+
// now to ensure that there is the correct kind associated with the child component
if (typeof props.kind == 'string') props.kind = kind.constructorForKind(props.kind);
if (props.kind && props.kind.prototype instanceof Filter) {
if (!props.name) {
throw 'enyo.Filter.adjustComponentProps: Child filters must have a name';
}
-
+
// if no method is named explicitly we assume the same name as the filter
if (!props.method) props.method = props.name;
-
+
// most likely it will be a string but it is possible that the filter method
// be declared inline in the component descriptor block
if (typeof props.method == 'string') props.method = this[props.method];
-
+
// we assign an always true method if none exists just because we assume it was
// mean to be a mirror filter for the entire dataset
if (typeof props.method != 'function') {
@@ -128,30 +128,30 @@ var Filter = module.exports = kind(
}
};
}),
-
+
/**
* @private
*/
addComponent: kind.inherit(function (sup) {
return function (comp) {
-
+
// if the component is a filter we add it to the array
if (comp instanceof Filter) this.filters.push(comp);
-
+
return sup.apply(this, arguments);
};
}),
-
+
/**
* Resets the [filter]{@link module:enyo/Filter~Filter} to its initial state. Behavior will
* vary depending on the [subkind]{@glossary subkind} implementation.
- *
+ *
* @virtual
* @method
* @public
*/
reset: utils.nop,
-
+
/**
* @private
*/
@@ -159,16 +159,16 @@ var Filter = module.exports = kind(
return function () {
// ensure we have an array to work with
this.filters = [];
-
+
// unfortunately we must maintain data structures that need remain out of our
// proxy path so we each must create a collection instance for internal use
this._internal = new Collection({options: {modelEvents: false}});
this._internal.on('*', this._internalEvent, this);
-
+
sup.apply(this, arguments);
};
}),
-
+
/**
* @private
*/
@@ -176,37 +176,37 @@ var Filter = module.exports = kind(
return function () {
var collection,
owner;
-
+
sup.apply(this, arguments);
-
+
// we allow filters to be nested so they need to receive events from the
// parent-filter and do with them as they need
this.isChildFilter = ((owner = this.owner) && owner instanceof Filter);
if(this.isChildFilter) {
-
+
// if we're a child collection we don't want to monitor our parent's own state
// we want to monitor their entire dataset
this.collection = owner._internal;
-
+
// register especially for owner events as we will differentiate them from
// normal collection events
this.collection.on('*', this._ownerEvent, this);
}
-
+
collection = this.collection;
-
+
// if there is a collection instance already we need to initialize it
if (collection) this.collectionChanged(null, collection);
};
}),
-
+
/**
* @private
*/
destroy: kind.inherit(function (sup) {
return function () {
var collection = this.collection;
-
+
// make sure that we remove our listener if we're being destroyed for some
// reason (this would seem to be an irregular practice)
if (collection) {
@@ -215,42 +215,42 @@ var Filter = module.exports = kind(
} else {
collection.off('*', this._collectionEvent, this);
}
-
+
collection.unobserve('destroyed', this._collectionDestroyed, this);
}
-
+
sup.apply(this, arguments);
-
+
// free our internal collection
this._internal.destroy();
this._internal = null;
};
}),
-
+
/**
* @private
*/
collectionChanged: function (was, is) {
var internal = this._internal;
-
+
if (was) {
was.off('*', this._collectionEvent, this);
was.unobserve('destroyed', this._collectionDestroyed, this);
}
-
+
// ensure that child-filters cannot have their internal/external collections reset
if (is && !(was && this.isChildFilter && was === this.owner._internal)) {
-
+
// case of child-filter whose collection is its owner does not need to receive
// these events since it will receive them in a special handler to differentiate
// these cases
if (!this.isChildFilter || (is !== this.owner._internal)) {
is.on('*', this._collectionEvent, this);
}
-
+
// if for any reason the collection is destroyed we want to know about it
is.observe('destroyed', this._collectionDestroyed, this);
-
+
// reset the models (causing reset to propagate to children or bound parties)
internal.set('models', is.models.copy());
} else {
@@ -258,7 +258,7 @@ var Filter = module.exports = kind(
if (internal.length) internal.empty();
}
},
-
+
/**
* This method is invoked when events are received from a
* [collection]{@link module:enyo/Collection~Collection} that is not the owner of this
@@ -267,42 +267,42 @@ var Filter = module.exports = kind(
* As long as we are consistent about applying the same action against ourselves,
* we should remain in sync and propagate the same event again, except that
* `sort` will end up being a `reset`.
- *
+ *
* @private
*/
_collectionEvent: function (sender, e, props) {
// we are listening for particular events to signal that we should update according
// to its changes if we are a nested filter
-
+
var models = props.models,
internal = this._internal;
-
+
switch (e) {
case 'add':
-
+
// will ensure an add gets propagated if the models are new
internal.add(models, {merge: false});
break;
case 'reset':
case 'sort':
-
+
// will ensure a reset gets propagated
internal.empty(models);
break;
case 'remove':
-
+
// will ensure a remove gets propagated (assuming something is removed)
internal.remove(models);
break;
case 'change':
-
+
// we need to propagate the change event as our internal collection's own so that
// child filters and/or subclasses will be able to handle this as they need to
internal.emit(e, props);
break;
}
},
-
+
/**
* When the collection is destroyed we can't use it anymore so we need to remove it as our
* collection to prevent weird things from happening.
@@ -312,7 +312,7 @@ var Filter = module.exports = kind(
_collectionDestroyed: function () {
this.set('collection', null);
},
-
+
/**
* To be implemented by [subkind]{@glossary subkind}; for internal use only.
*
@@ -320,7 +320,7 @@ var Filter = module.exports = kind(
* @private
*/
_internalEvent: utils.nop,
-
+
/**
* To be implemented by [subkind]{@glossary subkind}; for internal use only.
*
@@ -328,7 +328,7 @@ var Filter = module.exports = kind(
* @private
*/
_ownerEvent: utils.nop,
-
+
/**
* Unavailable on {@link module:enyo/Filter~Filter} and [subkinds]{@glossary subkind}.
*
@@ -336,7 +336,7 @@ var Filter = module.exports = kind(
* @public
*/
add: utils.nop,
-
+
/**
* Unavailable on {@link module:enyo/Filter~Filter} and [subkinds]{@glossary subkind}.
*
@@ -344,7 +344,7 @@ var Filter = module.exports = kind(
* @public
*/
remove: utils.nop,
-
+
/**
* Unavailable on {@link module:enyo/Filter~Filter} and [subkinds]{@glossary subkind}.
*
@@ -352,7 +352,7 @@ var Filter = module.exports = kind(
* @public
*/
fetch: utils.nop,
-
+
/**
* Unavailable on {@link module:enyo/Filter~Filter} and [subkinds]{@glossary subkind}.
*
@@ -360,7 +360,7 @@ var Filter = module.exports = kind(
* @public
*/
sort: utils.nop,
-
+
/**
* Unavailable on {@link module:enyo/Filter~Filter} and [subkinds]{@glossary subkind}.
*
@@ -368,7 +368,7 @@ var Filter = module.exports = kind(
* @public
*/
commit: utils.nop,
-
+
/**
* Overloaded implementation.
*
@@ -381,7 +381,7 @@ var Filter = module.exports = kind(
return this.models ? sup.apply(this.models.at ? this.models : this, arguments) : undefined;
};
}),
-
+
/**
* Unavailable on {@link module:enyo/Filter~Filter} and [subkinds]{@glossary subkind}.
*
@@ -389,7 +389,7 @@ var Filter = module.exports = kind(
* @public
*/
raw: utils.nop,
-
+
/**
* Unavailable on {@link module:enyo/Filter~Filter} and [subkinds]{@glossary subkind}.
*
@@ -397,7 +397,7 @@ var Filter = module.exports = kind(
* @public
*/
toJSON: utils.nop,
-
+
/**
* Overloaded implementation.
*
@@ -410,7 +410,7 @@ var Filter = module.exports = kind(
return this.models ? sup.apply(this, arguments) : false;
};
}),
-
+
/**
* Overloaded implementation.
*
@@ -423,7 +423,7 @@ var Filter = module.exports = kind(
return this.models ? sup.apply(this, arguments) : undefined;
};
}),
-
+
/**
* Overloaded implementation.
*
@@ -436,7 +436,7 @@ var Filter = module.exports = kind(
return this.models ? sup.apply(this, arguments) : [];
};
}),
-
+
/**
* Overloaded implementation.
*
@@ -449,7 +449,7 @@ var Filter = module.exports = kind(
return this.models ? sup.apply(this, arguments) : undefined;
};
}),
-
+
/**
* Overloaded implementation.
*
@@ -462,7 +462,7 @@ var Filter = module.exports = kind(
return this.models ? sup.apply(this, arguments) : [];
};
}),
-
+
/**
* Overloaded implementation.
*
@@ -475,7 +475,7 @@ var Filter = module.exports = kind(
return this.models ? sup.apply(this, arguments) : -1;
};
}),
-
+
/**
* Unavailable on {@link module:enyo/Filter~Filter} and [subkinds]{@glossary subkind}.
*
diff --git a/src/FluxDispatcher.js b/src/FluxDispatcher.js
index e56aac955..723eea776 100644
--- a/src/FluxDispatcher.js
+++ b/src/FluxDispatcher.js
@@ -1,5 +1,6 @@
/**
* Returns the FluxDispatcher singleton.
+* @wip
* @module enyo/FluxDispatcher
*/
diff --git a/src/FluxStore.js b/src/FluxStore.js
index 57ac44915..9ee1bee57 100644
--- a/src/FluxStore.js
+++ b/src/FluxStore.js
@@ -1,5 +1,6 @@
/**
* Contains the declaration for the {@link module:enyo/FluxStore~FluxStore} kind.
+* @wip
* @module enyo/FluxStore
*/
@@ -50,13 +51,6 @@ module.exports = kind(
*/
kind: CoreObject,
-
- /**
- * @private
- */
- data: {},
-
-
/**
* How a store is identitified to the Flux Dispatcher. This ID is used for
* subscribing to a store's state notification change.
@@ -67,6 +61,9 @@ module.exports = kind(
*/
id: -1,
+ /**
+ * @private
+ */
mixins: [EventEmitter, StateSupport],
/**
@@ -78,6 +75,10 @@ module.exports = kind(
*/
source: '',
+ /**
+ * @private
+ * @lends module:enyo/FluxStore~FluxStore.prototype
+ */
published: {
/**
@@ -98,6 +99,7 @@ module.exports = kind(
constructor: kind.inherit(function (sup) {
return function () {
sup.apply(this, arguments);
+ this.reset();
//id the store with the dispatcher
this.id = FluxDispatcher.subscribe();
diff --git a/src/Group/Group.js b/src/Group/Group.js
index eabd555e3..ec72b5cd5 100644
--- a/src/Group/Group.js
+++ b/src/Group/Group.js
@@ -14,7 +14,7 @@ var
* The extended {@glossary event} [object]{@glossary Object} that is provided when the
* [onActiveChanged]{@link module:enyo/Group~Group#onActiveChanged} event is fired.
*
-* @typedef {Object} enyo.Group~ActiveChangedEvent
+* @typedef {Object} module:enyo/Group~Group~ActiveChangedEvent
* @property {module:enyo/Control~Control} active - The active [control]{@link module:enyo/Control~Control} for the
* [group]{@link module:enyo/Group~Group}.
*/
diff --git a/src/History.js b/src/History.js
index eaaeb9890..433ed2688 100644
--- a/src/History.js
+++ b/src/History.js
@@ -227,7 +227,7 @@ var EnyoHistory = module.exports = kind.singleton(
_processing = true;
if (_queue.length) {
this.processQueue();
- } else {
+ } else if (_history.length) {
this.processPopEntry(_history.pop());
}
_processing = false;
@@ -394,7 +394,7 @@ var EnyoHistory = module.exports = kind.singleton(
* @private
*/
handlePop: function (event) {
- if (this.enabled && _history.length) {
+ if (this.enabled) {
this.processState(event.state);
}
},
diff --git a/src/Input/Input.js b/src/Input/Input.js
index a450ca098..4232514fd 100644
--- a/src/Input/Input.js
+++ b/src/Input/Input.js
@@ -198,14 +198,7 @@ module.exports = kind(
rendered: kind.inherit(function (sup) {
return function() {
sup.apply(this, arguments);
-
dispatcher.makeBubble(this, 'focus', 'blur');
-
- //Force onchange event to be bubbled inside Enyo for IE8
- if(platform.ie == 8){
- this.setAttribute('onchange', dispatcher.bubbler);
- }
-
this.disabledChanged();
if (this.defaultFocus) {
this.focus();
@@ -264,8 +257,8 @@ module.exports = kind(
*/
iekeyup: function (sender, e) {
var ie = platform.ie, kc = e.keyCode;
- // input event missing on ie 8, fails to fire on backspace and delete keys in ie 9
- if (ie <= 8 || (ie == 9 && (kc == 8 || kc == 46))) {
+ // input event fails to fire on backspace and delete keys in ie 9
+ if (ie == 9 && (kc == 8 || kc == 46)) {
this.bubble('oninput', e);
}
},
diff --git a/src/Jsonp.js b/src/Jsonp.js
index 83d0f1840..9abd03e9c 100644
--- a/src/Jsonp.js
+++ b/src/Jsonp.js
@@ -38,11 +38,11 @@ var JsonpRequest = module.exports = kind(
* @private
*/
published: {
+ /** @lends module:enyo/Jsonp~JsonpRequest.prototype */
/**
* The URL for the service.
*
- * @memberof enyo.JsonpRequest.prototype
* @type {String}
* @default ''
* @public
@@ -52,7 +52,6 @@ var JsonpRequest = module.exports = kind(
/**
* The optional character set to use to interpret the return data.
*
- * @memberof enyo.JsonpRequest.prototype
* @type {String}
* @default null
* @public
@@ -65,7 +64,6 @@ var JsonpRequest = module.exports = kind(
* This may also be set to `null` in some cases.
*
* @see module:enyo/Jsonp~JsonpRequest.overrideCallback
- * @memberof enyo.JsonpRequest.prototype
* @type {String}
* @default 'callback'
* @public
@@ -77,7 +75,6 @@ var JsonpRequest = module.exports = kind(
* to (attempt to) force a new fetch of the resource instead of reusing a
* local cache.
*
- * @memberof enyo.JsonpRequest.prototype
* @type {Boolean}
* @default true
* @public
@@ -92,7 +89,6 @@ var JsonpRequest = module.exports = kind(
* name and only one [JsonpRequest]{@link module:enyo/Jsonp~JsonpRequest} using this property may
* be active at a time.
*
- * @memberof enyo.JsonpRequest.prototype
* @type {String}
* @default null
* @public
diff --git a/src/LightPanels/LightPanel.js b/src/LightPanels/LightPanel.js
index fe334da90..9af7cffe5 100644
--- a/src/LightPanels/LightPanel.js
+++ b/src/LightPanels/LightPanel.js
@@ -1,5 +1,10 @@
/**
* Contains the declaration for the {@link module:enyo/LightPanels~LightPanel} kind.
+*
+* Note: LightPanel is exported from {@link module:enyo/LightPanels}. This module should not be
+* required directly.
+* @wip
+* @ignore
* @module enyo/LightPanels
*/
@@ -28,8 +33,10 @@ var States = {
* between child components.
*
* @class LightPanel
+* @name module:enyo/LightPanels~LightPanel
* @extends module:enyo/Control~Control
* @ui
+* @wip
* @public
*/
module.exports = kind(
@@ -70,4 +77,4 @@ module.exports = kind(
});
-module.exports.States = States;
\ No newline at end of file
+module.exports.States = States;
diff --git a/src/LightPanels/LightPanels.js b/src/LightPanels/LightPanels.js
index f0ce6b1a7..758ab1f7c 100644
--- a/src/LightPanels/LightPanels.js
+++ b/src/LightPanels/LightPanels.js
@@ -2,6 +2,7 @@ require('enyo');
/**
* Contains the declaration for the {@link module:enyo/LightPanels~LightPanels} kind.
+* @wip
* @module enyo/LightPanels
*/
@@ -68,6 +69,7 @@ var Orientation = {
* @extends module:enyo/Control~Control
* @mixes module:enyo/TaskManagerSupport~TaskManagerSupport
* @mixes module:enyo/ViewPreloadSupport~ViewPreloadSupport
+* @wip
* @ui
* @public
*/
@@ -132,13 +134,13 @@ module.exports = kind(
wrap: false,
/**
- * When `true`, previous panels are automatically popped when moving backwards.
+ * When `true`, previous panels are destroyed when moving backwards.
*
* @type {Boolean}
- * @default true
+ * @default false
* @public
*/
- popOnBack: true,
+ popOnBack: false,
/**
* The amount of time, in milliseconds, to run the transition animation between panels.
@@ -190,6 +192,11 @@ module.exports = kind(
*/
reverseForRtl: false,
+ /**
+ * @private
+ */
+ transitioning: false,
+
/**
* @private
*/
@@ -324,6 +331,16 @@ module.exports = kind(
return (this._panels = this._panels || (this.controlParent || this).children);
},
+ /**
+ * Whether or not we are currently in the midst of a panel transition.
+ *
+ * @return {Boolean} If `true`, we are currently transitioning; otherwise, `false`.
+ * @public
+ */
+ isTransitioning: function () {
+ return this.transitioning;
+ },
+
/*
@@ -336,13 +353,15 @@ module.exports = kind(
* Animates to the specified panel index.
*
* @param {Number} index - The index of the panel we wish to animate a transition to.
+ * @return {Boolean} If `true`, the index to animate to was successful; `false` otherwise (i.e.
+ * if the index is invalid, or another animation is already in progress).
* @public
*/
animateTo: function (index) {
var from = this.index;
this.index = index;
this.notifyObservers('index');
- this.setupTransitions(from, true);
+ return this.setupTransitions(from, true);
},
/**
@@ -390,7 +409,8 @@ module.exports = kind(
* @param {Object} moreInfo - Additional properties to be applied (defaults).
* @param {module:enyo/LightPanels~PushPanelOptions} opts - Additional options to be used during
* panel pushing.
- * @return {Object} The instance of the panel that was created on top of the stack.
+ * @return {Object|undefined} The instance of the panel that was created; if
+ * `undefined`, the panel could not be pushed (i.e. we are currently transitioning).
* @public
*/
pushPanel: function (info, moreInfo, opts) {
@@ -402,7 +422,7 @@ module.exports = kind(
var lastIndex = this.getPanels().length - 1,
nextPanel = this.createPanel(info, moreInfo),
- newIndex = lastIndex + 1;
+ targetIndex = (opts && opts.targetIndex != null) ? opts.targetIndex : lastIndex + 1;
if (this.cacheViews) {
this.pruneQueue([info]);
}
@@ -413,8 +433,8 @@ module.exports = kind(
nextPanel.postTransition();
}
- if (!this.animate || (opts && opts.direct)) this.set('index', newIndex, {force: opts && opts.force});
- else this.animateTo(newIndex);
+ if (!this.animate || (opts && opts.direct)) this.set('index', targetIndex, {force: opts && opts.force});
+ else this.animateTo(targetIndex);
// TODO: When pushing panels after we have gone back (but have not popped), we need to
// adjust the position of the panels after the previous index before our push.
@@ -429,12 +449,12 @@ module.exports = kind(
* @param {Object} moreInfo - Additional properties to be applied (defaults).
* @param {module:enyo/LightPanels~PushPanelOptions} opts - Additional options to be used when
* pushing multiple panels.
- * @return {null|Object[]} Array of the panels that were created on top of the stack, or
- * `null` if panels could not be created.
+ * @return {Object[]|undefined} Array of the panels that were created on top of the stack; if
+ * `undefined`, the panels could not be pushed (i.e. we are currently transitioning).
* @public
*/
pushPanels: function (info, moreInfo, opts) {
- if (this.transitioning) return true;
+ if (this.transitioning) return;
if (opts && opts.purge) {
this.purge();
@@ -469,51 +489,6 @@ module.exports = kind(
return newPanels;
},
- /**
- * Removes panels whose index is either greater than, or less than, the specified value,
- * depending on the direction.
- *
- * @param {Number} index - Index at which to start removing panels.
- * @param {Number} direction - The direction in which we are changing indices. A negative value
- * signifies that we are moving backwards, and want to remove panels whose indices are greater
- * than the current index. Conversely, a positive value signifies that we are moving forwards,
- * and panels whose indices are less than the current index should be removed.
- * @public
- */
- removePanels: function (index, direction) {
- var panels = this.getPanels(),
- i;
-
- if (direction < 0) {
- for (i = panels.length - 1; i > index; i--) {
- this.removePanel(panels[i]);
- }
- } else {
- for (i = 0; i < index; i++) {
- this.removePanel(panels[i], true);
- }
- }
- },
-
- /**
- * Removes the specified panel.
- *
- * @param {Object} panel - The panel to remove.
- * @param {Boolean} [preserve] - If {@link module:enyo/LightPanels~LightPanels#cacheViews} is
- * `true`, this value is used to determine whether or not to preserve the current panel's
- * position in the component hierarchy and on the screen, when caching.
- * @private
- */
- removePanel: function (panel, preserve) {
- if (panel) {
- if (this.cacheViews) {
- this.cacheView(panel, preserve);
- } else {
- panel.destroy();
- }
- }
- },
-
/**
* Replaces the panel(s) at the specified index with panels that will be created via provided
* component definition(s).
@@ -524,25 +499,32 @@ module.exports = kind(
* @param {Number} count - The number of panels we wish to replace.
* @param {Object|Object[]} info - The component definition (or array of component definitions)
* for the replacement panel(s).
+ * @param {module:enyo/LightPanels~PushPanelOptions} opts - Additional options to be used when
+ * pushing multiple panels. Note that for the case of "targetIndex", if this is not specified,
+ * then the default behavior is to display the first replacement panel.
+ * @return {Object|Object[]|undefined} The panel or array of the panels that were pushed; if
+ * `undefined`, the replacement could not be processed (i.e. we are currently transitioning).
* @public
*/
- replaceAt: function (start, count, info) {
- var panels = this.getPanels(),
- insertBefore, commonInfo, end, idx;
+ replaceAt: function (start, count, info, opts) {
+ var panels, panelsToPop, insertBefore, commonInfo, end, panelOpts, targetIndex;
+
+ if (this.transitioning) return;
+ panels = this.getPanels();
start = start < 0 ? panels.length + start : start;
end = start + count;
insertBefore = panels[end];
commonInfo = {addBefore: insertBefore};
+ targetIndex = opts && opts.targetIndex;
+ panelOpts = {direct: true, force: true, targetIndex: targetIndex != null ? targetIndex : start};
- // remove existing panels
- for (idx = end - 1; idx >= start; idx--) {
- this.removePanel(panels[idx]);
- }
+ panelsToPop = panels.splice(start, end - start);
+ this.popQueue = (this.popQueue && this.popQueue.concat(panelsToPop)) || panelsToPop;
// add replacement panels
- if (utils.isArray(info)) this.pushPanels(info, commonInfo, {direct: true, force: true});
- else this.pushPanel(info, commonInfo, {direct: true, force: true});
+ if (utils.isArray(info)) return this.pushPanels(info, commonInfo, panelOpts);
+ else return this.pushPanel(info, commonInfo, panelOpts);
},
@@ -652,13 +634,7 @@ module.exports = kind(
cleanUpPanel: function (panel) {
if (panel) {
panel.set('state', panel === this._currentPanel ? States.ACTIVE : States.INACTIVE);
- if (panel.postTransition) {
- // Async'ing this as it seems to improve ending transition performance on the TV.
- // Requires further investigation into its behavior.
- utils.asyncMethod(this, function () {
- panel.postTransition();
- });
- }
+ panel.postTransition && panel.postTransition();
}
},
@@ -667,31 +643,40 @@ module.exports = kind(
*
* @param {Object} sender - The event sender.
* @param {Object} ev - The event object.
- * @param {Boolean} [direct] - If `true`, this was a non-animated (direct) transition.
* @private
*/
- transitionFinished: function (sender, ev, direct) {
+ transitionFinished: function (sender, ev) {
var prevPanel, currPanel;
- if (this.transitioning && ((ev && ev.originator === this.$.client) || direct)) {
+ if (this.transitioning && (!ev || ev.originator === this.$.client)) {
+ if (this._fallbackTimeout) {
+ global.clearTimeout(this._fallbackTimeout);
+ this._fallbackTimeout = null;
+ }
+
prevPanel = this._previousPanel;
currPanel = this._currentPanel;
- if ((this._indexDirection < 0 && (this.popOnBack || this.cacheViews) && this.index < this.getPanels().length - 1) ||
- (this._indexDirection > 0 && this.cacheViews && this.index > 0)) {
- this.removePanels(this.index, this._indexDirection);
- }
-
if (prevPanel) {
prevPanel.removeClass('shifted');
prevPanel.addClass('offscreen');
}
- this.cleanUpPanel(prevPanel);
- this.cleanUpPanel(currPanel);
-
this.removeClass('transitioning');
this.transitioning = false;
+
+ utils.asyncMethod(this, function () {
+ this.cleanUpPanel(prevPanel);
+ this.cleanUpPanel(currPanel);
+
+ if (this.popQueue && this.popQueue.length) {
+ this.finalizePurge();
+ } else if ((this._indexDirection < 0 && (this.popOnBack || this.cacheViews)
+ && this.index < this.getPanels().length - 1)
+ || (this._indexDirection > 0 && this.cacheViews && this.index > 0)) {
+ this.removePanels(this.index, this._indexDirection);
+ }
+ });
}
},
@@ -721,25 +706,29 @@ module.exports = kind(
* @param {Number} [previousIndex] - The index of the panel we are transitioning from.
* @param {Boolean} [animate] - Whether or not there should be a visible animation when
* transitioning between the current and next panel.
+ * @return {Boolean} If `true`, the transition was setup successfully, otherwise it was not (i.e.
+ * we are currently transitioning or there is no "next" panel to transition to).
* @private
*/
setupTransitions: function (previousIndex, animate) {
- var panels = this.getPanels(),
- nextPanel = panels[this.index],
- currPanel = this._currentPanel,
- shiftCurrent, fnInitiateTransition;
+ var panels, nextPanel, currPanel, shiftCurrent, fnInitiateTransition;
- this._indexDirection = 0;
+ if (this.transitioning) return;
- // handle the wrapping case
- if (this.wrap) {
- if (this.index === 0 && previousIndex == panels.length - 1) this._indexDirection = 1;
- else if (this.index === panels.length - 1 && previousIndex === 0) this._indexDirection = -1;
- }
- if (this._indexDirection === 0 && previousIndex != -1) this._indexDirection = this.index - previousIndex;
+ panels = this.getPanels();
+ nextPanel = panels[this.index];
+ currPanel = this._currentPanel;
if (nextPanel) {
this.transitioning = true;
+ this._indexDirection = 0;
+
+ // handle the wrapping case
+ if (this.wrap) {
+ if (this.index === 0 && previousIndex == panels.length - 1) this._indexDirection = 1;
+ else if (this.index === panels.length - 1 && previousIndex === 0) this._indexDirection = -1;
+ }
+ if (this._indexDirection === 0 && previousIndex != -1) this._indexDirection = this.index - previousIndex;
// prepare the panel that will be deactivated
if (currPanel) {
@@ -770,6 +759,8 @@ module.exports = kind(
if (!this.generated || !animate) fnInitiateTransition();
else animation.requestAnimationFrame(fnInitiateTransition);
+
+ return true;
}
},
@@ -789,7 +780,8 @@ module.exports = kind(
this._currentPanel = nextPanel;
// ensure that `transitionFinished` is called in the case where we are not animating
- if (!this.shouldAnimate() || !animate) this.transitionFinished(null, null, true);
+ if (!this.shouldAnimate() || !animate) this.transitionFinished();
+ else this.setupFallback();
},
/**
@@ -813,15 +805,76 @@ module.exports = kind(
dom.transformValue(container, 'translate' + this.orientation, value + '%');
},
+ /**
+ * Removes panels whose index is either greater than, or less than, the specified value,
+ * depending on the direction.
+ *
+ * @param {Number} index - Index at which to start removing panels.
+ * @param {Number} direction - The direction in which we are changing indices. A negative value
+ * signifies that we are moving backwards, and want to remove panels whose indices are greater
+ * than the current index. Conversely, a positive value signifies that we are moving forwards,
+ * and panels whose indices are less than the current index should be removed.
+ * @private
+ */
+ removePanels: function (index, direction) {
+ var panels = this.getPanels(),
+ i;
+
+ if (direction < 0) {
+ for (i = panels.length - 1; i > index; i--) {
+ this.removePanel(panels[i], this.cacheViews && !this.popOnBack);
+ }
+ } else {
+ for (i = 0; i < index; i++) {
+ this.removePanel(panels[i], this.cacheViews, true);
+ }
+ }
+ },
+
+ /**
+ * Removes the specified panel.
+ *
+ * @param {Object} panel - The panel to remove.
+ * @param {Boolean} cache - Whether or not the panel should be cached; if `false` or not
+ * specified, the panel will instead be destroyed (this is the default behavior).
+ * @param {Boolean} [preserve] - If {@link module:enyo/LightPanels~LightPanels#cacheViews} is
+ * `true`, this value is used to determine whether or not to preserve the current panel's
+ * position in the component hierarchy and on the screen, when caching.
+ * @private
+ */
+ removePanel: function (panel, cache, preserve) {
+ if (panel) {
+ if (cache) {
+ this.cacheView(panel, preserve);
+ } else {
+ if (this.cacheViews) {
+ this.popView(this.getViewId(panel));
+ }
+ panel.destroy();
+ }
+ }
+ },
+
/**
* Destroys all panels.
*
* @private
*/
purge: function () {
- var panels = this.getPanels(),
- panel;
+ var panels = this.getPanels();
+ this.popQueue = panels.slice();
+ panels.length = 0;
+ this.index = -1;
+ },
+ /**
+ * Clean-up any panels queued for destruction.
+ *
+ * @private
+ */
+ finalizePurge: function () {
+ var panels = this.popQueue,
+ panel;
while (panels.length) {
panel = panels.pop();
if (this.cacheViews) {
@@ -831,8 +884,6 @@ module.exports = kind(
panel.destroy();
}
}
-
- this.index = -1;
},
/**
@@ -846,9 +897,20 @@ module.exports = kind(
for (var idx = 0; idx < viewProps.length; idx++) {
this.removeTask(this.getViewId(viewProps[idx]));
}
+ },
+
+ /**
+ * @private
+ */
+ setupFallback: function () {
+ this._fallbackTimeout = global.setTimeout(this.bindSafely('transitionFinished'), this.duration);
}
});
+/**
+* The {@link module:enyo/LightPanels~LightPanel} kind export.
+* @public
+*/
module.exports.Panel = LightPanel;
module.exports.Direction = Direction;
module.exports.Orientation = Orientation;
diff --git a/src/LinkedList.js b/src/LinkedList.js
index 4bddf681c..46651cfe4 100644
--- a/src/LinkedList.js
+++ b/src/LinkedList.js
@@ -19,37 +19,32 @@ var
*/
module.exports = kind(
/** @lends module:enyo/LinkedList~LinkedList.prototype */ {
-
+
/**
* @private
*/
kind: null,
-
- /**
- * @private
- */
-
/**
* @private
*/
nodeKind: LinkedListNode,
-
+
/**
* @private
*/
head: null,
-
+
/**
* @private
*/
tail: null,
-
+
/**
* @private
*/
length: 0,
-
+
/**
* @private
*/
@@ -60,9 +55,9 @@ module.exports = kind(
}
this.head = null;
this.tail = null;
- this.length = 0;
+ this.length = 0;
},
-
+
/**
* @private
*/
@@ -70,20 +65,20 @@ module.exports = kind(
var node = fromNode || this.head
, list = new this.ctor()
, cpy;
-
+
// ensure we have a final node or our tail
toNode = toNode || this.tail;
-
+
if (node && node !== toNode) {
do {
cpy = node.copy();
list.appendNode(cpy);
} while ((node = node.next) && node !== toNode);
}
-
+
return list;
},
-
+
/**
* @private
*/
@@ -91,67 +86,67 @@ module.exports = kind(
this.clear();
this.destroyed = true;
},
-
+
/**
* @private
*/
createNode: function (props) {
return new this.nodeKind(props);
},
-
+
/**
* @private
*/
deleteNode: function (node) {
this.removeNode(node);
-
+
// can't chain destruct because we removed its chain references
node.destroy();
return this;
},
-
+
/**
* @private
*/
removeNode: function (node) {
var prev = node.prev
, next = node.next;
-
+
prev && (prev.next = next);
next && (next.prev = prev);
this.length--;
node.next = node.prev = null;
return this;
},
-
+
/**
* @private
*/
appendNode: function (node, targetNode) {
targetNode = targetNode || this.tail;
-
+
if (targetNode) {
if (targetNode.next) {
node.next = targetNode.next;
}
-
+
targetNode.next = node;
node.prev = targetNode;
-
+
if (targetNode === this.tail) {
this.tail = node;
}
-
+
this.length++;
} else {
-
+
this.head = this.tail = node;
node.prev = node.next = null;
this.length = 1;
}
return this;
},
-
+
/**
* @private
*/
@@ -167,7 +162,7 @@ module.exports = kind(
// if no node qualified it returns false
return false;
},
-
+
/**
* @private
*/
@@ -183,7 +178,7 @@ module.exports = kind(
// returns the last node (if any) that was processed in the chain
return node;
},
-
+
/**
* @private
*/
@@ -199,7 +194,7 @@ module.exports = kind(
// returns the last node (if any) that was processed in the chain
return node;
},
-
+
/**
* @private
*/
diff --git a/src/Loop.js b/src/Loop.js
index 5dd7ba374..efdc05147 100644
--- a/src/Loop.js
+++ b/src/Loop.js
@@ -2,13 +2,15 @@ require('enyo');
/**
* This module returns the Loop singleton
+* @wip
* @module enyo/Loop
*/
var
kind = require('./kind');
var
- CoreObject = require('./CoreObject');
+ CoreObject = require('./CoreObject'),
+ animation = require('./animation');
module.exports = kind.singleton({
/** @lends module:enyo/Loop */
@@ -43,7 +45,7 @@ module.exports = kind.singleton({
* @private
*/
trigger: function () {
- global.requestAnimationFrame(this.lcb || this.initLoopCallback());
+ animation.requestAnimationFrame(this.lcb || this.initLoopCallback());
},
/**
* @private
diff --git a/src/Media.js b/src/Media.js
index 745a63b08..9bf329fc5 100644
--- a/src/Media.js
+++ b/src/Media.js
@@ -25,7 +25,7 @@ var
* propagated the {@glossary event}.
* @property {Object} event - An [object]{@glossary Object} containing event information.
* @public
-*/
+*/
/**
* Fires when element can resume playback of the [media]{@link module:enyo/Media~Media} data, but may
@@ -45,7 +45,7 @@ var
*
* @event module:enyo/Media~Media#onCanPlayThrough
* @type {Object}
-* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
+* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
* propagated the {@glossary event}.
* @property {Object} event - An [object]{@glossary Object} containing event information.
* @public
@@ -357,17 +357,17 @@ module.exports = kind(
* @private
*/
kind: Control,
-
+
/**
* @private
*/
- published:
+ published:
/** @lends module:enyo/Media~Media.prototype */ {
-
+
/**
* URL of the [media]{@link module:enyo/Media~Media} file to play; may be relative to the
* application HTML file.
- *
+ *
* @type {String}
* @default ''
* @public
@@ -376,7 +376,7 @@ module.exports = kind(
/**
* If `true`, [media]{@link module:enyo/Media~Media} will automatically start playback when loaded.
- *
+ *
* @type {Boolean}
* @default false
* @public
@@ -385,7 +385,7 @@ module.exports = kind(
/**
* The desired speed at which the [media]{@link module:enyo/Media~Media} resource is to play.
- *
+ *
* @type {Number}
* @default 1.0
* @public
@@ -394,7 +394,7 @@ module.exports = kind(
/**
* The amount of time, in seconds, to jump forward or backward.
- *
+ *
* @type {Number}
* @default 30
* @public
@@ -403,7 +403,7 @@ module.exports = kind(
/**
* The effective playback rate.
- *
+ *
* @type {Number}
* @default 1.0
* @public
@@ -418,7 +418,7 @@ module.exports = kind(
* slowRewind: ['-1/2', '-1']
* }
* ```
- *
+ *
* @type {Object}
* @default {
* fastForward: ['2', '4', '8', '16'],
@@ -438,7 +438,7 @@ module.exports = kind(
/**
* Indicates how data should be preloaded, reflecting the `preload` HTML attribute.
* Will be one of `'none'` (the default), `'metadata'`, or `'auto'`.
- *
+ *
* @type {String}
* @default 'none'
* @public
@@ -447,7 +447,7 @@ module.exports = kind(
/**
* If `true`, [media]{@link module:enyo/Media~Media} playback restarts from beginning when finished.
- *
+ *
* @type {Boolean}
* @default false
* @public
@@ -456,7 +456,7 @@ module.exports = kind(
/**
* If `true`, [media]{@link module:enyo/Media~Media} playback is muted.
- *
+ *
* @type {Boolean}
* @default false
* @public
@@ -465,7 +465,7 @@ module.exports = kind(
/**
* If `true`, default [media]{@link module:enyo/Media~Media} controls are shown.
- *
+ *
* @type {Boolean}
* @default false
* @public
@@ -474,7 +474,7 @@ module.exports = kind(
/**
* Current playback volume, as a number in the range from 0.0 to 1.0.
- *
+ *
* @type {Number}
* @default 1.0
* @public
@@ -515,7 +515,7 @@ module.exports = kind(
onJumpBackward: '',
onStart: ''
},
-
+
/**
* @private
*/
@@ -732,7 +732,7 @@ module.exports = kind(
_canPlayThrough: function () {
this.doCanPlayThrough();
},
-
+
/**
* Called when the [duration]{@link module:enyo/Media~Media#duration} attribute has been changed.
*
@@ -766,7 +766,7 @@ module.exports = kind(
/**
* Called when an error occurs while fetching media data.
- *
+ *
* @private
*/
_error: function () {
@@ -784,7 +784,7 @@ module.exports = kind(
},
/**
* Called when the media duration and dimensions of the media resource/text tracks are ready.
- *
+ *
* @private
*/
_loadedMetaData: function () {
@@ -856,7 +856,6 @@ module.exports = kind(
this.doStart();
}
return {
- srcElement: node,
duration: node.duration,
currentTime: node.currentTime,
playbackRate: this.getPlaybackRate()
@@ -876,7 +875,7 @@ module.exports = kind(
return (pbArray.length > 1) ? parseInt(pbArray[0], 10) / parseInt(pbArray[1], 10) : parseInt(rate, 10);
},
/**
- * Called when either [defaultPlaybackRate]{@link module:enyo/Media~Media#defaultPlaybackRate} or
+ * Called when either [defaultPlaybackRate]{@link module:enyo/Media~Media#defaultPlaybackRate} or
* [playbackRate]{@link module:enyo/Media~Media#playbackRate} has been updated.
*
* @fires module:enyo/Media~Media#onSlowforward
@@ -945,7 +944,7 @@ module.exports = kind(
/**
* Called when the media controller position has changed.
- *
+ *
* @private
*/
_timeUpdate: function (sender, e) {
@@ -1022,7 +1021,7 @@ module.exports = kind(
* Retrieves the ranges of the [media]{@link module:enyo/Media~Media} [source]{@link module:enyo/Media~Media#src}
* that have been buffered.
*
- * @returns {TimeRanges} The ranges of the [media]{@link module:enyo/Media~Media}
+ * @returns {TimeRanges} The ranges of the [media]{@link module:enyo/Media~Media}
* [source]{@link module:enyo/Media~Media#src} that have been buffered.
* @public
*/
@@ -1059,7 +1058,7 @@ module.exports = kind(
return 0;
},
- /**
+ /**
* Determines whether the [media]{@link module:enyo/Media~Media} element is paused.
*
* @returns {Boolean} `true` if the [media]{@link module:enyo/Media~Media} is paused;
@@ -1072,11 +1071,11 @@ module.exports = kind(
}
},
- /**
- * Retrieves the ranges of the [media]{@link module:enyo/Media~Media} [source]{@link module:enyo/Media~Media#src}
+ /**
+ * Retrieves the ranges of the [media]{@link module:enyo/Media~Media} [source]{@link module:enyo/Media~Media#src}
* that have been played, if any.
*
- * @returns {TimeRanges} The ranges of the [media]{@link module:enyo/Media~Media}
+ * @returns {TimeRanges} The ranges of the [media]{@link module:enyo/Media~Media}
* [source]{@link module:enyo/Media~Media#src} that have been played.
* @public
*/
@@ -1086,7 +1085,7 @@ module.exports = kind(
}
},
- /**
+ /**
* Determines the [readiness]{@glossary readyState} of the [media]{@link module:enyo/Media~Media}.
*
* @returns {ReadyState} The [readiness]{@glossary readyState} state.
@@ -1098,7 +1097,7 @@ module.exports = kind(
}
},
- /**
+ /**
* Retrieves the ranges of the [media]{@link module:enyo/Media~Media} [source]{@link module:enyo/Media~Media#src}
* that the user may seek to, if any.
*
@@ -1112,7 +1111,7 @@ module.exports = kind(
}
},
- /**
+ /**
* Sets current player position in the [media]{@link module:enyo/Media~Media} element.
*
* @param {Number} time - The player position, in seconds.
@@ -1124,7 +1123,7 @@ module.exports = kind(
}
},
- /**
+ /**
* Implements custom rewind functionality (until browsers support negative playback rate).
*
* @public
@@ -1136,7 +1135,7 @@ module.exports = kind(
/**
* Calculates the time that has elapsed since.
- *
+ *
* @private
*/
_rewind: function () {
@@ -1149,7 +1148,7 @@ module.exports = kind(
this.startRewindJob();
},
- /**
+ /**
* Starts rewind job.
*
* @public
@@ -1159,7 +1158,7 @@ module.exports = kind(
Job(this.id + 'rewind', this.bindSafely('_rewind'), 100);
},
- /**
+ /**
* Stops rewind job.
*
* @public
@@ -1168,7 +1167,7 @@ module.exports = kind(
Job.stop(this.id + 'rewind');
},
- /**
+ /**
* Determines whether the [media]{@link module:enyo/Media~Media} is currently seeking to a new position.
*
* @returns {Boolean} `true` if currently seeking; otherwise, `false`.
@@ -1180,7 +1179,7 @@ module.exports = kind(
}
},
- /**
+ /**
* Determines whether the [media]{@link module:enyo/Media~Media} is currently in a paused state.
*
* @returns {Boolean} `true` if paused; otherwise, `false`.
@@ -1190,7 +1189,7 @@ module.exports = kind(
return this.hasNode() ? this.hasNode().paused : true;
},
- /**
+ /**
* Fast forwards the [media]{@link module:enyo/Media~Media}, taking into account the current
* playback state.
*
@@ -1248,7 +1247,7 @@ module.exports = kind(
},
- /**
+ /**
* Rewinds the [media]{@link module:enyo/Media~Media}, taking into account the current
* playback state.
*
@@ -1322,7 +1321,7 @@ module.exports = kind(
}
},
- /**
+ /**
* Jumps backward by an amount specified by the [jumpSec]{@link module:enyo/Media~Media#jumpSec}
* property.
*
@@ -1343,7 +1342,7 @@ module.exports = kind(
this.doJumpBackward(utils.mixin(this.createEventData(), {jumpSize: this.jumpSec}));
},
- /**
+ /**
* Jumps forward by an amount specified by the [jumpSec]{@link module:enyo/Media~Media#jumpSec}
* property.
*
@@ -1364,7 +1363,7 @@ module.exports = kind(
this.doJumpForward(utils.mixin(this.createEventData(), {jumpSize: this.jumpSec}));
},
- /**
+ /**
* Jumps to the beginning of the [media]{@link module:enyo/Media~Media} content.
*
* @public
@@ -1382,7 +1381,7 @@ module.exports = kind(
this._prevCommand = 'jumpToStart';
},
- /**
+ /**
* Jumps to the end of the [media]{@link module:enyo/Media~Media} content.
*
* @public
diff --git a/src/ModelController.js b/src/ModelController.js
index 06a375eb5..fb7bce9b9 100644
--- a/src/ModelController.js
+++ b/src/ModelController.js
@@ -34,18 +34,18 @@ var BaseModelController = kind({
* [model]{@link module:enyo/ModelController~ModelController#model} reserved property, the actual model
* may be changed without the bindings' needing to know. It will also propagate
* events [emitted]{@link module:enyo/EventEmitter~EventEmitter#emit} by the underlying model.
-*
+*
* It is important to note that `'model'` is a reserved property name. Also
* note that bindings should **never** bind through the controller to the model
* directly.
-*
+*
* **Rules of property resolution**
*
* If the controller can call [hasOwnProperty()]{@glossary Object.hasOwnProperty}
* and it returns `true`, it will look locally; if the property is resolved to
* be a computed property, the requested property will be proxied from the given
* model, when available.
-*
+*
* @class ModelController
* @extends module:enyo/Component~Component
* @mixes module:enyo/ComputedSupport~ComputedSupport
@@ -55,18 +55,18 @@ var BaseModelController = kind({
*/
module.exports = kind(
/** @lends module:enyo/ModelController~ModelController.prototype */ {
-
+
name: 'enyo.ModelController',
-
+
/**
* @private
*/
kind: BaseModelController,
-
+
/**
- * The {@link module:enyo/Model~Model} to proxy. If this is set to an instance of `enyo.Model`,
- * the [controller]{@link module:enyo/ModelController~ModelController} will propagate `enyo.Model`
- * [events]{@glossary event} and [notifications]{@link module:enyo/ObserverSupport~ObserverSupport.notify}.
+ * The {@link module:enyo/Model~Model} to proxy. If this is set to an instance of `enyo/Model`,
+ * the [controller]{@link module:enyo/ModelController~ModelController} will propagate `enyo/Model`
+ * [events]{@glossary event} and [notifications]{@link module:enyo/ObserverSupport~ObserverSupport#notify}.
* **No bindings should ever bind directly to attributes of this property.**
*
* Also note that this is a reserved property name and will collide with any
@@ -78,52 +78,51 @@ module.exports = kind(
* @public
*/
model: null,
-
+
/**
* @private
*/
proxyObjectKey: 'model',
-
+
/**
* @method
* @private
*/
get: kind.inherit(function (sup) {
return function (path) {
-
+
if (this.hasOwnProperty(path) || this.isComputed(path)) {
return this._getComputed(path);
}
-
+
return sup.apply(this, arguments);
};
}),
-
+
/**
* @method
* @private
*/
set: kind.inherit(function (sup) {
return function (path) {
-
+
if (typeof path == 'string') {
if (this.hasOwnProperty(path)) {
return this.isComputed(path) ? this : utils.setPath.apply(this, arguments);
}
}
-
+
return sup.apply(this, arguments);
};
}),
-
+
/**
* @method
* @private
*/
_getComputed: ComputedSupport.get.fn(CoreObject.prototype.get),
-
+
/**
- * @type enyo.ObserverSupport~Observer
* @private
*/
modelChanged: function (was, is, path) {
@@ -131,7 +130,7 @@ module.exports = kind(
if (was) was.off('*', this._modelEvent, this);
// register for events on new model if any
if (is) is.on('*', this._modelEvent, this);
-
+
// either way we need to update any observers that might be related
// to the model
var props = this.modelObservedProperties();
@@ -140,10 +139,10 @@ module.exports = kind(
this.notify(key, was && was.get(key), is && is.get(key));
}
}
-
+
this.emit('model', {was: was, is: is});
},
-
+
/**
* @method
* @private
@@ -153,7 +152,7 @@ module.exports = kind(
// will be this controller but all listeners should expect to use the third parameter as
// is the convention for model listeners
this.emit(e, props, model);
-
+
switch (e) {
case 'change':
if (props) for (var key in props) this.notify(key, model.previous[key], props[key]);
@@ -163,7 +162,7 @@ module.exports = kind(
break;
}
},
-
+
/**
* @method
* @private
@@ -171,7 +170,7 @@ module.exports = kind(
modelObservedProperties: function () {
return this._observedProps || (this._observedProps = {});
},
-
+
/**
* @method
* @private
@@ -180,24 +179,24 @@ module.exports = kind(
return function (path) {
var part = path
, parts;
-
+
if (path.indexOf('.') > -1) {
parts = path.split('.');
part = parts.shift();
}
-
+
if (!this.hasOwnProperty(part) && !this.isComputed(part)) this.modelObservedProperties()[path] = null;
return sup.apply(this, arguments);
};
}),
-
+
/**
* @private
*/
addObserver: function () {
return this.observe.apply(this, arguments);
},
-
+
/**
* @private
*/
@@ -205,13 +204,13 @@ module.exports = kind(
return function (props) {
// ensure we have our own model property
this.model = null;
-
+
// adhere to normal approach to constructor properties hash
props && utils.mixin(this, props);
sup.apply(this, arguments);
};
}),
-
+
/**
* @method
* @private
@@ -222,5 +221,5 @@ module.exports = kind(
this.model && this.model.off('*', this._modelEvent, this);
};
})
-
+
});
diff --git a/src/NewAnimator.js b/src/NewAnimator.js
index 139cb7e51..ab94de1b3 100644
--- a/src/NewAnimator.js
+++ b/src/NewAnimator.js
@@ -1,3 +1,10 @@
+/**
+* Contains the declaration for the {@link module:enyo/NewAnimator~NewAnimator} kind.
+* @wip
+* @private
+* @module enyo/NewAnimator
+*/
+
require('enyo');
var
@@ -8,7 +15,16 @@ var
CoreObject = require('./CoreObject'),
Loop = require('./Loop');
-module.exports = kind.singleton({
+/**
+* {@link module:enyo/NewAnimator~NewAnimator} is a work-in-progress
+*
+* @class NewAnimator
+* @extends module:enyo/CoreObject~Object
+* @wip
+* @private
+*/
+module.exports = kind.singleton(
+ /** @lends module:enyo/NewAnimator~NewAnimator.prototype */ {
name: 'enyo.NewAnimator',
kind: CoreObject,
animate: function(fn, duration) {
diff --git a/src/NewDataList.js b/src/NewDataList.js
index eb44b0767..435934758 100644
--- a/src/NewDataList.js
+++ b/src/NewDataList.js
@@ -1,3 +1,11 @@
+/**
+* Contains the declaration for the {@link module:enyo/NewDataList~NewDataList} kind.
+*
+* @wip
+* @public
+* @module enyo/NewDataList
+*/
+
require('enyo');
var
@@ -8,19 +16,135 @@ var
Scrollable = require('./Scrollable'),
VirtualDataRepeater = require('./VirtualDataRepeater');
-module.exports = kind({
+/**
+* {@link module:enyo/NewDataList~NewDataList} is new virtual list implementation.
+*
+* It is intended to replace the older {@link module:enyo/DataList~DataList},
+* {@link module:enyo/DataGridList~DataGridList} and probably
+* {@link module:layout/List~List}, but as of the Enyo 2.7 release is a work in
+* progress and currently lacks many of the features of those older implementations.
+*
+* The most significant difference between `NewDataList` and `DataList` / `DataGridList`
+* is that `NewDataList` "virtualizes" items one at a time, not a page at a time. This
+* approach performs somewhat better in general and most notably disributes the cost of
+* virtualization over time, which produces smoother frame rates.
+*
+* `NewDataList` supports both linear and grid layouts, in either horizontal or
+* vertical direction.
+*
+* Notes:
+* * List items must be styled with `position: absolute` to be laid out properly,
+* but `NewDataList` does not currently provide any default style rules for items,
+* so you need to specify `position: absolute` in your items' classes or style attributes.
+* * `NewDataList` currently supports only explicitly sized items; neither variable-size
+* items nor "naturally" sized items are currently supported.
+*
+* @class NewDataList
+* @extends module:enyo/VirtualDataRepeater~VirtualDataRepeater
+* @wip
+* @ui
+* @public
+*/
+module.exports = kind(
+ /** @lends module:enyo/NewDataList~NewDataList.prototype */ {
name: 'enyo.NewDataList',
kind: VirtualDataRepeater,
+ /**
+ * The direction of the layout, which may be either `'vertical'`
+ * or `'horizontal'`.
+ *
+ * @type {String}
+ * @default 'vertical'
+ * @public
+ */
direction: 'vertical',
+ /**
+ * The height of each list item, in pixels.
+ *
+ * Required for grid layouts and linear vertical layouts; may be
+ * omitted for linear horizontal layouts.
+ *
+ * @type {Number}
+ * @default 100
+ * @public
+ */
itemHeight: 100,
+ /**
+ * The width of each list item, in pixels.
+ *
+ * Required for grid layouts and linear horizontal layouts; may be
+ * omitted for linear vertical layouts.
+ *
+ * @type {Number}
+ * @default 100
+ * @public
+ */
itemWidth: 100,
+ /**
+ * The space between list items, in pixels.
+ *
+ * @type {Number}
+ * @default 0
+ * @public
+ */
spacing: 0,
+ /**
+ * The number of rows (only applies to horizontally scrolling grid layouts).
+ *
+ * To specify a horizontally scrolling grid layout, set `rows` to `2` or more
+ * and `direction` to `horizontal`.
+ *
+ * @type {Number}
+ * @default 'auto'
+ * @public
+ */
rows: 'auto',
+ /**
+ * The number of columns (only applies to vertically scrolling grid layouts).
+ *
+ * To specify a vertically scrolling grid layout, set `columns` to `2` or more
+ * and `direction` to `vertical`.
+ *
+ * @type {Number}
+ * @default 'auto'
+ * @public
+ */
columns: 'auto',
+ /**
+ * This number determines how many "extra" items the list will generate, beyond
+ * the number required to fill the list's viewport. Higher numbers result in more
+ * extra items being generated.
+ *
+ * You should generally not need to adjust this value.
+ *
+ * @type {Number}
+ * @default 3
+ * @public
+ */
overhang: 3,
- // Experimental
+ /**
+ * This feature is experimental, and only partly functional.
+ *
+ * When `scrollToBoundaries` is set to `true`, the list will come to rest on an
+ * item boundary, such that the first visible item is fully within the list's
+ * viewport, not partially outside.
+ *
+ * Important limitation: this feature currently only works when scrolling in
+ * response to wheel events or when scrolling to explicitly provided coordinates;
+ * it does not work when scrolling in response to touch or mouse events.
+ *
+ * @type {Boolean}
+ * @default false
+ * @public
+ */
scrollToBoundaries: false,
+ /**
+ * @private
+ */
mixins: [Scrollable],
+ /**
+ * @private
+ */
observers: [
{method: 'reset', path: [
'direction', 'columns', 'rows',
@@ -151,6 +275,7 @@ module.exports = kind({
// as long as calculateMetrics() is called only by reset().
this.numItems = num;
},
+
/**
* @private
*/
@@ -194,6 +319,34 @@ module.exports = kind({
}
this.positionChildren();
},
+
+ /**
+ * @private
+ */
+ refreshThresholds: function () {
+ var tt = this.threshold;
+
+ if (tt) {
+ var
+ v = (this.direction === 'vertical'),
+ val = v ? this.scrollTop : this.scrollLeft,
+ delta = this.delta,
+ cb = this.cachedBounds ? this.cachedBounds : this._getScrollBounds(),
+ maxVal = v ? cb.maxTop : cb.maxLeft,
+ d2x = this.dim2extent,
+ head = Math.floor(this.overhang / 2),
+ fvg = Math.floor(val / delta),
+ fg = Math.max(0, fvg - head),
+ f = d2x * fg,
+ nPos = fvg * delta;
+
+ tt.max = Math.min(maxVal, nPos + delta),
+ tt.min = Math.max(0, nPos);
+
+ this.first = f;
+ }
+ },
+
/**
* @private
*/
@@ -326,6 +479,7 @@ module.exports = kind({
modelsAdded: kind.inherit(function (sup) {
return function() {
this.calcBoundaries();
+ this.refreshThresholds();
sup.apply(this, arguments);
};
}),
@@ -336,6 +490,7 @@ module.exports = kind({
modelsRemoved: kind.inherit(function (sup) {
return function() {
this.calcBoundaries();
+ this.refreshThresholds();
sup.apply(this, arguments);
};
}),
diff --git a/src/NewDrawer/NewDrawer.js b/src/NewDrawer/NewDrawer.js
index 0b9a1d22c..dbf2bd335 100644
--- a/src/NewDrawer/NewDrawer.js
+++ b/src/NewDrawer/NewDrawer.js
@@ -1,3 +1,10 @@
+/**
+* Contains the declaration for the {@link module:enyo/NewDrawer~NewDrawer} kind.
+* @wip
+* @private
+* @module enyo/NewDrawer
+*/
+
require('enyo');
var
@@ -8,7 +15,22 @@ var
Control = require('../Control'),
NewAnimator = require('../NewAnimator');
-module.exports = kind({
+/**
+* {@link module:enyo/NewDrawer~NewDrawer} is an experimental
+* {@link module:enyo/Control~Control}.
+*
+* It is not a 1:1 replacement for {@link module:enyo/Drawer~Drawer}
+* and will likely never be promoted out of its experimental state.
+* Use at your own risk.
+*
+* @class NewDrawer
+* @extends module:enyo/Control~Control
+* @wip
+* @private
+* @ui
+*/
+module.exports = kind(
+ /** @lends module:enyo/NewDrawer~NewDrawer.prototype */ {
name: 'enyo.NewDrawer',
kind: Control,
classes: 'enyo-new-drawer',
@@ -61,4 +83,4 @@ module.exports = kind({
// this.discoverControlParent();
};
})
-});
+});
\ No newline at end of file
diff --git a/src/NewThumb/NewThumb.js b/src/NewThumb/NewThumb.js
index 7e1f0c74b..228cfdbd6 100644
--- a/src/NewThumb/NewThumb.js
+++ b/src/NewThumb/NewThumb.js
@@ -2,6 +2,8 @@ require('enyo');
/**
* Contains the declaration for the {@link module:enyo/NewThumb~NewThumb} kind.
+* @wip
+* @public
* @module enyo/NewThumb
*/
@@ -14,15 +16,37 @@ var
Control = require('../Control');
/**
-* {@link module:enyo/NewThumb~NewThumb} is a helper [kind]{@glossary kind} used
-* by {@link module:enyo/TouchScrollStrategy~TouchScrollStrategy} and
-* {@link module:enyo/TranslateScrollStrategy~TranslateScrollStrategy} to display
-* a small visual scroll indicator.
+* {@link module:enyo/NewThumb~NewThumb} is a simple scroll thumb designed to be
+* used with any scrolling {@link module:enyo/Control~Control} whose scrolling
+* behavior is provided by the {@link module:enyo/Scrollable~Scrollable} mixin.
+*
+* Like all {@link module:enyo/Scrollable~Scrollable}-compatible scroll controls,
+* {@link module:enyo/NewThumb~NewThumb} listens to events emitted by the scrolling
+* {@link module:enyo/Control~Control} and updates its state (position, visibility,
+* etc.) accordingly.
*
-* `enyo/NewThumb` is not typically created in application code.
+* To use {@link module:enyo/NewThumb~NewThumb}, simply include it in the
+* {@link module:enyo/Scrollable~Scrollable#scrollControls} block of the scrolling
+* control:
+*
+* ```javascript
+* var
+* kind = require('enyo/kind'),
+* NewThumb = require('enyo/NewThumb'),
+* NewDataList = require('enyo/NewDataList');
+*
+* var MyList = kind({
+* kind: NewDataList,
+* scrollControls: [
+* {kind: NewThumb}
+* ]
+* });
+* ```
*
* @class NewThumb
-* @protected
+* @extends module:enyo/Control~Control
+* @wip
+* @public
*/
module.exports = kind(
/** @lends module:enyo/NewThumb~NewThumb.prototype */ {
@@ -31,12 +55,12 @@ module.exports = kind(
* @private
*/
name: 'enyo.NewScrollThumb',
-
+
kind: Control,
/**
* The orientation of the scroll indicator bar; 'v' for vertical or 'h' for horizontal.
- *
+ *
* @type {String}
* @default 'v'
* @public
@@ -50,19 +74,19 @@ module.exports = kind(
/**
* Minimum size of the indicator.
*
- * @private
+ * @public
*/
minSize: ri.scale(4),
/**
* Size of the indicator's corners.
*
- * @private
+ * @public
*/
cornerSize: ri.scale(6),
/**
- * @private
+ * @public
*/
enabled: false,
@@ -112,6 +136,9 @@ module.exports = kind(
};
}),
+ /**
+ * @private
+ */
scrollerChanged: function(was) {
if (was) {
was.off('scrollabilityChanged', this._updateEnablement);
@@ -123,6 +150,9 @@ module.exports = kind(
}
},
+ /**
+ * @private
+ */
updateEnablement: function() {
var s = this.scroller,
was = this.enabled,
@@ -134,7 +164,7 @@ module.exports = kind(
s.on('stateChanged', this._updateVisibility);
}
}
-
+
if (was && !is) {
s.off('metricsChanged', this._update);
s.off('stateChanged', this._updateVisibility);
@@ -142,6 +172,9 @@ module.exports = kind(
}
},
+ /**
+ * @private
+ */
_updateVisibility: function() {
var s = this.scroller;
@@ -154,6 +187,9 @@ module.exports = kind(
}
},
+ /**
+ * @private
+ */
rendered: kind.inherit(function (sup) {
return function () {
sup.apply(this, arguments);
@@ -161,6 +197,9 @@ module.exports = kind(
};
}),
+ /**
+ * @private
+ */
calculateMetrics: function () {
this.extent = this.parent.getBounds()[this.dimension];
this.minSizeRatio = this.minSize / this.extent;
@@ -168,12 +207,7 @@ module.exports = kind(
},
/**
- * Updates the scroll indicator bar based on the scroll bounds of the strategy, the available
- * scroll area, and whether there is overscrolling. If the scroll indicator bar is not
- * needed, it will be not be displayed.
- *
- * @param {module:enyo/ScrollStrategy~ScrollStrategy} strategy - The scroll strategy to update from.
- * @public
+ * @private
*/
update: function () {
var sc = this.scroller,
@@ -213,9 +247,13 @@ module.exports = kind(
},
/**
- * Override `show()` to give fade effect.
+ * Shows the thumb.
+ *
+ * App code should generally not need to manage thumb visibility
+ * unless the {@link module:enyo/NewThumb~NewThumb#autoHide} property
+ * has been set to `false`.
*
- * @private
+ * @public
*/
show: function (delay) {
if (this.enabled) {
@@ -228,27 +266,67 @@ module.exports = kind(
},
/**
- * Hides the control.
+ * Hides the thumb.
*
- * @private
+ * App code should generally not need to manage thumb visibility
+ * unless the {@link module:enyo/NewThumb~NewThumb#autoHide} property
+ * has been set to `false`.
+ *
+ * @public
*/
hide: function () {
this.stopJob('hide');
this.addClass('hidden');
},
+ /**
+ * Overriding `handleResize()` to re-calculate ratio and size.
+ *
+ * @private
+ */
+ handleResize: function () {
+ Control.prototype.handleResize.apply(this, arguments);
+ if (this.getAbsoluteShowing()) {
+ this.calculateMetrics();
+ }
+ },
+
+ /**
+ * Overriding `showingChangedHandler()` to recalculate metrics on show.
+ *
+ * @private
+ */
+ showingChangedHandler: function (sender, e) {
+ Control.prototype.showingChangedHandler.apply(this, arguments);
+ if (this.getAbsoluteShowing()) {
+ this.calculateMetrics();
+ }
+ },
+
+ /**
+ * @private
+ */
v2dMatrix: function (p, s) {
return '1, 0, 0, ' + (s / this.naturalSize) + ', 0,' + p;
},
+ /**
+ * @private
+ */
v3dMatrix: function(p, s) {
return '1, 0, 0, 0, 0,' + (s / this.naturalSize) + ', 0, 0, 0, 0, 1, 0, 0, ' + p + ', 1, 1';
},
+ /**
+ * @private
+ */
h2dMatrix: function(p, s) {
return (s / this.naturalSize) + ', 0, 0, 1, ' + p + ', 0';
},
+ /**
+ * @private
+ */
h3dMatrix: function(p, s) {
return (s / this.naturalSize) + ', 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ' + p + ', 0, 1, 1';
}
diff --git a/src/ObserverSupport.js b/src/ObserverSupport.js
index 1df5d353c..decff104f 100644
--- a/src/ObserverSupport.js
+++ b/src/ObserverSupport.js
@@ -373,7 +373,7 @@ var ObserverSupport = {
if (path) {
loc[path] = null;
} else {
- observerTable[euid] = null;
+ delete observerTable[euid];
}
}
@@ -509,7 +509,8 @@ var ObserverSupport = {
chain;
sup.apply(this, arguments);
-
+
+ this.removeAllObservers();
if (chains) {
for (path in chains) {
chain = chains[path];
diff --git a/src/Option.js b/src/Option.js
index 02ebdcd25..ab4b64c30 100644
--- a/src/Option.js
+++ b/src/Option.js
@@ -36,12 +36,13 @@ module.exports = kind(
* @private
*/
published: {
+ /** @lends module:enyo/Option~Option.prototype */
+
/**
* Value of the [option]{@link module:enyo/Option~Option}.
*
* @type {String}
* @default ''
- * @memberof enyo.Option.prototype
* @public
*/
value: '',
@@ -51,7 +52,6 @@ module.exports = kind(
*
* @type {Boolean}
* @default false
- * @memberof enyo.Option.prototype
* @public
*/
selected: false
diff --git a/src/OptionGroup.js b/src/OptionGroup.js
index c4bad93af..88fb00bff 100644
--- a/src/OptionGroup.js
+++ b/src/OptionGroup.js
@@ -40,12 +40,13 @@ module.exports = kind(
* @private
*/
published: {
+ /** @lends module:enyo/OptionGroup~OptionGroup.prototype */
+
/**
* The name for this [option group]{@link module:enyo/OptionGroup~OptionGroup}.
*
* @type {String}
* @default ''
- * @memberof enyo.OptionGroup.prototype
* @public
*/
label: ''
diff --git a/src/Popup/Popup.js b/src/Popup/Popup.js
index 89c7a7e72..f657a6086 100644
--- a/src/Popup/Popup.js
+++ b/src/Popup/Popup.js
@@ -326,6 +326,7 @@ var Popup = module.exports = kind(
destroy: kind.inherit(function (sup) {
return function() {
this.release();
+ if (this.showing) this.showHideScrim(false);
sup.apply(this, arguments);
};
}),
diff --git a/src/PriorityQueue.js b/src/PriorityQueue.js
index 752ba4818..6efa5e9a1 100644
--- a/src/PriorityQueue.js
+++ b/src/PriorityQueue.js
@@ -2,6 +2,7 @@ require('enyo');
/**
* Exports Priority options used by {@link module:enyo/BackgroundTaskManager}.
+* @wip
* @module enyo/PriorityQueue
*/
@@ -48,6 +49,7 @@ var Priorities = {
/**
* @class PriorityQueue
+* @wip
* @public
*/
module.exports = exports = kind(
diff --git a/src/RelationalModel/RelationalCollection.js b/src/RelationalModel/Collection.js
similarity index 64%
rename from src/RelationalModel/RelationalCollection.js
rename to src/RelationalModel/Collection.js
index 4989f64b4..3b7e87e3d 100644
--- a/src/RelationalModel/RelationalCollection.js
+++ b/src/RelationalModel/Collection.js
@@ -1,6 +1,7 @@
/**
-* Contains the declaration for the {@link module:enyo/RelationalModel~RelationalCollection} kind.
-* @module enyo/RelationalModel
+* Contains the declaration for the {@link module:enyo/RelationalModel~Collection} kind.
+* @module enyo/RelationalModel/Collection
+* @private
*/
var
@@ -8,23 +9,24 @@ var
Collection = require('../Collection');
var
- RelationalModel = require('./RelationalModel');
+ Model = require('./Model');
/**
* Private class for a collection with a default model kind of
* {@link module:enyo/RelationalModel~RelationalModel} as opposed to {@link module:enyo/Model~Model}.
*
-* @class RelationalCollection
+* @class Collection
+* @name module:enyo/RelationalModel~Collection
* @extends module:enyo/Collection~Collection
* @private
*/
module.exports = kind(
- /** @lends module:enyo/RelationalModel~RelationalCollection.prototype */ {
+ /** @lends module:enyo/RelationalModel~Collection.prototype */ {
/**
* @private
*/
- name: "RelationalCollection",
+ name: 'Collection',
/**
* @private
@@ -34,5 +36,5 @@ module.exports = kind(
/**
* @private
*/
- model: RelationalModel
+ model: Model
});
diff --git a/src/RelationalModel/RelationalModel.js b/src/RelationalModel/Model.js
similarity index 91%
rename from src/RelationalModel/RelationalModel.js
rename to src/RelationalModel/Model.js
index 90cd16d08..a8d24d5f5 100644
--- a/src/RelationalModel/RelationalModel.js
+++ b/src/RelationalModel/Model.js
@@ -1,7 +1,11 @@
/**
- * Contains the declaration for the {@link module:enyo/RelationalModel~RelationalModel} kind.
- * @module enyo/RelationalModel
- */
+* Contains the declaration for the {@link module:enyo/RelationalModel~RelationalModel} kind.
+*
+* NOTE: Do not require this module for use in applications. Require
+* {@link module:enyo/RelationalModel} instead.
+* @module enyo/RelationalModel/Model
+* @private
+*/
var
kind = require('../kind'),
@@ -10,7 +14,7 @@ var
var
Model = require('../Model'),
Store = require('../Store'),
- Relation = require('../Relation');
+ Relation = require('./Relation');
var
defaultRelationType;
@@ -22,6 +26,7 @@ var
* individual models to exist separately, but be treated as a single entity.
*
* @class RelationalModel
+* @name module:enyo/RelationalModel~RelationalModel
* @extends module:enyo/Model~Model
* @public
*/
@@ -34,12 +39,7 @@ var RelationalModel = module.exports = kind(
* @private
*/
kind: Model,
-
- /**
- * @private
- */
-
/**
* An [array]{@glossary Array} declaring relationships of this
* [model]{@link module:enyo/RelationalModel~RelationalModel} to other models.
@@ -83,14 +83,14 @@ var RelationalModel = module.exports = kind(
*
* @param {String} key - The key as defined in the
* [relations]{@link module:enyo/RelationalModel~RelationalModel#relations} property.
- * @returns {(Relation|undefined)} The correct relation instance, or
+ * @returns {(module:enyo/RelationalModel~Relation|undefined)} The correct relation instance, or
* `undefined` if not found.
* @public
*/
getRelation: function (key) {
- return this.relations.find(function (ln) {
+ return this.relations ? this.relations.find(function (ln) {
return ln instanceof Relation && ln.key == key;
- });
+ }) : undefined;
},
/**
@@ -98,7 +98,7 @@ var RelationalModel = module.exports = kind(
*
* @param {String} key - The key as defined in the
* [relations]{@link module:enyo/RelationalModel~RelationalModel#relations} property.
- * @returns {(Relation|undefined)} The correct relation instance, or
+ * @returns {(module:enyo/RelationalModel~Relation|undefined)} The correct relation instance, or
* `undefined` if not found.
* @public
*/
@@ -107,8 +107,8 @@ var RelationalModel = module.exports = kind(
},
/**
- * Overloaded version of [get]{@link module:enyo/Model~Model#get} to be able to use a _path_ through
- * relations.
+ * Overloaded version of [get]{@link module:enyo/Model~Model#get} to be able to use a _path_
+ * through relations.
*
* @method
* @private
@@ -312,6 +312,9 @@ var RelationalModel = module.exports = kind(
/**
* Defines a named relation type
*
+* @name module:enyo/RelationalModel~RelationalModel.defineRelationType
+* @static
+* @method
* @param {String} name Name of relation type
* @param {Relation} type Relation kind constructor
* @param {Boolean} isDefault `true` if this type should be the default for type-less relations
@@ -326,8 +329,9 @@ RelationalModel.defineRelationType = function (name, type, isDefault) {
/**
* Ensures that we concatenate (sanely) the relations for any subkinds.
*
-* @name enyo.RelationalModel.concat
+* @name module:enyo/RelationalModel~RelationalModel.concat
* @static
+* @method
* @private
*/
RelationalModel.concat = function (ctor, props) {
@@ -351,5 +355,3 @@ RelationalModel.concat = function (ctor, props) {
// apply our modified relations array to the prototype
proto.relations = rels;
};
-
-Relation.relationDefaults.model = RelationalModel;
diff --git a/src/Relation.js b/src/RelationalModel/Relation.js
similarity index 71%
rename from src/Relation.js
rename to src/RelationalModel/Relation.js
index 6cccc89c9..b94c8c2a7 100644
--- a/src/Relation.js
+++ b/src/RelationalModel/Relation.js
@@ -1,35 +1,38 @@
require('enyo');
/**
-* Contains the declaration for the {@link module:enyo/Relation~Relation} kind.
-* @module enyo/Relation
+* Contains the declaration for the {@link module:enyo/RelationalModel~Relation} kind.
+* @module enyo/RelationalModel/Relation
+* @private
*/
var
- kind = require('./kind'),
- utils = require('./utils');
+ kind = require('../kind'),
+ utils = require('../utils');
var
- Store = require('./Store');
+ Store = require('../Store');
/**
* The default options for [relations]{@link module:enyo/RelationalModel~RelationalModel#relations}.
* These may vary depending on the individual [kind]{@glossary kind} of relation.
*
* @typedef {Object} module:enyo/RelationalModel~RelationOptions
-* @property {String} type=toOne - The [kind]{@glossary kind} of relation being declared.
-* Can be the name of the relation type or a reference to the constructor.
-* @property {String} key=null - The [attribute]{@link module:enyo/Model~Model#attributes} name for the
-* relation being declared.
+* @property {module:enyo/RelationalModel~Relation} type=module:enyo/RelationalModel~toOne - The
+* [kind]{@glossary kind} of relation being declared.
+* @property {String} key=null - The [attribute]{@link module:enyo/Model~Model#attributes} name for
+* the relation being declared.
* @property {Boolean} create=false - Whether or not the relation should automatically create
* the instance of the related kind.
* @property {Boolean} parse=false - Whether or not the relation should call the
* [parse()]{@link module:enyo/Model~Model#parse} method on incoming data before
-* [setting]{@link module:enyo/Model~Model#set} it on the [model]{@link module:enyo/RelationalModel~RelationalModel}.
-* @property {String} model=enyo.RelationalModel - The kind of the
+* [setting]{@link module:enyo/Model~Model#set} it on the
+* [model]{@link module:enyo/RelationalModel~RelationalModel}.
+* @property {String} model=enyo/RelationalModel~RelationModel - The kind of the
* reverse of the relation. This will vary depending on the type of relation being declared.
* @property {Boolean} fetch=false - Whether or not to automatically call
-* [fetch()]{@link module:enyo/Model~Model#fetch} (or {@link module:enyo/Collection~Collection#fetch}) after initialization.
+* [fetch()]{@link module:enyo/Model~Model#fetch} (or
+* {@link module:enyo/Collection~Collection#fetch}) after initialization.
* @property {String} inverseKey=null - The key of the reverse relation.
* @property {String} inverseType=null - The type of the reverse relation.
* @property {Boolean} isOwner=false - Whether or not this end of the relation owns the
@@ -41,11 +44,11 @@ var
* be included.
*/
var relationDefaults = {
- type: 'toOne',
+ type: null, // set ex post facto by the module
key: null,
create: false,
parse: false,
- model: null,
+ model: null, // set ex post facto by the module
fetch: false,
inverseKey: null,
inverseType: null,
@@ -55,83 +58,92 @@ var relationDefaults = {
/**
* @class Relation
-* @protected
+* @name module:enyo/RelationalModel~Relation
+* @private
*/
var Relation = module.exports = kind(
- /** @lends module:enyo/Relation~Relation.prototype */ {
-
+ /** @lends module:enyo/RelationalModel~Relation.prototype */ {
+
/**
* @private
*/
- name: "Relation",
-
+ name: 'enyo.Relation',
+
/**
* @private
*/
kind: null,
-
+
/**
* @private
*/
options: {},
-
+
/**
* @private
*/
constructor: function (instance, props) {
-
+
// apply any of the properties to ourself for reference
utils.mixin(this, [relationDefaults, this.options, props]);
-
+
// store a reference to the model we're relating
this.instance = instance;
-
- // ensure we have a constructor for our related model kind
- this.model = kind.constructorForKind(this.model);
-
+
this.includeInJSON = props.includeInJSON == null && !this.isOwner
? (this.model.prototype.primaryKey || 'id')
: this.includeInJSON;
-
+
// let the subkinds do their thing
this.init();
},
-
+
+ /**
+ * @private
+ */
+ isRelated: function (related) {
+ return related === this.related;
+ },
+
/**
* @private
*/
getRelated: function () {
return this.related;
},
-
+
/**
+ * Sets the `related` model
+ *
+ * @param {module:enyo/Model~Model} related - The related model
+ * @param {Object} [opts] - Used by subkinds to configure the behavior of the method
* @private
*/
- setRelated: function (related) {
+ setRelated: function (related, opts) {
var inst = this.instance,
model = this.model,
was = this.related,
key = this.key,
changed,
prev;
-
-
+
+
if (related) Store.off(model, 'add', this._changed, this);
-
+
this.related = related;
-
+
if (!inst._changing) {
-
+
changed = inst.changed || (inst.changed = {}),
prev = inst.previous || (inst.previous = {});
-
+
changed[key] = related;
prev[key] = was;
if (was !== related) inst.emit('change', changed);
}
return this;
},
-
+
/**
* @private
*/
@@ -139,21 +151,17 @@ var Relation = module.exports = kind(
var isOwner = this.isOwner,
create = this.create,
related = this.related;
-
+
if ((isOwner || create) && related && related.destroy && !related.destroyed) {
related.destroy();
}
-
+
this.destroyed = true;
this.instance = null;
this.related = null;
}
});
-/**
-* @private
-* @static
-*/
Relation.concat = function (ctor, props) {
var proto = ctor.prototype;
if (props.options) {
diff --git a/src/RelationalModel/index.js b/src/RelationalModel/index.js
index cb79150ab..f3fee3c82 100644
--- a/src/RelationalModel/index.js
+++ b/src/RelationalModel/index.js
@@ -1,18 +1,23 @@
require('enyo');
/**
-* Contains the declaration for the {@link module:enyo/RelationalModel~RelationalModel} kind.
+* Contains the declaration for the {@link module:enyo/RelationalModel~RelationalModel} and
+* {@link module:enyo/RelationalModel~Collection} kinds.
* @module enyo/RelationalModel
*/
var
- RelationalModel = require('./RelationalModel'),
+ Model = require('./Model'),
+ Relation = require('./Relation'),
toOne = require('./toOne'),
toMany = require('./toMany'),
manyToMany = require('./manyToMany');
-RelationalModel.defineRelationType('toOne', toOne, true);
-RelationalModel.defineRelationType('toMany', toMany);
-RelationalModel.defineRelationType('manyToMany', manyToMany);
+Model.defineRelationType('toOne', toOne, true);
+Model.defineRelationType('toMany', toMany);
+Model.defineRelationType('manyToMany', manyToMany);
-module.exports = RelationalModel;
+Relation.relationDefaults.model = Model;
+Relation.relationDefaults.type = toOne;
+
+module.exports = Model;
\ No newline at end of file
diff --git a/src/RelationalModel/manyToMany.js b/src/RelationalModel/manyToMany.js
index 221f9f7fa..8003e6d5f 100644
--- a/src/RelationalModel/manyToMany.js
+++ b/src/RelationalModel/manyToMany.js
@@ -1,6 +1,7 @@
/**
-* Contains the declaration for the {@link module:moonstone/RelationalModel~manyToMany} kind.
-* @module enyo/RelationalModel
+* Contains the declaration for the {@link module:enyo/RelationalModel~manyToMany} kind.
+* @module enyo/RelationalModel/manyToMany
+* @private
*/
var
@@ -14,35 +15,37 @@ var
* models. This is an internally-used class.
*
* @class manyToMany
+* @name module:enyo/RelationalModel~manyToMany
* @extends module:enyo/RelationalModel~toMany
-* @protected
+* @private
*/
var manyToMany = module.exports = kind(
/** @lends module:enyo/RelationalModel~manyToMany.prototype */ {
-
+
/**
* @private
*/
kind: toMany,
-
+
/**
* @private
*/
name: 'enyo.manyToMany',
-
+
/**
* The default [options]{@link module:enyo/RelationalModel~RelationOptions} overloaded for this
* [kind]{@glossary kind}.
*
* @see module:enyo/RelationalModel~toMany#options
- * @type module:enyo/RelationalModel~RelationOptions
- * @property {String} inverseType=enyo.manyToMany - This is the **required** type.
+ * @type enyo/RelationalModel~RelationOptions
+ * @property {module:enyo/RelationalModel~Relation} inverseType=module:enyo/RelationalModel~manyToMany - This is
+ * the **required** type.
* @public
*/
options: {
inverseType: null // set after the fact
},
-
+
/**
* @private
*/
@@ -55,10 +58,10 @@ var manyToMany = module.exports = kind(
rel = model.getRelation(inverseKey),
// id = inst.get(inst.primaryKey),
isOwner = this.isOwner;
-
+
if (related && related.has(inst)) {
// if (related && (related.has(inst) || related.find(function (model) { return model.attributes[model.primaryKey] == id; }))) {
-
+
// if the relation isn't found it probably wasn't defined and we need
// to automatically generate it based on what we know
if (!rel) {
@@ -72,15 +75,15 @@ var manyToMany = module.exports = kind(
related: inst
})));
}
-
+
// if (rel.related !== inst) rel.setRelated(inst);
// if (!rel.related.has(inst)) rel.related.add(inst);
return true;
}
-
+
return false;
},
-
+
/**
* @private
*/
@@ -92,12 +95,12 @@ var manyToMany = module.exports = kind(
isOwner = this.isOwner,
model,
i;
-
+
// this is a very tricky scenario that we need to be very careful about to try
// and avoid unnecessary work (when possible) and to keep out of an infinite
// loop of notifications
if (sender === related) {
-
+
// we are attempting to distinguish between the occassions we can encounter
// this method here if our related collection emits an add, remove or change
// event -- if it is change we know it stemmed from a model already
@@ -116,7 +119,7 @@ var manyToMany = module.exports = kind(
// in this case we removed a/some model/models that should probably be
// updated to know about the removal as well
for (i = 0; (model = props.models[i]); ++i) {
-
+
// this event will be caught in the event that the model was destroyed
// but should that happen the other collections will also have done
// this already (or will do it) but if the model is already destroyed
@@ -125,7 +128,7 @@ var manyToMany = module.exports = kind(
if (!model.destroyed) model.get(inverseKey).remove(inst);
}
}
-
+
// manyToMany is a special case that requires us to propagate the changes from
// either end as changes to the parent model unlike toMany and toOne that
// exclusively rely on the isOwner field and safely assuming uni-directional
@@ -142,7 +145,7 @@ var manyToMany = module.exports = kind(
// return it to whatever it was originally
this.isOwner = isOwner;
}
-
+
} else sup.apply(this, arguments);
};
})
diff --git a/src/RelationalModel/toMany.js b/src/RelationalModel/toMany.js
index e2cdd1add..2c659fc50 100644
--- a/src/RelationalModel/toMany.js
+++ b/src/RelationalModel/toMany.js
@@ -1,17 +1,18 @@
/**
* Contains the declaration for the {@link module:enyo/RelationalModel~toMany} kind.
- * @module enyo/RelationalModel
+ * @module enyo/RelationalModel/toMany
+ * @private
*/
var
kind = require('../kind'),
utils = require('../utils'),
Collection = require('../Collection'),
- Relation = require('../Relation'),
Store = require('../Store');
var
- RelationalCollection = require('./RelationalCollection'),
+ Relation = require('./Relation'),
+ RelationalCollection = require('./Collection'),
toOne = require('./toOne');
/**
@@ -19,8 +20,9 @@ var
* models. This is an internally-used class.
*
* @class toMany
-* @extends module:enyo/Relation~Relation
-* @protected
+* @name module:enyo/RelationalModel~toMany
+* @extends module:enyo/RelationalModel~Relation
+* @private
*/
var toMany = module.exports = kind(
/** @lends module:enyo/RelationalModel~toMany.prototype */ {
@@ -36,13 +38,13 @@ var toMany = module.exports = kind(
name: 'enyo.toMany',
/**
- * The default [options]{@link module:enyo/RelationalModel~RelationOptions} overloaded for this
- * [kind]{@glossary kind}.
+ * The default [options]{@link module:enyo/RelationalModel~RelationOptions} overloaded for
+ * this [kind]{@glossary kind}.
*
* @type module:enyo/RelationalModel~RelationOptions
* @property {Boolean} create=true - By default, the relation should create the
* [collection]{@link module:enyo/Collection~Collection} automatically.
- * @property {module:enyo/Collection~Collection} collection=RelationalCollection - The
+ * @property {module:enyo/Collection~Collection} collection=module:enyo/RelationalModel~Collection - The
* [kind]{@glossary kind} of collection to use; can be the kind name or a
* reference to the constructor.
* @property {Object} collectionOptions - An options hash to pass to the
@@ -67,9 +69,6 @@ var toMany = module.exports = kind(
key = this.key,
related = this.related != null ? this.related : inst.attributes[key];
- if (typeof collection == 'string') collection = kind.constructorForKind(collection);
- if (typeof model == 'string') model = kind.constructorForKind(model);
-
// since we allow the model property to be used for the collection constructor
// we need to check for and use it if we find it
if (model.prototype instanceof Collection) {
@@ -130,15 +129,23 @@ var toMany = module.exports = kind(
fetchRelated: function () {
},
+
+ /**
+ * @private
+ */
+ isRelated: function (related) {
+ return this.related.indexOf(related) >= 0;
+ },
/**
+ * @see module:enyo/RelationalModel~Relation#setRelated
* @private
*/
- setRelated: function (data) {
+ setRelated: function (data, opts) {
var related = this.related;
// related.add(data, {purge: true, parse: true});
- related.add(data, {purge: true});
+ related.add(data, opts || {purge: true});
},
/**
diff --git a/src/RelationalModel/toOne.js b/src/RelationalModel/toOne.js
index 1dd3f0847..6cd4a7e25 100644
--- a/src/RelationalModel/toOne.js
+++ b/src/RelationalModel/toOne.js
@@ -1,42 +1,47 @@
/**
* Contains the declaration for the {@link module:enyo/RelationalModel~toOne} kind.
-* @module enyo/RelationalModel
+* @module enyo/RelationalModel/toOne
+* @private
*/
var
kind = require('../kind'),
utils = require('../utils'),
Model = require('../Model'),
- Relation = require('../Relation'),
Store = require('../Store');
+var
+ Relation = require('./Relation');
+
/**
* Represents a relationship of data from one [model]{@link module:enyo/Model~Model} to another
* model. This is an internally-used class.
*
* @class toOne
-* @extends module:enyo/Relation~Relation
-* @protected
+* @name module:enyo/RelationalModel~toOne
+* @extends module:enyo/RelationalModel~Relation
+* @private
*/
var toOne = module.exports = kind(
/** @lends module:enyo/RelationalModel~toOne.prototype */ {
-
+
/**
* @private
*/
kind: Relation,
-
+
/**
* @private
*/
name: 'enyo.toOne',
-
+
/**
* The default [options]{@link module:enyo/RelationalModel~RelationOptions} overloaded for this
* [kind]{@glossary kind}.
*
* @type module:enyo/RelationalModel~RelationOptions
- * @property {String} inverseType=enyo.toOne - This can be `'enyo.toOne'` or `'enyo.toMany'`.
+ * @property {module:enyo/RelationalModel~Relation} inverseType=module:enyo/RelationalModel~toOne - This can be
+ * {@link module:enyo/RelationalModel~toOne} or {@link module:enyo/RelationalModel~toMany}.
* @property {Object} modelOptions - An options hash to pass to the related instance if
* `create` is `true`.
* @public
@@ -45,12 +50,12 @@ var toOne = module.exports = kind(
inverseType: null, // set after the fact
modelOptions: null
},
-
+
/**
* @private
*/
init: function () {
-
+
var model = this.model,
inverseType = this.inverseType,
inst = this.instance,
@@ -60,44 +65,38 @@ var toOne = module.exports = kind(
modelOptions = this.modelOptions,
id,
found;
-
- // ensure we have a valid model constructor
- if (typeof model == 'string') model = kind.constructorForKind(model);
-
- // ensure our inverse type constructor is correct
- if (typeof inverseType == 'string') inverseType = kind.constructorForKind(inverseType);
-
+
// ensure we've got the correct related if any
if (related || related === 0) this.related = related;
-
+
// the instance attribute for the designated key will actually point to this relation
inst.attributes[key] = this;
this.inverseType = inverseType;
-
+
// if we have a related value now check to see if it is something we should attempt
// to resolve
if (related != null) {
-
+
// just make sure that no one stuck an instance in here
if (!(related instanceof Model)) {
-
+
// try and figure out what the assumed id for the related model is if possible
if (typeof related == 'object') id = related[model.prototype.primaryKey];
else if (typeof related == 'string' || typeof related == 'number') id = related;
-
+
if (id != null) found = Store.resolve(model, id);
-
+
// if we found an instance we store it and make sure to update the local
// reference here
if (found) related = this.related = found;
}
}
-
+
// if this is the owner side of the relation we may need to create the instance
// for our relation if it wasn't found already
if (related == null || !(related instanceof Model)) {
if (this.create) {
-
+
// if the only information we have about the thing is a string or number
// then we facade a data hash so the model has the opportunity to work
// as expected
@@ -106,41 +105,39 @@ var toOne = module.exports = kind(
related = {};
related[model.prototype.primaryKey] = id;
}
-
+
// if the parse flag is true then we force a parse operation on model
// creation regardless of its own flags
if (this.parse) {
if (!modelOptions) modelOptions = {};
modelOptions.parse = true;
}
- /*jshint -W055 */
// we create the empty instance so we can separately deal with the
// various ways the related data could be handed to us (could be id or data)
found = model = new model(related, null, modelOptions);
- /*jshint +W055 */
this.related = model;
}
}
-
+
if (!found) Store.on(model, 'add', this._changed, this);
-
+
// last but not least we begin to listen for changes on our model instance
inst.on('change', this._changed, this);
},
-
+
/**
* @private
*/
setRelated: kind.inherit(function (sup) {
return function (related) {
var val;
-
+
if (related && related instanceof Model) {
return sup.apply(this, arguments);
} else if (related != null) {
val = related;
related = this.getRelated();
-
+
// the only thing we can do is assume the value is intended to be the primary
// key of the model just like we would had it been passed into the constructor
if (this.create && related) related.set(related.primaryKey, val);
@@ -155,34 +152,34 @@ var toOne = module.exports = kind(
if (related && related instanceof Model) return sup.call(this, related);
}
}
-
+
// @TODO: This ignores cases that it might be set as null or undefined which
// would clear the related but most of the code assumes there will always be
// a value for related but it seems _possible_ that this behavior may be
// necessary so would need to find a way to handle that
};
}),
-
+
/**
* @private
*/
fetchRelated: function () {
},
-
+
/**
* @private
*/
findRelated: function () {
-
+
var related = this.related,
// inst = this.instance,
isOwner = this.isOwner,
found,
rev;
-
+
if (related && related instanceof this.model) found = related;
else {
-
+
// we need to search for the related instance if we can
found = Store.findLocal(
this.model,
@@ -190,20 +187,20 @@ var toOne = module.exports = kind(
{all: false, context: this}
);
}
-
+
if (found) {
-
+
// if we are the owner end we may have a listener on the store and can
// safely remove it
Store.off(this.model, 'add', this._changed, this);
-
+
// update our related value
this.related = found;
-
+
// if we can/need to we will establish the other end of this relationship
if (this.inverseKey) {
rev = found.getRelation(this.inverseKey);
-
+
// if there isn't one then we go ahead and create it implicitly
if (!rev) {
rev = new this.inverseType(found, {
@@ -214,27 +211,20 @@ var toOne = module.exports = kind(
model: this.instance.ctor,
related: this.instance
});
-
+
found.relations.push(rev);
}
-
+
// now we ensure that the instances are pointing at eachother
- switch (rev.kindName) {
- case 'enyo.toOne':
- if (rev.related !== this.instance) rev.setRelated(this.instance);
- break;
- case 'enyo.toMany':
- rev.related.add(this.instance, {merge: false});
- break;
- }
+ if (!rev.isRelated(this.instance)) rev.setRelated(this.instance, {merge: false});
}
-
+
if (isOwner) found.on('change', this._changed, this);
}
-
+
return found;
},
-
+
/**
* @private
*/
@@ -244,7 +234,7 @@ var toOne = module.exports = kind(
id = inst.get(inst.primaryKey),
inverseKey = this.inverseKey,
pkey = model.get(model.primaryKey);
-
+
return (related && (
model.euid == related ||
pkey == related ||
@@ -252,7 +242,7 @@ var toOne = module.exports = kind(
) || (id != null && model.get(inverseKey) == id)
);
},
-
+
/**
* @private
*/
@@ -267,7 +257,7 @@ var toOne = module.exports = kind(
}
return raw;
},
-
+
/**
* @private
*/
@@ -276,18 +266,18 @@ var toOne = module.exports = kind(
inst = this.instance,
isOwner = this.isOwner,
changed;
-
+
if (sender === this.instance) {
if (e == 'change') {
if (key in props) this.findRelated();
}
} else if (sender === this.related) {
if (e == 'change' && isOwner) {
-
+
// if the instance is already changing then we do not need to do anything
// because it probably stemmed from there anyway
if (inst._changing) return;
-
+
// @todo This must be updated to be more thorough...
inst.isDirty = true;
changed = inst.changed || (inst.changed = {});
diff --git a/src/Repeater.js b/src/Repeater.js
index 9c7116608..930ccae2c 100644
--- a/src/Repeater.js
+++ b/src/Repeater.js
@@ -15,7 +15,7 @@ var
* The extended {@glossary event} [object]{@glossary Object} that is provided
* when the [onSetupItem]{@link module:enyo/Repeater~Repeater#onSetupItem} event is fired.
*
-* @typedef {Object} enyo.Repeater~SetupItemEvent
+* @typedef {Object} module:enyo/Repeater~Repeater~SetupItemEvent
* @property {Number} index - The item's index.
* @property {Object} item - The item control, for decoration.
*/
@@ -95,7 +95,7 @@ var OwnerProxy = kind(
* Repeater = require('enyo/Repeater');
*
* {kind: Repeater, count: 2, onSetupItem: 'setImageSource', components: [
-* {kind: 'Image'}
+* {kind: Image}
* ]}
*
* setImageSource: function(inSender, inEvent) {
diff --git a/src/RepeaterChildSupport.js b/src/RepeaterChildSupport.js
index 46d665ba4..b917809a5 100644
--- a/src/RepeaterChildSupport.js
+++ b/src/RepeaterChildSupport.js
@@ -39,6 +39,15 @@ var RepeaterChildSupport = {
*/
selected: false,
+ /**
+ * The CSS class applied to the child when selected
+ *
+ * @name module:enyo/RepeaterChildSupport~RepeaterChildSupport#selectedClass
+ * @type {String}
+ * @default null
+ * @public
+ */
+
/**
* Setting cachePoint: true ensures that events from the repeater child's subtree will
* always bubble up through the child, allowing the events to be decorated with repeater-
@@ -49,7 +58,7 @@ var RepeaterChildSupport = {
* @private
*/
cachePoint: true,
-
+
/*
* @method
* @private
@@ -109,9 +118,9 @@ var RepeaterChildSupport = {
}
},
/**
- * Deliberately used to supersede the default method and set
- * [owner]{@link module:enyo/Component~Component#owner} to this [control]{@link module:enyo/Control~Control} so that there
- * are no name collisions in the instance [owner]{@link module:enyo/Component~Component#owner}, and also so
+ * Deliberately used to supersede the default method and set
+ * [owner]{@link module:enyo/Component~Component#owner} to this [control]{@link module:enyo/Control~Control} so that there
+ * are no name collisions in the instance [owner]{@link module:enyo/Component~Component#owner}, and also so
* that [bindings]{@link module:enyo/Binding~Binding} will correctly map to names.
*
* @method
@@ -132,7 +141,7 @@ var RepeaterChildSupport = {
dispatchEvent: kind.inherit(function (sup) {
return function (name, event, sender) {
var owner;
-
+
// if the event is coming from a child of the repeater-child (this...) and has a
// delegate assigned to it there is a distinct possibility it is supposed to be
// targeting the instanceOwner of repeater-child not the repeater-child itself
@@ -151,7 +160,7 @@ var RepeaterChildSupport = {
}
}
}
-
+
if (!event._fromRepeaterChild) {
if (!!~utils.indexOf(name, this.repeater.selectionEvents)) {
this._selectionHandler();
@@ -177,8 +186,7 @@ var RepeaterChildSupport = {
var bnd = this.binding({
from: 'model.' + s,
to: 'selected',
- oneWay: false/*,
- kind: enyo.BooleanBinding*/
+ oneWay: false
});
this._selectionBindingId = bnd.euid;
}
diff --git a/src/RichText/RichText.js b/src/RichText/RichText.js
index dae00b0de..12f8ff13f 100644
--- a/src/RichText/RichText.js
+++ b/src/RichText/RichText.js
@@ -19,14 +19,14 @@ var
/**
* The type of change to apply. Possible values are `'move'` and `'extend'`.
*
-* @typedef {String} enyo.RichText~ModifyType
+* @typedef {String} module:enyo/RichText~RichText~ModifyType
*/
/**
* The direction in which to apply the change. Possible values include: `'forward'`,
* `'backward'`, `'left'`, and `'right'`.
*
-* @typedef {String} enyo.RichText~ModifyDirection
+* @typedef {String} module:enyo/RichText~RichText~ModifyDirection
*/
/**
@@ -34,7 +34,7 @@ var
* `'sentence'`, `'line'`, `'paragraph'`, `'lineboundary'`, `'sentenceboundary'`,
* `'paragraphboundary'`, and `'documentboundary'`.
*
-* @typedef {String} enyo.RichText~ModifyAmount
+* @typedef {String} module:enyo/RichText~RichText~ModifyAmount
*/
/**
@@ -277,6 +277,7 @@ var RichText = module.exports = kind(
* @param {module:enyo/RichText~ModifyType} type - The type of change to apply.
* @param {module:enyo/RichText~ModifyDirection} dir - The direction in which to apply the change.
* @param {module:enyo/RichText~ModifyAmount} amount - The granularity of the change.
+ * @deprecated since version 2.7
* @public
*/
modifySelection: function (type, dir, amount) {
@@ -291,6 +292,7 @@ var RichText = module.exports = kind(
*
* @param {module:enyo/RichText~ModifyDirection} dir - The direction in which to apply the change.
* @param {module:enyo/RichText~ModifyAmount} amount - The granularity of the change.
+ * @deprecated since version 2.7
* @public
*/
moveCursor: function (dir, amount) {
@@ -300,6 +302,7 @@ var RichText = module.exports = kind(
/**
* Moves the cursor to end of text field.
*
+ * @deprecated since version 2.7
* @public
*/
moveCursorToEnd: function () {
@@ -309,6 +312,7 @@ var RichText = module.exports = kind(
/**
* Moves the cursor to start of text field.
*
+ * @deprecated since version 2.7
* @public
*/
moveCursorToStart: function () {
diff --git a/src/ScrollMath.js b/src/ScrollMath.js
index ca759576b..18f2bfb86 100644
--- a/src/ScrollMath.js
+++ b/src/ScrollMath.js
@@ -19,7 +19,7 @@ var
*
* @event module:enyo/ScrollMath~ScrollMath#onScrollStart
* @type {Object}
-* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
+* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
* propagated the {@glossary event}.
* @property {module:enyo/Scroller~Scroller~ScrollEvent} event - An [object]{@glossary Object} containing
* event information.
@@ -31,7 +31,7 @@ var
*
* @event module:enyo/ScrollMath~ScrollMath#onScroll
* @type {Object}
-* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
+* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
* propagated the {@glossary event}.
* @property {module:enyo/Scroller~Scroller~ScrollEvent} event - An [object]{@glossary Object} containing
* event information.
@@ -43,7 +43,7 @@ var
*
* @event module:enyo/ScrollMath~ScrollMath#onScrollStop
* @type {Object}
-* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
+* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
* propagated the {@glossary event}.
* @property {module:enyo/Scroller~Scroller~ScrollEvent} event - An [object]{@glossary Object} containing
* event information.
@@ -54,7 +54,7 @@ var
* {@link module:enyo/ScrollMath~ScrollMath} implements a scrolling dynamics simulation. It is a
* helper [kind]{@glossary kind} used by other [scroller]{@link module:enyo/Scroller~Scroller}
* kinds, such as {@link module:enyo/TouchScrollStrategy~TouchScrollStrategy}.
-*
+*
* `enyo/ScrollMath` is not typically created in application code.
*
* @class ScrollMath
@@ -73,10 +73,10 @@ module.exports = kind(
/**
* @private
*/
- published:
+ published:
/** @lends module:enyo/ScrollMath~ScrollMath.prototype */ {
- /**
+ /**
* Set to `true` to enable vertical scrolling.
*
* @type {Boolean}
@@ -85,7 +85,7 @@ module.exports = kind(
*/
vertical: true,
- /**
+ /**
* Set to `true` to enable horizontal scrolling.
*
* @type {Boolean}
@@ -106,95 +106,95 @@ module.exports = kind(
},
/**
- * "Spring" damping returns the scroll position to a value inside the boundaries. Lower
+ * "Spring" damping returns the scroll position to a value inside the boundaries. Lower
* values provide faster snapback.
*
* @private
*/
kSpringDamping: 0.93,
- /**
- * "Drag" damping resists dragging the scroll position beyond the boundaries. Lower values
+ /**
+ * "Drag" damping resists dragging the scroll position beyond the boundaries. Lower values
* provide more resistance.
*
* @private
*/
kDragDamping: 0.5,
-
- /**
+
+ /**
* "Friction" damping reduces momentum over time. Lower values provide more friction.
*
* @private
*/
kFrictionDamping: 0.97,
- /**
- * Additional "friction" damping applied when momentum carries the viewport into overscroll.
+ /**
+ * Additional "friction" damping applied when momentum carries the viewport into overscroll.
* Lower values provide more friction.
*
* @private
*/
kSnapFriction: 0.9,
-
- /**
+
+ /**
* Scalar applied to `flick` event velocity.
*
* @private
*/
kFlickScalar: 15,
- /**
- * Limits the maximum allowable flick. On Android > 2, we limit this to prevent compositing
+ /**
+ * Limits the maximum allowable flick. On Android > 2, we limit this to prevent compositing
* artifacts.
*
* @private
*/
kMaxFlick: platform.android > 2 ? 2 : 1e9,
-
- /**
- * The value used in [friction()]{@link module:enyo/ScrollMath~ScrollMath#friction} to determine if the delta
+
+ /**
+ * The value used in [friction()]{@link module:enyo/ScrollMath~ScrollMath#friction} to determine if the delta
* (e.g., y - y0) is close enough to zero to consider as zero.
*
* @private
*/
kFrictionEpsilon: platform.webos >= 4 ? 1e-1 : 1e-2,
-
- /**
+
+ /**
* Top snap boundary, generally `0`.
*
* @private
*/
topBoundary: 0,
-
- /**
+
+ /**
* Right snap boundary, generally `(viewport width - content width)`.
*
* @private
*/
rightBoundary: 0,
-
- /**
+
+ /**
* Bottom snap boundary, generally `(viewport height - content height)`.
*
* @private
*/
bottomBoundary: 0,
-
- /**
+
+ /**
* Left snap boundary, generally `0`.
*
* @private
*/
leftBoundary: 0,
-
- /**
+
+ /**
* Animation time step.
*
* @private
*/
interval: 20,
-
- /**
+
+ /**
* Flag to enable frame-based animation; if `false`, time-based animation is used.
*
* @private
@@ -267,7 +267,7 @@ module.exports = kind(
},
/**
- * Boundary damping function. Returns damped `value` based on `coeff` on one side of
+ * Boundary damping function. Returns damped `value` based on `coeff` on one side of
* `origin`.
*
* @private
@@ -289,7 +289,7 @@ module.exports = kind(
},
/**
- * Dual-boundary damping function. Returns damped `value` based on `coeff` when exceeding
+ * Dual-boundary damping function. Returns damped `value` based on `coeff` when exceeding
* either boundary.
*
* @private
@@ -334,7 +334,7 @@ module.exports = kind(
this[ex] = this[ex0] + c * dp;
},
- /**
+ /**
* One unit of time for simulation.
*
* @private
@@ -466,7 +466,7 @@ module.exports = kind(
});
this.job = animation.requestAnimationFrame(fn);
},
-
+
/**
* @private
*/
@@ -483,7 +483,7 @@ module.exports = kind(
stop: function (fire) {
var job = this.job;
if (job) {
- this.job = animation.cancelRequestAnimationFrame(job);
+ this.job = animation.cancelAnimationFrame(job);
}
if (fire) {
this.doScrollStop();
@@ -533,7 +533,7 @@ module.exports = kind(
if (this.dragging) {
v = this.canScrollY();
h = this.canScrollX();
-
+
dy = v ? e.pageY - this.my : 0;
this.uy = dy + this.py;
// provides resistance against dragging into overscroll
@@ -643,7 +643,7 @@ module.exports = kind(
dX = dY;
dY = 0;
}
-
+
if (dY && canY) {
tY = -(refY + (dY * m));
shouldScroll = true;
@@ -670,7 +670,7 @@ module.exports = kind(
// NOTE: Yip/Orvell method for determining scroller instantaneous velocity
// FIXME: incorrect if called when scroller is in overscroll region
// because does not account for additional overscroll damping.
-
+
/**
* Scrolls to the specified position.
*
@@ -754,7 +754,7 @@ module.exports = kind(
setScrollPosition: function (pos) {
this.setScrollY(pos);
},
-
+
canScrollX: function() {
return this.horizontal && this.rightBoundary < 0;
},
@@ -764,9 +764,9 @@ module.exports = kind(
},
- /**
+ /**
* Determines whether or not the [scroller]{@link module:enyo/Scroller~Scroller} is actively moving.
- *
+ *
* @return {Boolean} `true` if actively moving; otherwise, `false`.
* @private
*/
@@ -774,9 +774,9 @@ module.exports = kind(
return Boolean(this.job);
},
- /**
+ /**
* Determines whether or not the [scroller]{@link module:enyo/Scroller~Scroller} is in overscroll.
- *
+ *
* @return {Boolean} `true` if in overscroll; otherwise, `false`.
* @private
*/
diff --git a/src/Scrollable/Scrollable.js b/src/Scrollable/Scrollable.js
index c2eb8055e..a18aa563d 100644
--- a/src/Scrollable/Scrollable.js
+++ b/src/Scrollable/Scrollable.js
@@ -1,3 +1,11 @@
+/**
+* Exports the {@link module:enyo/Scrollable~Scrollable} mixin.
+*
+* @wip
+* @public
+* @module enyo/Scrollable
+*/
+
var
kind = require('../kind'),
utils = require('../utils'),
@@ -27,18 +35,32 @@ function calcNodeVisibility (nodePos, nodeSize, scrollPos, scrollSize) {
}
/**
-* Doc
+* Mix scrolling support into any Control that contains content suitable for scrolling.
*
-* @module enyo/Scrollable
+* @mixin
+* @wip
* @public
*/
-module.exports = {
+var Scrollable = {
/**
* @private
*/
name: 'Scrollable',
-
+
+ /**
+ * An array of control definitions that will be instatiated with the scroller. Each object
+ * will be passed a `scroller` property that contains a reference to the scroller. The controls
+ * can register to receive scroll events from the scroller.
+ *
+ * @name scrollControls
+ * @type {Object[]}
+ * @default undefined
+ * @see module:enyo/NewThumb~NewThumb
+ * @public
+ * @memberof module:enyo/Scrollable~Scrollable
+ */
+
/**
* Specifies how to horizontally scroll. Acceptable values are `'scroll'`, `'auto'`,
* `'hidden'`, and `'default'`. The precise effect of the setting is determined by the
@@ -80,24 +102,19 @@ module.exports = {
scrollLeft: 0,
/**
- * Maximum height of the scroll content.
- *
- * @type {Number}
- * @default null
- * @memberof module:enyo/Scroller~Scroller.prototype
- * @public
+ * Vestige of previous implementation -- should be eliminated and
+ * does not appear to be referenced, but leaving here for the moment
+ * to avoid accidental breakage.
+ *
+ * @private
*/
maxHeight: null,
/**
- * Set to `true` to make this [scroller]{@link module:enyo/Scroller~Scroller} select a
- * platform-appropriate touch-based scrolling strategy. Note that if you specify a value
- * for [strategyKind]{@link module:enyo/Scroller~Scroller#strategyKind}, that will take precedence over
- * this setting.
- *
- * @type {Boolean}
- * @default false
- * @public
+ * Vestige of previous implementation -- should be eliminated, but
+ * currently still referenced.
+ *
+ * @private
*/
touch: true,
@@ -127,16 +144,16 @@ module.exports = {
block: 'farthest',
/**
- * Set to `true` to display a scroll thumb in touch [scrollers]{@link module:enyo/Scroller~Scroller}.
- *
- * @type {Boolean}
- * @default true
- * @public
+ * Vestige of previous implementation -- should be eliminated and
+ * does not appear to be referenced, but leaving here for the moment
+ * to avoid accidental breakage.
+ *
+ * @private
*/
thumb: true,
/**
- * If `true`, mouse wheel may be used to move the [scroller]{@link module:enyo/Scroller~Scroller}.
+ * If `true`, mouse wheel may be used to move the [scrollable]{@link module:enyo/Scrollable~Scrollable} control.
*
* @type {Boolean}
* @default true
@@ -145,51 +162,116 @@ module.exports = {
useMouseWheel: true,
/**
- * TODO: Document
- * Experimental
+ * This should ultimately be made public, but not sure it's fully baked so
+ * holding off for now.
*
- * @public
+ * @private
*/
horizontalSnapIncrement: null,
/**
- * TODO: Document
- * Experimental
+ * This should ultimately be made public, but not sure it's fully baked so
+ * holding off for now.
*
- * @public
+ * @private
*/
verticalSnapIncrement: null,
/**
- * TODO: Document
- * Experimental
+ * This should ultimately be made public, but not sure it's fully baked so
+ * holding off for now.
*
- * @public
+ * @private
*/
suppressMouseEvents: false,
+ /**
+ * By default, {@link module:enyo/Scrollable~Scrollable} creates and
+ * uses a default instance of {@link module:enyo/ScrollMath~ScrollMath}, which
+ * is responsible for scroll physics.
+ *
+ * If you want to customize scroll physics, you can provide an object literal
+ * to the `scrollMath` property that will be used to create a
+ * {@link module:enyo/ScrollMath~ScrollMath} instance to your specifications.
+ * Make sure to include `kind: ScrollMath` in your object literal, along with
+ * whatever `ScrollMath` properties you want to set.
+ *
+ * @type {Object}
+ * @public
+ */
scrollMath: {kind: ScrollMath},
+ /**
+ * This should ultimately be made public, but not sure it's fully baked so
+ * holding off for now.
+ *
+ * @private
+ */
pageMultiplier: 1,
+ /**
+ * @private
+ */
canScrollX: false,
+ /**
+ * @private
+ */
canScrollY: false,
+ /**
+ * @private
+ */
couldScrollX: false,
+ /**
+ * @private
+ */
couldScrollY: false,
+ /**
+ * @private
+ */
canScrollUp: false,
+ /**
+ * @private
+ */
canScrollDown: false,
+ /**
+ * @private
+ */
canScrollLeft: false,
+ /**
+ * @private
+ */
canScrollRight: false,
+ /**
+ * @private
+ */
velocity: 0,
+ /**
+ * @private
+ */
topOffset: 0,
+ /**
+ * @private
+ */
rightOffset: 0,
+ /**
+ * @private
+ */
bottomOffset: 0,
+ /**
+ * @private
+ */
leftOffset: 0,
+ /**
+ * @private
+ */
mixins: [EventEmitter],
+ /**
+ * @private
+ */
handlers: {
ondragstart: 'dragstart',
ondragfinish: 'dragfinish',
@@ -213,8 +295,14 @@ module.exports = {
onShouldDrag: ''
},
+ /**
+ * @private
+ */
classes: 'enyo-scrollable enyo-fill',
+ /**
+ * @private
+ */
create: kind.inherit(function (sup) {
return function() {
sup.apply(this, arguments);
@@ -234,6 +322,9 @@ module.exports = {
};
}),
+ /**
+ * @private
+ */
destroy: kind.inherit(function (sup) {
return function () {
sup.apply(this, arguments);
@@ -243,8 +334,21 @@ module.exports = {
};
}),
+ /**
+ * @private
+ */
showingChangedHandler: kind.inherit(function (sup) {
return function (sender, event) {
+ // Calculate boundaries when shown, just in case
+ // anything has happened (like scroller contents changing)
+ // while we were hidden. We do this unconditionally since
+ // it's cheap to do it now and we avoid a lot of extra
+ // complexity by not trying to track whether we need it.
+ // May need to revisit this decision if related issues
+ // arise.
+ if (event.showing) {
+ this.calcBoundaries();
+ }
sup.apply(this, arguments);
if (!event.showing && this._suppressing) {
this._resumeMouseEvents();
@@ -252,6 +356,9 @@ module.exports = {
};
}),
+ /**
+ * @private
+ */
rendered: kind.inherit(function (sup) {
return function() {
sup.apply(this, arguments);
@@ -1061,3 +1168,5 @@ module.exports = {
return false;
}
};
+
+module.exports = Scrollable;
diff --git a/src/Scroller/Scroller.js b/src/Scroller/Scroller.js
index 42f99c8f4..05111272d 100644
--- a/src/Scroller/Scroller.js
+++ b/src/Scroller/Scroller.js
@@ -47,7 +47,7 @@ var
*/
/**
-* The extended {@glossary event} [object]{@glossary Object} that is provided
+* The extended {@glossary event} [object]{@glossary Object} that is provided
* when a scroll event is fired.
*
* @typedef {Object} module:enyo/Scroller~Scroller~ScrollEvent
@@ -59,7 +59,7 @@ var
*
* @event module:enyo/Scroller~Scroller#onScrollStart
* @type {Object}
-* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
+* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
* propagated the {@glossary event}.
* @property {module:enyo/Scroller~Scroller~ScrollEvent} event - An [object]{@glossary Object} containing
* event information.
@@ -71,9 +71,9 @@ var
*
* @event module:enyo/Scroller~Scroller#onScroll
* @type {Object}
-* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
+* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
* propagated the {@glossary event}.
-* @property {Object} event - An [object]{@glossary Object} containing
+* @property {Object} event - An [object]{@glossary Object} containing
* event information.
* @public
*/
@@ -83,9 +83,9 @@ var
*
* @event module:enyo/Scroller~Scroller#onScrollStop
* @type {Object}
-* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
+* @property {Object} sender - The [component]{@link module:enyo/Component~Component} that most recently
* propagated the {@glossary event}.
-* @property {Object} event - An [object]{@glossary Object} containing
+* @property {Object} event - An [object]{@glossary Object} containing
* event information.
* @public
*/
@@ -93,14 +93,14 @@ var
/**
* {@link module:enyo/Scroller~Scroller} is a scroller suitable for use in both desktop and mobile
* applications.
-*
+*
* In some mobile environments, a default scrolling solution is not implemented for
* DOM elements. In such cases, `enyo/Scroller` implements a touch-based scrolling
* solution, which may be opted into either globally (by setting
* [touchScrolling]{@link module:enyo/Scroller~Scroller#touchScrolling} to `true`) or on a
* per-instance basis (by specifying a [strategyKind]{@link module:enyo/Scroller~Scroller#strategyKind}
* of `'TouchScrollStrategy'`).
-*
+*
* For more information, see the documentation on
* [Scrollers]{@linkplain $dev-guide/building-apps/layout/scrollers.html} in the
* Enyo Developer Guide.
@@ -110,22 +110,22 @@ var
*/
var Scroller = module.exports = kind(
/** @lends module:enyo/Scroller~Scroller.prototype */ {
-
+
name: 'enyo.Scroller',
-
+
kind: Control,
-
+
/**
* @private
*/
- published:
+ published:
/** @lends module:enyo/Scroller~Scroller.prototype */ {
/**
* Specifies how to horizontally scroll. Acceptable values are `'scroll'`, `'auto'`,
* `'hidden'`, and `'default'`. The precise effect of the setting is determined by the
* scroll strategy.
- *
+ *
* @type {String}
* @default 'default'
* @public
@@ -136,7 +136,7 @@ var Scroller = module.exports = kind(
* Specifies how to vertically scroll. Acceptable values are `'scroll'`, `'auto'`,
* `'hidden'`, and `'default'`. The precise effect of the setting is determined by the
* scroll strategy.
- *
+ *
* @type {String}
* @default 'default'
* @public
@@ -145,7 +145,7 @@ var Scroller = module.exports = kind(
/**
* The vertical scroll position.
- *
+ *
* @type {Number}
* @default 0
* @public
@@ -154,7 +154,7 @@ var Scroller = module.exports = kind(
/**
* The horizontal scroll position.
- *
+ *
* @type {Number}
* @default 0
* @public
@@ -163,7 +163,7 @@ var Scroller = module.exports = kind(
/**
* Maximum height of the scroll content.
- *
+ *
* @type {Number}
* @default null
* @memberof enyo/Scroller~Scroller.prototype
@@ -172,41 +172,40 @@ var Scroller = module.exports = kind(
maxHeight: null,
/**
- * Set to `true` to make this [scroller]{@link module:enyo/Scroller~Scroller} select a
- * platform-appropriate touch-based scrolling strategy. Note that if you specify a value
+ * Set to `true` to make this [scroller]{@link module:enyo/Scroller~Scroller} select a
+ * platform-appropriate touch-based scrolling strategy. Note that if you specify a value
* for [strategyKind]{@link module:enyo/Scroller~Scroller#strategyKind}, that will take precedence over
* this setting.
- *
+ *
* @type {Boolean}
* @default false
* @public
*/
touch: false,
/**
- * Specifies a type of scrolling. The [scroller]{@link module:enyo/Scroller~Scroller} will attempt to
+ * Specifies a type of scrolling. The [scroller]{@link module:enyo/Scroller~Scroller} will attempt to
* automatically select a strategy compatible with the runtime environment. Alternatively,
* you may choose to use a specific strategy:
- *
- * - [ScrollStrategy]{@link module:enyo/ScrollStrategy~ScrollStrategy} is the default and implements no
+ *
+ * - [ScrollStrategy]{@link module:enyo/ScrollStrategy~ScrollStrategy} is the default and implements no
* scrolling, relying instead on the environment to scroll properly.
- * - [TouchScrollStrategy]{@link module:enyo/TouchScrollStrategy~TouchScrollStrategy} implements a touch scrolling
+ * - [TouchScrollStrategy]{@link module:enyo/TouchScrollStrategy~TouchScrollStrategy} implements a touch scrolling
* mechanism.
- * - [TranslateScrollStrategy]{@link module:enyo/TranslateScrollStrategy~TranslateScrollStrategy} implements a touch
+ * - [TranslateScrollStrategy]{@link module:enyo/TranslateScrollStrategy~TranslateScrollStrategy} implements a touch
* scrolling mechanism using translations; it is currently recommended only for Android
- * 3 and 4, and Windows Phone 8.
- * - [TransitionScrollStrategy]{@link module:enyo/TransitionScrollStrategy~TransitionScrollStrategy} implements a touch
- * scrolling mechanism using CSS transitions; it is currently recommended only for iOS
- * 5 and later.
+ * 3+, iOS 5+ and Windows Phone 8.
+ * - [TransitionScrollStrategy]{@link module:enyo/TransitionScrollStrategy~TransitionScrollStrategy} implements a touch
+ * scrolling mechanism using CSS transitions;
*
- * @type {String}
- * @default 'ScrollStrategy'
+ * @type {Object}
+ * @default module:enyo/ScrollStrategy~ScrollStrategy
* @public
*/
strategyKind: ScrollStrategy,
/**
* Set to `true` to display a scroll thumb in touch [scrollers]{@link module:enyo/Scroller~Scroller}.
- *
+ *
* @type {Boolean}
* @default true
* @public
@@ -215,7 +214,7 @@ var Scroller = module.exports = kind(
/**
* If `true`, mouse wheel may be used to move the [scroller]{@link module:enyo/Scroller~Scroller}.
- *
+ *
* @type {Boolean}
* @default true
* @public
@@ -253,7 +252,7 @@ var Scroller = module.exports = kind(
touchOverscroll: true,
/**
- * If `true`, the [scroller]{@link module:enyo/Scroller~Scroller} will not propagate `dragstart`
+ * If `true`, the [scroller]{@link module:enyo/Scroller~Scroller} will not propagate `dragstart`
* [events]{@glossary event} that cause it to start scrolling.
*
* @type {Boolean}
@@ -263,7 +262,7 @@ var Scroller = module.exports = kind(
preventDragPropagation: true,
/**
- * If `true`, the [scroller]{@link module:enyo/Scroller~Scroller} will not propagate scroll
+ * If `true`, the [scroller]{@link module:enyo/Scroller~Scroller} will not propagate scroll
* [events]{@glossary event}.
*
* @type {Boolean}
@@ -274,7 +273,7 @@ var Scroller = module.exports = kind(
/**
* Needed to allow global mods to `enyo/Scroller.touchScrolling`.
- *
+ *
* @private
*/
@@ -295,9 +294,13 @@ var Scroller = module.exports = kind(
classes: 'enyo-scroller',
/**
+ * @lends module:enyo/Scroller~Scroller
* @private
*/
statics: {
+ /**
+ * @private
+ */
osInfo: [
{os: 'android', version: 3},
{os: 'androidChrome', version: 18},
@@ -308,7 +311,7 @@ var Scroller = module.exports = kind(
{os: 'blackberry', version:1e9},
{os: 'tizen', version: 2}
],
- //* Returns true if platform should have touch events.
+ /** Returns true if platform should have touch events. */
hasTouchScrolling: function() {
for (var i=0, t; (t=this.osInfo[i]); i++) {
if (platform[t.os]) {
@@ -321,8 +324,8 @@ var Scroller = module.exports = kind(
}
},
/**
- Returns true if the platform has native div scrollers (desktop
- browsers always have them).
+ * Returns true if the platform has native div scrollers (desktop
+ * browsers always have them).
*/
hasNativeScrolling: function() {
for (var i=0, t; (t=this.osInfo[i]); i++) {
@@ -332,8 +335,11 @@ var Scroller = module.exports = kind(
}
return true;
},
+ /**
+ * @private
+ */
getTouchStrategy: function() {
- return (platform.androidChrome >= 27) || (platform.android >= 3) || (platform.windowsPhone === 8) || (platform.webos >= 4)
+ return (platform.androidChrome >= 27) || (platform.android >= 3) || (platform.ios >= 5) || (platform.windowsPhone === 8) || (platform.webos >= 4)
? TranslateScrollStrategy
: TouchScrollStrategy;
}
@@ -488,7 +494,7 @@ var Scroller = module.exports = kind(
// FIXME: these properties are virtual; property changed methods are fired only if
// property value changes, not if getter changes.
-
+
/**
* Sets the horizontal scroll position.
*
@@ -535,7 +541,7 @@ var Scroller = module.exports = kind(
/**
* Retrieves the scroll boundaries of the [scroller]{@link module:enyo/Scroller~Scroller}.
- *
+ *
* @returns {module:enyo/Scroller~BoundaryObject} An [object]{@glossary Object} describing the
* scroll boundaries.
* @public
@@ -554,11 +560,11 @@ var Scroller = module.exports = kind(
return bounds;
},
- /**
+ /**
* Trigger a remeasurement of the scroller's metrics (specifically, the
* size of its viewport, the size of its contents and the difference between
* the two, which determines the extent to which the scroller may scroll).
- *
+ *
* You should generally not need to call this from application code, as the
* scroller usually remeasures automatically whenever needed. This method
* exists primarily to support an internal use case for
@@ -584,7 +590,7 @@ var Scroller = module.exports = kind(
this.$.strategy.scrollIntoView(ctl, alignWithTop);
},
- /**
+ /**
* Scrolls to the specified position.
*
* @param {Number} x - The `x` position in pixels.
@@ -596,10 +602,10 @@ var Scroller = module.exports = kind(
},
/**
- * Ensures that the given [control]{@link module:enyo/Control~Control} is visible in the
- * [scroller's]{@link module:enyo/Scroller~Scroller} viewport. Unlike
- * [scrollIntoView()]{@link module:enyo/Scroller~Scroller#scrollIntoView}, which uses DOM's
- * [scrollIntoView()]{@glossary scrollIntoView}, this only affects the current
+ * Ensures that the given [control]{@link module:enyo/Control~Control} is visible in the
+ * [scroller's]{@link module:enyo/Scroller~Scroller} viewport. Unlike
+ * [scrollIntoView()]{@link module:enyo/Scroller~Scroller#scrollIntoView}, which uses DOM's
+ * [scrollIntoView()]{@glossary scrollIntoView}, this only affects the current
* scroller.
*
* @param {module:enyo/Control~Control} ctl - The [control]{@link module:enyo/Control~Control} to make visible in the
@@ -612,7 +618,7 @@ var Scroller = module.exports = kind(
this.scrollToNode(ctl.hasNode(), alignWithTop);
},
- /**
+ /**
* Ensures that the given node is visible in the [scroller's]{@link module:enyo/Scroller~Scroller} viewport.
*
* @param {Node} node - The node to make visible in the [scroller's]{@link module:enyo/Scroller~Scroller}
@@ -625,9 +631,9 @@ var Scroller = module.exports = kind(
this.$.strategy.scrollToNode(node, alignWithTop);
},
- /**
+ /**
* Stops the scroller if it is currently animating.
- *
+ *
* @public
*/
stop: function() {
@@ -636,9 +642,9 @@ var Scroller = module.exports = kind(
}
},
- /**
+ /**
* Adds current values of `getScrollBounds()` to {@glossary event}.
- *
+ *
* @private
*/
decorateScrollEvent: function (e) {
@@ -670,7 +676,7 @@ var Scroller = module.exports = kind(
this.scrollTop = bounds.top;
},
- /**
+ /**
* Normalizes scroll {@glossary event} to `onScroll`.
*
* @fires module:enyo/Scroller~Scroller#onScroll
@@ -710,7 +716,7 @@ var Scroller = module.exports = kind(
return true;
},
- /**
+ /**
* Either propagates or stops the current scroll {@glossary event}.
*
* @private
@@ -795,7 +801,7 @@ var Scroller = module.exports = kind(
},
/**
- * Sends the [useMouseWheel]{@link module:enyo/Scroller~Scroller#useMouseWheel} property to the scroll
+ * Sends the [useMouseWheel]{@link module:enyo/Scroller~Scroller#useMouseWheel} property to the scroll
* strategy.
*
* @private
diff --git a/src/Select.js b/src/Select.js
index cdfd106b1..ead5457a2 100644
--- a/src/Select.js
+++ b/src/Select.js
@@ -7,8 +7,7 @@ require('enyo');
var
kind = require('./kind'),
- platform = require('./platform'),
- dispatcher = require('./dispatcher');
+ platform = require('./platform');
var
Control = require('./Control'),
/*jshint -W079*/
@@ -38,7 +37,7 @@ var
* }
* }
* ```
-*
+*
* Note: This uses the [<select>]{@glossary select} tag, which isn't implemented for
* native webOS applications, although it does work in the webOS Web browser.
*
@@ -63,12 +62,12 @@ module.exports = kind(
/**
* @private
*/
- published:
+ published:
/** @lends module:enyo/Select~Select.prototype */ {
-
+
/**
* The index of the selected [option]{@link module:enyo/Option~Option} in the list.
- *
+ *
* @type {Number}
* @default null
* @public
@@ -77,7 +76,7 @@ module.exports = kind(
/**
* The value of the selected [option]{@link module:enyo/Option~Option}.
- *
+ *
* @type {Object}
* @default null
* @public
@@ -86,7 +85,7 @@ module.exports = kind(
/**
* The size of the select box in rows.
- *
+ *
* @type {Number}
* @default 0
* @public
@@ -94,8 +93,8 @@ module.exports = kind(
size: 0,
/**
- * Sets whether the enyo.Select can select multiple options
- *
+ * Sets whether the enyo/Select can select multiple options
+ *
* @type {Boolean}
* @default false
* @public
@@ -103,15 +102,15 @@ module.exports = kind(
multiple: false,
/**
- * Sets whether the enyo.Select is disabled, or not
- *
+ * Sets whether the enyo/Select is disabled, or not
+ *
* @type {Boolean}
* @default false
* @public
*/
disabled: false
},
-
+
/**
* @private
*/
@@ -136,10 +135,6 @@ module.exports = kind(
rendered: kind.inherit(function (sup) {
return function () {
sup.apply(this, arguments);
- //Trick to force IE8 onchange event bubble
- if (platform.ie == 8) {
- this.setAttribute('onchange', dispatcher.bubbler);
- }
// This makes Select.selected a higher priority than Option.selected but ensures that
// the former works at create time
if (this.selected !== null) {
@@ -168,6 +163,25 @@ module.exports = kind(
this.set('value', this.getNodeProperty('value', this.value));
},
+ /**
+ * Updates the `selected` option matching the current value. If the option doesn't have a value,
+ * it will match its content instead.
+ *
+ * @private
+ */
+ selectOptionByValue: function () {
+ var i, controls, l, c;
+
+ for (i = 0, controls = this.getControls(), l = controls.length; i < l; i++) {
+ c = controls[i];
+ // support
+ if (c.value ? c.value === this.value : c.content === this.value) {
+ if (i !== this.selected) this.set('selected', i);
+ break;
+ }
+ }
+ },
+
/**
* @private
*/
@@ -180,8 +194,15 @@ module.exports = kind(
* @private
*/
valueChanged: function () {
- this.setNodeProperty('value', this.value);
- this.updateSelectedFromNode();
+ // IE will clear selectedIndex when setting the value directly on the node so instead we
+ // iterate the children, find the matching value, and update selected if necessary.
+ if (platform.ie || platform.edge) {
+ this.selectOptionByValue();
+ }
+ else {
+ this.setNodeProperty('value', this.value);
+ this.updateSelectedFromNode();
+ }
},
/**
diff --git a/src/Selection.js b/src/Selection.js
index 0f3dfbf86..b588190c8 100644
--- a/src/Selection.js
+++ b/src/Selection.js
@@ -15,7 +15,7 @@ var
* when the [onSelect]{@link module:enyo/Selection~Selection#onSelect} and
* [onDeselect]{@link module:enyo/Selection~Selection#onDeselect} events are fired.
*
-* @typedef {Object} enyo.Selection~SelectionEvent
+* @typedef {Object} module:enyo/Selection~Selection~SelectionEvent
* @property {Number|String} key The key that was used to register the
* [selection]{@link module:enyo/Selection~Selection} (usually a row index).
* @property {Object} data - References data registered with the key by the code
diff --git a/src/ShowingTransitionSupport.js b/src/ShowingTransitionSupport.js
new file mode 100644
index 000000000..a72077972
--- /dev/null
+++ b/src/ShowingTransitionSupport.js
@@ -0,0 +1,244 @@
+/**
+* This module exports the {@link module:enyo/ShowingTransitionSupport~ShowingTransitionSupport} mixin.
+*
+* @wip
+* @module enyo/ShowingTransitionSupport
+*/
+
+var kind = require('enyo/kind'),
+ utils = require('enyo/utils');
+
+/**
+* The {@link module:enyo/ShowingTransitionSupport~ShowingTransitionSupport} [mixin]{@glossary mixin}
+* is applicable to any control that should use a transition or animation when it is shown or hidden.
+* This mixin adds optional state-classes to the component at its resting or transitioning states.
+* The states are as follows:
+*
+* * 'shown' and 'hidden' - resting, static, not-transitioning, past tense states.
+* * 'showing' and 'hiding' - transitioning-to, progressive tense states.
+*
+* A CSS class may be optionally supplied and applied to the component during that state. It will be
+* removed immediately when the component is no longer in that state. The 'hidden', 'hiding', and
+* 'showing' CSS classes are already defined as defaults, to account for the most common use case.
+* The same classes are allowed to be used on multiple states.
+*
+* It may be desirable to have a transition on only one of the showing or hiding states; this is
+* also possible.
+*
+* Transitions take time, so be sure to include a `hidingDuration` and/or `showingDuration`. You may
+* take advantage of this [mixin]{@glossary mixin}'s state classes without using transitions by
+* leaving the duration properties blank (0, null or undefined) and the resting states will simply be
+* applied immediately, skipping the transition state classes.
+*
+* An optional method may be supplied to fire at the end of either of the transitions, using
+* `hidingMethod` and/or `showingMethod`.
+*
+* @mixin
+* @wip
+* @public
+*/
+var ShowingTransitionSupport = {
+
+ /**
+ * @ignore
+ * @readonly
+ * @private
+ */
+ name: 'ShowingTransitionSupport',
+
+ /**
+ * A read-only property for checking whether we are in the middle of a transition.
+ *
+ * @type {Boolean}
+ * @default false
+ * @readonly
+ * @public
+ */
+ showingTransitioning: false,
+
+ /**
+ * The amount of time the "showing" transition takes to complete in milliseconds.
+ *
+ * @type {Number}
+ * @default undefined
+ * @public
+ */
+ showingDuration: undefined,
+
+ /**
+ * The amount of time the "hiding" transition takes to complete in milliseconds.
+ *
+ * @type {Number}
+ * @default undefined
+ * @public
+ */
+ hidingDuration: undefined,
+
+ /**
+ * The method to fire at the end of the "showing" transition. This may be name of a method on the
+ * component, or a function.
+ *
+ * @type {String|Function}
+ * @default undefined
+ * @public
+ */
+ shownMethod: undefined,
+
+ /**
+ * The method to fire at the end of the "hiding" transition. This may be name of a method on the
+ * component, or a function.
+ *
+ * @type {String|Function}
+ * @default undefined
+ * @public
+ */
+ hiddenMethod: undefined,
+
+ /**
+ * The classname to apply for the "shown" (component is visible) resting state.
+ *
+ * @type {String}
+ * @default undefined
+ * @public
+ */
+ shownClass: undefined,
+
+ /**
+ * The classname to apply for the "hidden" (component is not visible) resting state.
+ *
+ * @type {String}
+ * @default 'hidden'
+ * @public
+ */
+ hiddenClass: undefined,
+
+ /**
+ * The classname to apply for the "hiding" (component has started the transition to the hidden
+ * state) transition state.
+ *
+ * @type {String}
+ * @default 'hiding'
+ * @public
+ */
+ hidingClass: undefined,
+
+ /**
+ * The classname to apply for the "showing" (component has started the transition to the shown
+ * state) transition state.
+ *
+ * @type {String}
+ * @default 'showing'
+ * @public
+ */
+ showingClass: undefined,
+
+ /**
+ * Initializes the defaults, and prepares the component with its classes in case of initially
+ * "showing: false".
+ *
+ * @method
+ * @private
+ */
+ create: kind.inherit(function (sup) {
+ return function () {
+ sup.apply(this, arguments);
+
+ this.showingDuration = (this.showingDuration === undefined) ? null : this.showingDuration;
+ this.hidingDuration = (this.hidingDuration === undefined) ? null : this.hidingDuration;
+ this.shownMethod = (this.shownMethod === undefined) ? null : this.shownMethod;
+ this.hiddenMethod = (this.hiddenMethod === undefined) ? null : this.hiddenMethod;
+ this.shownClass = (this.shownClass === undefined) ? 'shown' : this.shownClass;
+ this.hiddenClass = (this.hiddenClass === undefined) ? 'hidden' : this.hiddenClass;
+ this.hidingClass = (this.hidingClass === undefined) ? 'hiding' : this.hidingClass;
+ this.showingClass = (this.showingClass === undefined) ? 'showing' : this.showingClass;
+ if (this.shownMethod) this.shownMethodChanged();
+ if (this.hiddenMethod) this.hiddenMethodChanged();
+ this.showingChanged();
+ };
+ }),
+
+ /**
+ * Overrides the showingChanged handler to add support for transitions at the right times and
+ * places.
+ *
+ * @method
+ * @private
+ */
+ showingChanged: kind.inherit(function (sup) {
+ return function (sender, ev) {
+ var args = arguments;
+
+ // Prepare our visual state
+ this.applyStyle('display', null);
+ this.applyStyle('visibility', null);
+ if (this.showing) {
+ // Reset our state classes, in case we switched mid-stream
+ this.removeClass(this.hidingClass);
+ this.removeClass(this.hiddenClass);
+ sup.apply(this, args);
+ if (this.showingDuration && this.hasNode()) {
+ this.set('showingTransitioning', true);
+ // Start transition: Apply a class and start a timer.
+ // When timer finishes, run the exit function,
+ // remove the transitioning class
+ // and add the final-state class
+ this.addClass(this.showingClass);
+ this.startJob('showingTransition', function () {
+ this.removeClass(this.showingClass);
+ this.addClass(this.shownClass);
+ this.set('showingTransitioning', false);
+ utils.call(this._shownMethodScope, this.shownMethod); // Run the supplied method.
+ }, this.showingDuration);
+ } else {
+ // No transition, just a shown class.
+ this.stopJob('showingTransition');
+ this.addClass(this.shownClass);
+ utils.call(this._shownMethodScope, this.shownMethod); // Run the supplied method.
+ }
+ } else {
+ // Reset our state classes, in case we switched mid-stream
+ this.removeClass(this.showingClass);
+ this.removeClass(this.shownClass);
+ if (this.hidingDuration && this.hasNode()) {
+ this.set('showingTransitioning', true);
+ this.addClass(this.hidingClass);
+ this.startJob('showingTransition', function () {
+ this.removeClass(this.hidingClass);
+ this.addClass(this.hiddenClass);
+ this.set('showingTransitioning', false);
+ sup.apply(this, args);
+ utils.call(this._hiddenMethodScope, this.hiddenMethod); // Run the supplied method.
+ this.applyStyle('visibility', 'hidden');
+ this.applyStyle('display', null);
+ }, this.hidingDuration);
+ } else {
+ // No transition, just a hidden class.
+ this.stopJob('showingTransition');
+ this.addClass(this.hiddenClass);
+ sup.apply(this, args);
+ utils.call(this._hiddenMethodScope, this.hiddenMethod); // Run the supplied method.
+ this.applyStyle('visibility', 'hidden');
+ this.applyStyle('display', null);
+ }
+ }
+ };
+ }),
+ showingDurationChanged: function () {
+ if (!this.showingDuration) this.stopJob('showingTransition');
+ },
+ hidingDurationChanged: function () {
+ if (!this.hidingDuration) this.stopJob('showingTransition');
+ },
+ shownMethodChanged: function () {
+ // checking if the actual method exists to workaround hasOwnProperty issues due to the
+ // mechanism we use for assigning mixin defaults
+ this._shownMethodScope = this[this.shownMethod] ? this : this.getInstanceOwner();
+ },
+ hiddenMethodChanged: function () {
+ // checking if the actual method exists to workaround hasOwnProperty issues due to the
+ // mechanism we use for assigning mixin defaults
+ this._hiddenMethodScope = this[this.hiddenMethod] ? this : this.getInstanceOwner();
+ }
+};
+
+module.exports = ShowingTransitionSupport;
diff --git a/src/SlideViewLayout/SlideViewLayout.js b/src/SlideViewLayout/SlideViewLayout.js
new file mode 100644
index 000000000..6e9d21e12
--- /dev/null
+++ b/src/SlideViewLayout/SlideViewLayout.js
@@ -0,0 +1,176 @@
+/**
+* Exports the {@link module:enyo/SlideViewLayout~SlideViewLayout} kind.
+*
+* @module enyo/SlideViewLayout
+* @wip
+*/
+
+var
+ dom = require('enyo/dom'),
+ kind = require('enyo/kind');
+
+var
+ TransitionViewLayout = require('../TransitionViewLayout');
+
+/**
+* Slides views in from the right or top and out the left or bottom.
+*
+* Order of operations:
+* * `prepareTransition()`
+* Applies directional CSS classes (forward or back) to each view based on the animation
+* direction. For the becoming-active view, this positions it offscreen. For the becoming-inactive
+* view, the directional class is overridden by `active` which keeps it onscreen. Calculates the
+* `dragDuration` used as the transition duration when the drag is released.
+* * `transition()`
+* Sets the transition duration to either its `duration` or a lesser amount to complete the
+* animation if the transition happens as a result of a drag operation. If a transform was applied
+* during a drag, it is removed. The result is a transition from the currently dragged position
+* set by inline style to the final position set by the CSS classes.
+* * `completeTransition()`
+* Removes the directional classes and resets the `dragDuration`
+*
+* @class SlideViewLayout
+* @extends module:enyo/TransitionViewLayout~TransitionViewLayout
+* @wip
+* @public
+*/
+module.exports = kind(
+ /** @lends module:enyo/SlideViewLayout~SlideViewLayout.prototype */ {
+ /**
+ * @private
+ */
+ kind: TransitionViewLayout,
+
+ /**
+ * @private
+ */
+ layoutClass: 'enyo-viewlayout enyo-viewlayout-slide',
+
+ /**
+ * @private
+ */
+ constructor: function () {
+ TransitionViewLayout.prototype._constructor.apply(this, arguments);
+ if (this.container.layoutCover) this.container.addClass('cover');
+ },
+
+ /**
+ * @private
+ */
+ addRemoveDirection: function (view, addRemove, invert) {
+ var direction = invert ? -this.container.direction : this.container.direction,
+ className = direction == 1 ? 'forward' : 'back';
+ view.addRemoveClass(className, addRemove);
+ },
+
+ /**
+ * @private
+ */
+ transform: function (view, px) {
+ var v,
+ isHorizontal = this.container.orientation == 'horizontal';
+
+ if (px === null) {
+ v = null;
+ } else {
+ v = isHorizontal ? px + 'px, 0, 0' : '0, ' + px + 'px, 0';
+ }
+ dom.transformValue(view, 'translate3d', v);
+ },
+
+ /**
+ * @private
+ */
+ drag: function (event) {
+ var px,
+ c = this.container,
+ bounds = c.dragBounds,
+ isHorizontal = c.orientation == 'horizontal',
+ size = isHorizontal ? bounds.width : bounds.height,
+ delta = event.delta;
+
+ if (event.delta < 0 && event.delta < -size) {
+ this.overDrag = true;
+ delta = -size;
+ }
+ else if (event.delta > 0 && event.delta > size) {
+ this.overDrag = true;
+ delta = size;
+ }
+ else {
+ this.overDrag = false;
+ }
+
+ TransitionViewLayout.prototype.drag.apply(this, arguments);
+ this.transform(c.active, delta);
+ if (c.dragView) {
+ px = this.container.layoutCover ? 0 : size * event.direction + delta;
+ this.transform(c.dragView, px);
+ }
+ },
+
+ /**
+ * Applies directional CSS classes to initially position the views.
+ *
+ * @private
+ */
+ prepareTransition: function (was, is) {
+ var c = this.container;
+ TransitionViewLayout.prototype.prepareTransition.apply(this, arguments);
+ if (is) this.addRemoveDirection(is, true);
+ if (was) this.addRemoveDirection(was, true, true);
+
+ if (this.container.layoutCover) {
+ this.stationaryView = c.direction == 1 && was
+ || c.direction == -1 && is;
+ if (this.stationaryView) this.stationaryView.addClass('stationary');
+ }
+ },
+
+ /**
+ * Sets the transition duration,
+ *
+ * @private
+ */
+ transition: function (was, is) {
+ var dir;
+
+ TransitionViewLayout.prototype.transition.apply(this, arguments);
+ if (was && was != this.dragView) {
+ this.transform(was, null);
+ }
+ if (is) {
+ this.addRemoveDirection(is, false);
+ if (is != this.dragView) this.transform(is, null);
+ }
+
+ // If the user drags the entire view off screen, it won't animate so we won't see the CSS
+ // transition event.
+ if (this.overDrag) {
+ if (was) this.setTransitionComplete('from');
+ if (is) this.setTransitionComplete('to');
+ }
+ // when using layoutCover, one view doesn't transition so the ontransitionend doesn't fire
+ // to account for that, set a timeout of the same duration to manually clean up. The
+ // exception being when dismissing the ViewManager and there is no becoming-active view.
+ else if (this.stationaryView) {
+ dir = this.getTransitionDirection(this.stationaryView);
+ if (dir) this.setTransitionComplete(dir);
+ }
+ },
+
+ /**
+ * Removes the directional CSS class from the deactivating panel
+ *
+ * @private
+ */
+ completeTransition: function (was, is) {
+ if (is) this.addRemoveDirection(is, false);
+ if (was) this.addRemoveDirection(was, false, true);
+ if (this.stationaryView) {
+ this.stationaryView.removeClass('stationary');
+ this.stationaryView = null;
+ }
+ TransitionViewLayout.prototype.completeTransition.apply(this, arguments);
+ }
+});
diff --git a/src/SlideViewLayout/SlideViewLayout.less b/src/SlideViewLayout/SlideViewLayout.less
new file mode 100644
index 000000000..70fc689c4
--- /dev/null
+++ b/src/SlideViewLayout/SlideViewLayout.less
@@ -0,0 +1,48 @@
+.enyo-viewlayout-slide {
+ .pre(@prop, @val) {
+ -webkit-@{prop}: @val;
+ @{prop}: @val;
+ }
+ > .enyo-view {
+ .pre(transform, translate3d(-100%, 0, 0));
+ .pre(transition-property, none);
+ .pre(transition-timing-function, linear);
+ }
+
+ &:not(.dragging) > .enyo-view.transitioning {
+ -webkit-transition-property: -webkit-transform;
+ transition-property: transform;
+ }
+
+ &.horizontal > .enyo-view {
+ &.forward { .pre(transform, translate3d(100%, 0, 0)); }
+ &.back { .pre(transform, translate3d(-100%, 0, 0)); }
+ &.active { .pre(transform, translate3d(0, 0, 0)); }
+ }
+
+ &.vertical > .enyo-view {
+ &.forward { .pre(transform, translateY(0, -100%, 0)); }
+ &.back { .pre(transform, translateY(0, 100%, 0)); }
+ &.active { .pre(transform, translate3d(0, 0, 0)); }
+ }
+
+ &.cover {
+ // in cover mode, promote all views up a bit
+ > .enyo-view {
+ z-index: 5;
+ // unless it's the stationary view which should always remain behind
+ &.stationary {
+ z-index: 0;
+ .pre(transform, translate3d(0, 0, 0));
+ }
+ }
+
+ // except when dragging where the active view is promoted
+ &.dragging {
+ > .enyo-view {
+ z-index: 0;
+ &.active { z-index: 10; }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/SlideViewLayout/package.json b/src/SlideViewLayout/package.json
new file mode 100644
index 000000000..45206a06e
--- /dev/null
+++ b/src/SlideViewLayout/package.json
@@ -0,0 +1,6 @@
+{
+ "main": "SlideViewLayout.js",
+ "styles": [
+ "SlideViewLayout.less"
+ ]
+}
\ No newline at end of file
diff --git a/src/Source.js b/src/Source.js
index a01798084..1f41c1b56 100644
--- a/src/Source.js
+++ b/src/Source.js
@@ -10,13 +10,6 @@ var
utils = require('./utils'),
logger = require('./logger');
-/**
-* All of the known, instanced [sources]{@link module:enyo/Source~Source}, by name.
-*
-* @name enyo~sources
-* @type {Object}
-* @readonly
-*/
var sources = {};
/**
@@ -29,19 +22,19 @@ var sources = {};
*/
var Source = module.exports = kind(
/** @lends module:enyo/Source~Source.prototype */ {
-
+
name: 'enyo.Source',
-
+
/**
* @private
*/
kind: null,
-
+
/**
* @private
*/
-
+
/**
* When initialized, the source should be passed properties to set on itself.
* These properties should include the name by which it will be referenced in
@@ -53,11 +46,11 @@ var Source = module.exports = kind(
constructor: function (props) {
if (props) this.importProps(props);
// automatic coersion of name removing prefix
- this.name || (this.name = this.kindName.replace(/^(.*)\./, ""));
+ this.name || (this.name = this.kindName.replace(/^(.*)\./, ''));
// now add to the global registry of sources
sources[this.name] = this;
},
-
+
/**
* Overload this method to handle retrieval of data. This method should accept an options
* [hash]{@glossary Object} with additional configuration properties, including `success`
@@ -72,7 +65,7 @@ var Source = module.exports = kind(
fetch: function (model, opts) {
//
},
-
+
/**
* Overload this method to handle persisting of data. This method should accept an options
* [hash]{@glossary Object} with additional configuration properties, including `success`
@@ -87,12 +80,12 @@ var Source = module.exports = kind(
commit: function (model, opts) {
//
},
-
+
/**
* Overload this method to handle deletion of data. This method should accept an options
* [hash]{@glossary Object} with additional configuration properties, including `success`
* and `error` callbacks to handle the result. If called without parameters, it will
- * instead destroy itself and be removed from [enyo.sources]{@link enyo~sources}, rendering
+ * instead destroy itself and be removed from [sources]{@link module:enyo/Source~Source.sources}, rendering
* itself unavailable for further operations.
*
* @param {(module:enyo/Model~Model|module:enyo/Collection~Collection)} model The [model]{@link module:enyo/Model~Model} or
@@ -101,7 +94,7 @@ var Source = module.exports = kind(
* `success` and `error` callbacks.
*/
destroy: function (model, opts) {
-
+
// if called with no parameters we actually just breakdown the source and remove
// it as being available
if (!arguments.length) {
@@ -109,7 +102,7 @@ var Source = module.exports = kind(
this.name = null;
}
},
-
+
/**
* Overload this method to handle querying of data based on the passed-in constructor. This
* method should accept an options [hash]{@glossary Object} with additional configuration
@@ -124,21 +117,21 @@ var Source = module.exports = kind(
find: function (ctor, opts) {
//
},
-
+
/**
* @private
*/
importProps: function (props) {
props && utils.mixin(this, props);
},
-
+
/**
* @see module:enyo/utils#getPath
* @method
* @public
*/
get: utils.getPath,
-
+
/**
* @see module:enyo/utils#setPath
* @method
@@ -152,11 +145,11 @@ var Source = module.exports = kind(
* properties should include a `kind` property with the name of the
* [kind]{@glossary kind} of source and a `name` for the instance. This static
* method is also available on all [subkinds]{@glossary subkind} of
-* `enyo.Source`. The instance will automatically be added to the
-* [enyo.sources]{@link enyo~sources} [object]{@glossary Object} and may be
+* `enyo/Source`. The instance will automatically be added to the
+* [sources]{@link module:enyo/Source~Source.sources} [object]{@glossary Object} and may be
* referenced by its `name`.
*
-* @name enyo.Source.create
+* @name module:enyo/Source~Source.create
* @static
* @method
* @param {Object} props - The properties to pass to the constructor for the requested
@@ -166,110 +159,131 @@ var Source = module.exports = kind(
*/
Source.create = function (props) {
var Ctor = (props && props.kind) || this;
-
+
if (typeof Ctor == 'string') Ctor = kind.constructorForKind(Ctor);
-
+
return new Ctor(props);
};
/**
+* @name module:enyo/Source~Source.concat
* @static
+* @method
* @private
*/
Source.concat = function (ctor, props) {
-
+
// force noDefer so that we can actually set this method on the constructor
if (props) props.noDefer = true;
-
+
ctor.create = Source.create;
};
/**
+* @name module:enyo/Source~Source.execute
* @static
+* @method
* @private
*/
Source.execute = function (action, model, opts) {
var source = opts.source || model.source,
-
+
// we need to be able to bind the success and error callbacks for each of the
// sources we'll be using
options = utils.clone(opts, true),
nom = source,
- msg;
-
+ msg,
+ ret;
+
if (source) {
-
+
// if explicitly set to true then we need to use all available sources in the
// application
if (source === true) {
-
+
for (nom in sources) {
source = sources[nom];
if (source[action]) {
-
+
// bind the source name to the success and error callbacks
options.success = opts.success.bind(null, nom);
options.error = opts.error.bind(null, nom);
-
- source[action](model, options);
+
+ ret = source[action](model, options);
}
}
}
-
+
// if it is an array of specific sources to use we, well, will only use those!
else if (source instanceof Array) {
- source.forEach(function (nom) {
- var src = typeof nom == 'string' ? sources[nom] : nom;
-
+ var i,
+ src;
+
+ ret = [];
+
+ for (i = 0; i < source.length; i++) {
+ nom = source[i];
+ src = typeof nom == 'string' ? sources[nom] : nom;
+
if (src && src[action]) {
// bind the source name to the success and error callbacks
options.success = opts.success.bind(null, src.name);
options.error = opts.error.bind(null, src.name);
-
- src[action](model, options);
+
+ ret.push(src[action](model, options));
}
- });
+ }
}
-
+
// if it is an instance of a source
else if (source instanceof Source && source[action]) {
-
+
// bind the source name to the success and error callbacks
options.success = opts.success.bind(null, source.name);
options.error = opts.error.bind(null, source.name);
-
- source[action](model, options);
+
+ ret = source[action](model, options);
}
-
+
// otherwise only one was specified and we attempt to use that
else if ((source = sources[nom]) && source[action]) {
-
+
// bind the source name to the success and error callbacks
options.success = opts.success.bind(null, nom);
options.error = opts.error.bind(null, nom);
-
- source[action](model, options);
+
+ ret = source[action](model, options);
}
-
+
// we could not resolve the requested source
else {
msg = 'enyo.Source.execute(): requested source(s) could not be found for ' +
model.kindName + '.' + action + '()';
-
+
logger.warn(msg);
-
+
// we need to fail the attempt and let it be handled
opts.error(nom ? typeof nom == 'string' ? nom : nom.name : 'UNKNOWN', msg);
}
} else {
msg = 'enyo.Source.execute(): no source(s) provided for ' + model.kindName + '.' +
action + '()';
-
+
logger.warn(msg);
-
+
// we need to fail the attempt and let it be handled
opts.error(nom ? typeof nom == 'string' ? nom : nom.name : 'UNKNOWN', msg);
}
+
+ return ret;
};
+/**
+* All of the known, instanced [sources]{@link module:enyo/Source~Source}, by name.
+* @name module:enyo/Source~Source.sources
+* @type {Object}
+* @public
+* @readonly
+*/
Source.sources = sources;
+
diff --git a/src/SpriteAnimation/SpriteAnimation.js b/src/SpriteAnimation/SpriteAnimation.js
index 82fea364d..e23bb70a0 100644
--- a/src/SpriteAnimation/SpriteAnimation.js
+++ b/src/SpriteAnimation/SpriteAnimation.js
@@ -295,7 +295,7 @@ module.exports = kind(
*/
updateKeyframes: function () {
if (this.useCssAnimation) {
- this.$.spriteImage.set('stylesheetContent', this._generateKeyframes());
+ this.$.spriteImage.set('stylesheetContent', this._generateKeyframes('-webkit-') + this._generateKeyframes('-moz-') + this._generateKeyframes());
} else {
this._generatePositionList();
}
@@ -349,6 +349,7 @@ module.exports = kind(
start: function () {
if (this.useCssAnimation) {
this.$.spriteImage.applyStyle('-webkit-animation-name', this.get('animationName'));
+ this.$.spriteImage.applyStyle('-moz-animation-name', this.get('animationName'));
this.$.spriteImage.applyStyle('animation-name', this.get('animationName'));
} else {
this._intervalHandle = scope.setInterval(this.bindSafely(this._nextFrame, this), this.get('frameLength'));
@@ -363,6 +364,7 @@ module.exports = kind(
*/
stop: function () {
this.$.spriteImage.applyStyle('-webkit-animation-name', null);
+ this.$.spriteImage.applyStyle('-moz-animation-name', null);
this.$.spriteImage.applyStyle('animation-name', null);
scope.clearInterval(this._intervalHandle);
this._loopCount = 0;
@@ -373,6 +375,7 @@ module.exports = kind(
*/
stopAtEndChanged: function() {
this.$.spriteImage.applyStyle('-webkit-animation-fill-mode', this.get('stopAtEnd') ? 'forwards' : null);
+ this.$.spriteImage.applyStyle('-moz-animation-fill-mode', this.get('stopAtEnd') ? 'forwards' : null);
this.$.spriteImage.applyStyle('animation-fill-mode', this.get('stopAtEnd') ? 'forwards' : null);
},
@@ -409,6 +412,7 @@ module.exports = kind(
iterations = parseInt(this.get('iterationCount'), 10) || null; // strings like "infinite" will be converted to null
this.$.spriteImage.applyStyle('-webkit-transform', 'translate3d('+ x +'px, '+ y +'px, 0)');
+ this.$.spriteImage.applyStyle('-moz-transform', 'translate3d('+ x +'px, '+ y +'px, 0)');
this.$.spriteImage.applyStyle('transform', 'translate3d('+ x +'px, '+ y +'px, 0)');
if (fi + 1 >= this._positionList.length - 1) {
@@ -448,8 +452,10 @@ module.exports = kind(
iterations = (iterations && iterations !== 0) ? iterations : 'infinite';
this.$.spriteImage.applyStyle('-webkit-animation-timing-function', 'steps(' + steps + ', start)');
+ this.$.spriteImage.applyStyle('-moz-animation-timing-function', 'steps(' + steps + ', start)');
this.$.spriteImage.applyStyle('animation-timing-function', 'steps(' + steps + ', start)');
this.$.spriteImage.applyStyle('-webkit-animation-iteration-count', iterations);
+ this.$.spriteImage.applyStyle('-moz-animation-iteration-count', iterations);
this.$.spriteImage.applyStyle('animation-iteration-count', iterations);
this.durationChanged();
},
@@ -457,7 +463,8 @@ module.exports = kind(
/**
* @private
*/
- _generateKeyframes: function () {
+ _generateKeyframes: function (prefix) {
+ prefix = prefix || '';
var o,
width = this.get('width'),
height = this.get('height'),
@@ -467,7 +474,7 @@ module.exports = kind(
kfStr = '',
outer = (horiz ? rows : cols);
- kfStr += '@-webkit-keyframes '+ this.get('animationName') +' {\n';
+ kfStr += '@'+ prefix +'keyframes '+ this.get('animationName') +' {\n';
for (o = 0; o < outer; o++) {
kfStr += this._generateKeyframe(
// percent
@@ -475,7 +482,8 @@ module.exports = kind(
// startX
horiz ? width : (-width * o),
// startY
- horiz ? (-height * o) : height
+ horiz ? (-height * o) : height,
+ prefix
);
kfStr += this._generateKeyframe(
// percent
@@ -483,7 +491,8 @@ module.exports = kind(
// endX
horiz ? ((-width * cols) + width) : (-width * o),
// endY
- horiz ? (-height * o) : ((-height * rows) + height)
+ horiz ? (-height * o) : ((-height * rows) + height),
+ prefix
);
}
kfStr += '}\n';
@@ -493,8 +502,15 @@ module.exports = kind(
/**
* @private
*/
- _generateKeyframe: function (percent, x, y) {
- return (Math.ceil(percent*1000000) / 10000) +'% { -webkit-transform: translate3d('+ x +'px, '+ y +'px, 0); transform: translate3d('+ x +'px, '+ y +'px, 0); }\n';
+ _generateKeyframe: function (percent, x, y, prefix) {
+ var outStr = (Math.ceil(percent*1000000) / 10000) +'% { ',
+ transform = 'transform: translate3d('+ x +'px, '+ y +'px, 0); ';
+ if (prefix) {
+ // add the prefix and the standard
+ outStr+= prefix + transform;
+ }
+ outStr+= transform +'}\n';
+ return outStr;
},
_generatePositionList: function () {
diff --git a/src/Store.js b/src/Store.js
index a0cd310a4..39ba89c36 100644
--- a/src/Store.js
+++ b/src/Store.js
@@ -30,7 +30,7 @@ var BaseStore = kind({
* should be included in the filtered set for the [find()]{@link module:enyo/Store~Store#find}
* method.
*
-* @callback enyo.Store~Filter
+* @callback module:enyo/Store~Store~Filter
* @param {module:enyo/Model~Model} model - The [model]{@link module:enyo/Model~Model} to filter.
* @returns {Boolean} `true` if the model meets the filter requirements;
* otherwise, `false`.
@@ -39,7 +39,7 @@ var BaseStore = kind({
/**
* The configuration options for the [find()]{@link module:enyo/Store~Store#find} method.
*
-* @typedef {Object} enyo.Store~FindOptions
+* @typedef {Object} module:enyo/Store~Store~FindOptions
* @property {Boolean} all=true - Whether or not to include more than one match for the
* filter method. If `true`, an array of matches is returned; otherwise, a single match.
* @property {Object} context - If provided, it will be used as the `this` (context) of
@@ -304,8 +304,7 @@ var Store = kind(
* @see module:enyo/Model~Model
* @see module:enyo/Collection~Collection
* @see module:enyo/RelationalModel~RelationalModel
-* @type enyo.Store
-* @memberof enyo
+* @type module:enyo/Store~Store
* @public
*/
module.exports = new Store();
diff --git a/src/StylesheetSupport.js b/src/StylesheetSupport.js
index 7370fe900..c25bb85a6 100644
--- a/src/StylesheetSupport.js
+++ b/src/StylesheetSupport.js
@@ -1,5 +1,5 @@
/**
-* Exports the {@link module:enyo/StylesheetSupport} mixin.
+* Exports the {@link module:enyo/StylesheetSupport~StylesheetSupport} mixin.
* @module enyo/StylesheetSupport
*/
@@ -12,7 +12,7 @@ var
Style = require('./Style');
/**
-* The {@link module:enyo/StylesheetSupport} {@glossary mixin} is used to add a
+* The {@link module:enyo/StylesheetSupport~StylesheetSupport} {@glossary mixin} is used to add a
* "side-car" inline stylesheet to a [control]{@link module:enyo/Control~Control}, specifically
* for procedurally-generated CSS that can't live in the more appropriate
* location (i.e., in a CSS/LESS file).
@@ -20,7 +20,7 @@ var
* @mixin
* @public
*/
-module.exports = {
+var StylesheetSupport = {
/**
* @private
@@ -101,3 +101,5 @@ module.exports = {
return this.getId() + this._stylesheet_id_suffix;
}
};
+
+module.exports = StylesheetSupport;
diff --git a/src/SystemMonitor.js b/src/SystemMonitor.js
index 7e5564f09..f3fb399e3 100644
--- a/src/SystemMonitor.js
+++ b/src/SystemMonitor.js
@@ -2,6 +2,7 @@ require('enyo');
/**
* Returns the SystemMonitor singleton
+* @wip
* @module enyo/SystemMonitor
*/
diff --git a/src/Table/Table.js b/src/Table/Table.js
index 5770be3ff..847f457e7 100644
--- a/src/Table/Table.js
+++ b/src/Table/Table.js
@@ -12,10 +12,7 @@ var
TableRow = require('../TableRow');
/*
-* TODO: Won't work in IE8 because we can't set innerHTML on table elements. We'll need to fall
-* back to divs with table display styles applied.
-*
-* Should also facade certain useful table functionality (specific set TBD).
+* TODO: Should facade certain useful table functionality (specific set TBD).
*/
/**
diff --git a/src/TaskManagerSupport.js b/src/TaskManagerSupport.js
index f7c8516db..38fd7f3ff 100644
--- a/src/TaskManagerSupport.js
+++ b/src/TaskManagerSupport.js
@@ -1,5 +1,6 @@
/**
* Exports the {@link module:enyo/TaskManagerSupport~TaskManagerSupport} mixin
+* @wip
* @module enyo/TaskManagerSupport
*/
@@ -14,7 +15,10 @@ var
Priorities = PriorityQueue.Priorities,
BackgroundTaskManager = require('./BackgroundTaskManager');
-/** @mixin */
+/**
+* @mixin
+* @wip
+*/
var TaskManagerSupport = {
/**
diff --git a/src/TransitionScrollStrategy.js b/src/TransitionScrollStrategy.js
index 0c05cc2a8..90a7b8e04 100644
--- a/src/TransitionScrollStrategy.js
+++ b/src/TransitionScrollStrategy.js
@@ -2,6 +2,7 @@ require('enyo');
/**
* Contains the declaration for the {@link module:enyo/TransitionScrollStrategy~TransitionScrollStrategy} kind.
+* @wip
* @module enyo/TransitionScrollStrategy
*/
@@ -60,6 +61,7 @@ var
*
* @class TransitionScrollStrategy
* @extends module:enyo/TouchScrollStrategy~TouchScrollStrategy
+* @wip
* @protected
*/
var TransitionScrollStrategy = module.exports = kind(
diff --git a/src/TransitionViewLayout.js b/src/TransitionViewLayout.js
new file mode 100644
index 000000000..ee6956cc2
--- /dev/null
+++ b/src/TransitionViewLayout.js
@@ -0,0 +1,124 @@
+/**
+* @module enyo/TransitionViewLayout
+* @wip
+*/
+
+var
+ kind = require('enyo/kind');
+
+var
+ ViewLayout = require('./ViewLayout');
+
+
+/**
+* Slides views in from the right or top and out the left or bottom.
+*
+* Order of operations:
+* * `prepareTransition()`
+* Applies directional CSS classes (forward or back) to each view based on the animation
+* direction. For the becoming-active view, this positions it offscreen. For the becoming-inactive
+* view, the directional class is overridden by `active` which keeps it onscreen. Calculates the
+* `dragDuration` used as the transition duration when the drag is released.
+* * `transition()`
+* Sets the transition duration to either its `duration` or a lesser amount to complete the
+* animation if the transition happens as a result of a drag operation. If a transform was applied
+* during a drag, it is removed. The result is a transition from the currently dragged position
+* set by inline style to the final position set by the CSS classes.
+* * `completeTransition()`
+* Removes the directional classes and resets the `dragDuration`
+*
+* @class TransitionViewLayout
+* @extends module:enyo/ViewLayout~ViewLayout
+* @public
+* @wip
+*/
+module.exports = kind(
+ /** @lends module:enyo/TransitionViewLayout~TransitionViewLayout.prototype */ {
+ /**
+ * @private
+ */
+ kind: ViewLayout,
+
+ /**
+ * Sets the duration of the transition. Imported from the value of `layoutDuration` on the
+ * container on which the layout is applied.
+ *
+ * @type {Number}
+ * @default 300
+ * @public
+ */
+ duration: 300,
+
+ /**
+ * @private
+ */
+ constructor: function () {
+ ViewLayout.prototype._constructor.apply(this, arguments);
+ this.duration = this.container.layoutDuration || this.duration;
+ },
+
+ /**
+ * @private
+ */
+ drag: function (event) {
+ ViewLayout.prototype.drag.apply(this, arguments);
+ this.dragDuration = this.duration - Math.round(event.percentDelta * this.duration, 2);
+ },
+
+ /**
+ * Sets the transition duration,
+ *
+ * @private
+ */
+ transition: function (was, is) {
+ ViewLayout.prototype.transition.apply(this, arguments);
+ if (was) {
+ was.addClass('transitioning');
+ this.applyTransitionDuration(was, this.dragDuration || this.duration);
+ }
+ if (is) {
+ is.addClass('transitioning');
+ this.applyTransitionDuration(is, this.dragDuration || this.duration);
+ }
+ },
+
+ /**
+ * Removes the directional CSS class from the deactivating view
+ *
+ * @private
+ */
+ completeTransition: function (was, is) {
+ if (was) was.removeClass('transitioning');
+ if (is) is.removeClass('transitioning');
+ this.dragDuration = null;
+ ViewLayout.prototype.completeTransition.apply(this, arguments);
+ },
+
+ /**
+ * @private
+ */
+ applyTransitionDuration: function (view, duration) {
+ view.applyStyle('-webkit-transition-duration', duration + 'ms');
+ view.applyStyle('transition-duration', duration + 'ms');
+ },
+
+ /**
+ * @private
+ */
+ handlers: {
+ ontransitionend: 'handleTransitioned'
+ },
+
+ /**
+ * @private
+ */
+ handleTransitioned: function (sender, event) {
+ var dir,
+ view = event.originator;
+ if (view && view.container == this.container) {
+ dir = this.getTransitionDirection(view);
+ if (dir) this.setTransitionComplete(dir);
+ return true;
+ }
+ }
+});
diff --git a/src/UiComponent.js b/src/UiComponent.js
index 29d9e2c03..807e7376c 100644
--- a/src/UiComponent.js
+++ b/src/UiComponent.js
@@ -13,6 +13,15 @@ var
var
Component = require('./Component');
+/**
+* The configurable options used by {@link module:enyo/UiComponent~UiComponent} when updating
+* components.
+*
+* @typedef {Object} enyo/UiComponent~UiComponent~UpdateComponentsOptions
+* @property {Boolean} [silent] - If `true`, component properties will be updated silently i.e. they
+* will be set directly, rather than via the generic `set` method.
+*/
+
/**
* {@link module:enyo/UiComponent~UiComponent} implements a container strategy suitable for presentation layers.
*
@@ -34,13 +43,15 @@ var UiComponent = module.exports = kind(
*/
kind: Component,
- statics: {
+ statics:
+ /** @lends module:enyo/UiComponent~UiComponent */ {
/**
- * The default set of keys which are effectively "ignored" when determining whether or not the
- * this control has changed in such a way that warrants a complete re-render. When
- * {@link enyo.UIComponent#updateComponents} is invoked on a parent component, this set of
- * stateful keys is utilized by default, if no stateful keys are provided by us.
+ * The default set of keys which are effectively "ignored" when determining whether or not
+ * the this control has changed in such a way that warrants a complete re-render. When
+ * {@link module:enyo/UiComponent~UiComponent#updateComponents} is invoked on a parent
+ * component, this set of stateful keys is utilized by default, if no stateful keys are
+ * provided by us.
*
* @type {String[]}
* @default ['content', active', 'disabled']
@@ -227,36 +238,43 @@ var UiComponent = module.exports = kind(
};
}),
- /**
+ /**
* An alternative component update path that attempts to intelligently update only the
* relevant portions of the component which have changed.
*
- * @param {Array} comps - An array of kind definitions to be set as the child components of
+ * @param {Object[]} props - An array of kind definitions to be set as the child components of
* this component.
+ * @param {Object} [ext] - Additional properties to be supplied as defaults for components, when
+ * being created or recreated. These properties have no bearing on the diff computation of the
+ * child components.
+ * @param {module:enyo/UiComponent~UpdateComponentsOptions} [opts] - Additional options for how
+ * the update operation should behave.
* @returns {Boolean} - Whether or not the component should be re-rendered.
+ * @wip
* @public
*/
- updateComponents: function (comps) {
+ updateComponents: function (props, ext, opts) {
var allStatefulKeys = {},
- isChanged = this.computeComponentsDiff(comps, allStatefulKeys),
- comp, controls, control, keys, key, idxKey, idxComp, kind;
+ isChanged = this.computeComponentsDiff(props, allStatefulKeys),
+ prop, controls, control, keys, key, idxKey, idxProp, kind;
if (isChanged) {
this.destroyClientControls();
- this.createComponents(comps);
+ this.createComponents(props, ext);
return true;
} else {
controls = this.getClientControls();
- for (idxComp = 0; idxComp < comps.length; idxComp++) {
- comp = comps[idxComp];
- control = controls[idxComp];
- kind = comp.kind || this.defaultKind;
- keys = allStatefulKeys[idxComp];
+ for (idxProp = 0; idxProp < props.length; idxProp++) {
+ prop = props[idxProp];
+ control = controls[idxProp];
+ kind = prop.kind || this.defaultKind;
+ keys = allStatefulKeys[idxProp];
for (idxKey = 0; idxKey < keys.length; idxKey++) { // for each key, determine if there is a change
key = keys[idxKey];
- if (comp[key] != control[key]) {
- control.set(key, comp[key]);
+ if (prop[key] != control[key]) {
+ if (opts && opts.silent) control[key] = prop[key];
+ else control.set(key, prop[key]);
}
}
}
@@ -690,7 +708,7 @@ var UiComponent = module.exports = kind(
);
}
},
-
+
/**
* @method
* @private
diff --git a/src/VerticalDelegate.js b/src/VerticalDelegate.js
index d50fd09ce..ace9b3cf1 100644
--- a/src/VerticalDelegate.js
+++ b/src/VerticalDelegate.js
@@ -194,6 +194,7 @@ module.exports = {
view = page.children[i];
view.teardownRender();
view.canGenerate = false;
+ view.set('model', null);
}
// update the entire page at once - this removes old nodes and updates
// to the correct ones
@@ -516,17 +517,12 @@ module.exports = {
* @private
*/
adjustBuffer: function (list) {
- var pc = this.pageCount(list),
- ds = this.defaultPageSize(list),
+ var cs = this.childSize(list),
+ count = list.collection ? list.collection.length : 0,
bs = 0, sp = list.psizeProp, ss = list.ssizeProp,
- n = list.$.buffer.node || list.$.buffer.hasNode(), p;
+ n = list.$.buffer.node || list.$.buffer.hasNode();
if (n) {
- if (pc !== 0) {
- for (var i=0; i .enyo-view, & > & {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ }
+}
\ No newline at end of file
diff --git a/src/ViewLayout/package.json b/src/ViewLayout/package.json
new file mode 100644
index 000000000..6927b4e0a
--- /dev/null
+++ b/src/ViewLayout/package.json
@@ -0,0 +1,6 @@
+{
+ "main": "ViewLayout.js",
+ "styles": [
+ "ViewLayout.less"
+ ]
+}
\ No newline at end of file
diff --git a/src/ViewManager/ScrimSupport.js b/src/ViewManager/ScrimSupport.js
new file mode 100644
index 000000000..7fe6946b4
--- /dev/null
+++ b/src/ViewManager/ScrimSupport.js
@@ -0,0 +1,39 @@
+var
+ kind = require('../kind'),
+ utils = require('enyo/utils');
+
+
+/**
+* A mixin for use by ViewManager. Applies a user-defined `scrimConfig` if present.
+*
+* @name module:enyo/ViewManager~ScrimSupport
+* @mixin
+* @wip
+* @protected
+*/
+var ScrimSupport = {
+ /**
+ * @private
+ */
+ initComponents: kind.inherit(function (sup) {
+ return function () {
+ var config = {name: 'scrim', classes: 'enyo-viewmanager-scrim enyo-fit'};
+ sup.apply(this, arguments);
+
+ // override defaults with user-provided scrimConfig
+ if (this.scrimConfig) utils.mixin(config, this.scrimConfig);
+ this.createComponent(config, {isChrome: true});
+
+ // monitor the relevant events to hide and show the scrim
+ // @todo - may need to monitor active manager counts
+ this.on('manager-manage', function (sender, name, event) {
+ this.$[config.name].addClass('showing');
+ }, this);
+ this.on('manager-dismiss', function (sender, name, event) {
+ this.$[config.name].removeClass('showing');
+ }, this);
+ };
+ })
+};
+
+module.exports = ScrimSupport;
diff --git a/src/ViewManager/ViewManager.js b/src/ViewManager/ViewManager.js
new file mode 100644
index 000000000..7ca276dfc
--- /dev/null
+++ b/src/ViewManager/ViewManager.js
@@ -0,0 +1,1153 @@
+/**
+* ViewManager module
+*
+* @module enyo/ViewManager
+* @wip
+*/
+
+/**
+* Fires after a view has been created and rendered, if necessary, but before it transitions into
+* viewport.
+*
+* @event module:enyo/ViewManager~ViewManager#activate
+* @property {module:enyo/Control~Control} view The target view for the event
+* @property {Boolean} dragging `true` for `activate` or `deactivate` events that occur as a result
+* of dragging
+* @property {Number} direction Either 1 representing forward or -1 representing backward
+* @public
+*/
+
+/**
+* Fires after a view has been created, rendered, and transitioned into the viewport.
+*
+* @event module:enyo/ViewManager~ViewManager#activated
+* @type {Object}
+* @property {module:enyo/Control~Control} view The target view for the event
+* @property {Boolean} dragging `true` for `activate` or `deactivate` events that occur as a result
+* of dragging
+* @property {Number} direction Either 1 representing forward or -1 representing backward
+* @public
+*/
+
+/**
+* Fires on the previously active view when a new view has become active but before it has
+* transitioned out of the viewport
+*
+* @event module:enyo/ViewManager~ViewManager#deactivate
+* @property {module:enyo/Control~Control} view The target view for the event
+* @property {Boolean} dragging `true` for `activate` or `deactivate` events that occur as a result
+* of dragging
+* @property {Number} direction Either 1 representing forward or -1 representing backward
+* @public
+*/
+
+/**
+* Fires on the previously active view when it has transitioned out of the viewport and been torn
+* down.
+*
+* @event module:enyo/ViewManager~ViewManager#deactivated
+* @property {module:enyo/Control~Control} view The target view for the event
+* @property {Boolean} dragging `true` for `activate` or `deactivate` events that occur as a result
+* of dragging
+* @property {Number} direction Either 1 representing forward or -1 representing backward
+* @public
+*/
+
+/**
+* Fires on the previously active view when it has transitioned out of the viewport and been torn
+* down.
+*
+* @event module:enyo/ViewManager~ViewManager#deactivated
+* @property {module:enyo/Control~Control} view The target view for the event
+* @property {Boolean} dragging `true` for `activate` or `deactivate` events that occur as a result
+* of dragging
+* @property {Number} direction Either 1 representing forward or -1 representing backward
+* @public
+*/
+
+/**
+* Fires when this ViewManager is [activated]{@link module:enyo/ViewManager~ViewManager#activate} by
+* its [manager]{@link module:enyo/ViewManager~ViewManager#manager} and ready to activate its own
+* views.
+*
+* @event module:enyo/ViewManager~ViewManager#manage
+* @public
+*/
+
+/**
+* Fires when this ViewManager dimissal is initiated -- either by a call to
+* [dismiss()]{@link module:enyo/ViewManager~ViewManager#dismiss} or when a
+* [dismissable]{@link module:enyo/ViewManager~ViewManager#dismissable} ViewManager is on its first
+* view and is dragged beyond the
+* [dragThreshold]{@link module:enyo/ViewManager~ViewManager#dragThreshold}.
+*
+* @event module:enyo/ViewManager~ViewManager#dismiss
+* @property {Boolean} dragging `true` for when dismissing as a result of dragging
+* @public
+*/
+
+/**
+* Fires when a ViewManager completes its dismissal.
+*
+* @event module:enyo/ViewManager~ViewManager#dismissed
+* @public
+*/
+
+var
+ animation = require('../animation'),
+ kind = require('../kind'),
+ utils = require('../utils'),
+ Control = require('../Control'),
+ EventEmitter = require('../EventEmitter'),
+ SlideViewLayout = require('../SlideViewLayout'),
+ rAF = animation.requestAnimationFrame;
+
+var
+ ScrimSupport = require('./ScrimSupport');
+
+var viewCount = 0;
+
+/**
+* ViewManager manages views.
+*
+* ```
+* module.exports = kind({
+* kind: ViewManager,
+* classes: 'contacts',
+*
+* // All the views are declared in the common components block
+* components: [
+* {name: 'history', components: [
+* {content: 'History'},
+* {kind: Button, content: 'Next', ontap: 'next'}
+* ]},
+* {name: 'dialer', active: true, components: [
+* {content: 'Dialer'},
+* {kind: Button, content: 'Inline Example', ontap: 'activateInline'},
+* {kind: Button, content: 'Previous', ontap: 'previous'},
+* {kind: Button, content: 'Next', ontap: 'next'}
+* ]},
+* {name: 'contacts', components: [
+* {content: 'Contacts'},
+* {kind: Button, content: 'Previous', ontap: 'previous'},
+* {kind: Button, content: 'Add A Contact', ontap: 'pushAddContactView'}
+* ]}
+* ],
+*
+* // Child ViewManagers are declared within a new managers block
+* managers: [
+* {name: 'add', kind: AddContact},
+* {name: 'inline', kind: ViewManager, floating: true, components: [
+* {content: 'view1', style: 'background: #424242; color: #fff;', ontap: 'nextInline'},
+* {content: 'view2', style: 'background: #424242; color: #fff;', ontap: 'nextInline'},
+* {content: 'view3', style: 'background: #424242; color: #fff;', ontap: 'dismissInline'}
+* ]}
+* ],
+*
+* create: function () {
+* ViewManager.prototype.create.apply(this, arguments);
+*
+* function log (sender, name, event) {
+* console.log('Event', name,
+* 'on view', event.view.name,
+* event.dragging ? 'while dragging' : '');
+* }
+*
+* // ViewManager emits events to ease view initialization and teardown without concern for the
+* // async nature of animations.
+*
+* // `view` has been activated but not animated
+* this.on('activate', log);
+*
+* // `view` has been activate and animated
+* this.on('activated', log);
+*
+* // `view` has been deactivated but not animated
+* this.on('deactivate', log);
+*
+* // `view` has been deactivated and animated
+* this.on('deactivated', log);
+* },
+*
+* // Activate and navigate the Inline ViewManager
+* activateInline: function () {
+* this.activate('inline');
+* },
+* nextInline: function () {
+* this.$.inline.next();
+* },
+* dismissInline: function () {
+* this.$.inline.dismiss();
+* },
+*
+* // Activate the Contacts ViewManager
+* pushAddContactView: function () {
+* var view = this.activate('add');
+* view.set('model', new Model({
+* first: 'First Name',
+* last: 'Last Name'
+* }));
+* }
+* });
+* ```
+*
+* @class ViewManager
+* @extends module:enyo/Control~Control
+* @ui
+* @public
+* @wip
+*/
+var ViewMgr = kind(
+ /** @lends module:enyo/ViewManager~ViewManager.prototype */ {
+
+ /**
+ * @private
+ */
+ kind: Control,
+
+ /**
+ * @private
+ */
+ layoutKind: SlideViewLayout,
+
+ /**
+ * @private
+ */
+ mixins: [EventEmitter],
+
+ /**
+ * @private
+ */
+ animate: true,
+
+ /**
+ * @private
+ */
+ classes: 'enyo-viewmanager',
+
+ // PUBLIC PROPERTIES
+
+ /**
+ * Determines if and how the default view is activated. The default view is either the first
+ * view with a truthy `active` member or the first view if none are marked active.
+ *
+ * * 'off' - No view is activated by default
+ * * 'create' - The default view is activated on create and not animated into position
+ * * 'render' - The default view is activated on render and animated into position
+ * * 'auto' - For floating ViewManagers, this is equivalent to 'render'. For non-floating
+ * ViewManagers, this is equivalent to 'create'.
+ *
+ * @type {String}
+ * @default auto
+ * @public
+ */
+ activateDefault: 'auto',
+
+ /**
+ * Determines if the view can be dismissed by dragging. The ViewManager can be programmatically
+ * dismissed via dismiss() regardless of the value of this property. If the ViewManager is the
+ * root and does not have a `manager`, it cannot be dismissed by dragging or by `dismiss()`.
+ *
+ * * `true` - Can be dismissed
+ * * `false` - Cannot be dismissed
+ * * 'auto' - Can be dismissed if `floating` is `true`
+ *
+ * @type {Boolean|String}
+ * @default auto
+ * @public
+ */
+ dismissable: 'auto',
+
+ /**
+ * When `true`, the views can be dragged or flicked into and out of view.
+ * When `false`, the views cannot be dragged or flicked.
+ * When `drag`, the views can *only* be dragged and not flicked.
+ * When `flick`, the views can *only* be flicked and not dragged.
+ *
+ * @type {Boolean|String}
+ * @default true
+ * @public
+ */
+ draggable: true,
+
+ /**
+ * Percent a new view must be dragged into the viewport to be activated on drag release
+ *
+ * @type {Number}
+ * @default 25
+ * @public
+ */
+ dragThreshold: 25,
+
+ /**
+ * If `true`, this ViewManager 'floats' over its parent `manager`
+ *
+ * @type {Boolean}
+ * @default false
+ * @public
+ */
+ floating: false,
+
+ /**
+ * If created within another ViewManager, `manager` will maintain a reference to that
+ * ViewManager which will be notified of activated, deactivated, dismiss, and dismissed events
+ * from this ViewManager.
+ *
+ * @type {module:enyo/ViewManager~ViewManager}
+ * @default null
+ * @public
+ */
+ manager: null,
+
+ /**
+ * @private
+ */
+ managerChanged: function (was, is) {
+ if (was) this.off('*', was.managerEvent);
+ if (is) this.on('*', is.managerEvent);
+ },
+
+ /**
+ * When `draggable`, this constrains the drag to this direction.
+ *
+ * @type {String}
+ * @default horizontal
+ * @public
+ */
+ orientation: 'horizontal',
+
+ /**
+ * The number of views managed by this ViewManager. This member is observable but should be
+ * considered read-only.
+ *
+ * @type {Number}
+ * @default 0
+ * @readOnly
+ * @public
+ */
+ viewCount: 0,
+
+ // PRIVATE PROPERTIES
+
+ /**
+ * Active view
+ *
+ * @type {module:enyo/Control~Control}
+ * @private
+ */
+ active: null,
+
+ /**
+ * @private
+ */
+ activeChanged: function (was, is) {
+ if (was) {
+ if (this.dragging) {
+ this.set('dragging', false);
+ this.releaseDraggedView = was.retainNode();
+ }
+ this.emitViewEvent('deactivate', was);
+ }
+ },
+
+ /**
+ * Indicates the logical direction of a view activation. May be used by ViewLayouts to inform the
+ * direction of their animation
+ *
+ * @type {Number}
+ * @default 0
+ * @private
+ */
+ direction: 0,
+
+ /**
+ * `true` when this ViewManager has been dismissed
+ *
+ * @type {Boolean}
+ * @default false
+ * @private
+ */
+ dismissed: false,
+
+ /**
+ * `true` when a drag gesture is in process
+ *
+ * @type {Boolean}
+ * @default false
+ * @private
+ */
+ dragging: false,
+
+ /**
+ * During a drag, contains a reference to the becoming-active view
+ *
+ * @private
+ */
+ dragView: null,
+
+ /**
+ * @type {Boolean}
+ */
+ flicked: false,
+
+ /**
+ * @private
+ */
+ layoutKindChanged: function (was, is) {
+ Control.prototype.layoutKindChanged.apply(this, arguments);
+ if (this.layout && this.layout.on) {
+ this.layout.on('complete', this.handleLayoutComplete, this);
+ }
+ },
+
+ /**
+ * @private
+ */
+ handlers: {
+ onflick: 'handleFlick',
+ ondown: 'handleDown',
+ ondragstart: 'handleDragStart',
+ ondrag: 'handleDrag',
+ ondragfinish: 'handleDragFinish'
+ },
+
+ /**
+ * @private
+ */
+ create: function () {
+ // Set layoutCover for floating ViewManagers that haven't explicitly defined it
+ if (this.floating && this.layoutCover === undefined) this.layoutCover = true;
+
+ this.on('*', this.notifyViews, this);
+ Control.prototype.create.apply(this, arguments);
+
+ // cache a bound reference to the managerEvent handler
+ this.managerEvent = this.managerEvent.bind(this);
+ this.managerChanged(null, this.manager);
+
+ if (this.floating) this.stack = [];
+
+ if (this.activateDefault == 'create' || (this.activateDefault == 'auto' && !this.floating)) {
+ this.initFirstView();
+ }
+ },
+
+ /**
+ * @private
+ */
+ rendered: function () {
+ Control.prototype.rendered.apply(this, arguments);
+ if (this.activateDefault == 'render' || (this.activateDefault == 'auto' && this.floating)) {
+ this.initFirstView();
+ }
+ this.set('dismissed', false);
+ },
+
+ /**
+ * @private
+ */
+ initComponents: function () {
+ var managersOwner = this.hasOwnProperty('managers') ? this.getInstanceOwner() : this;
+
+ // view configs or instances
+ this.views = [];
+ this.viewManagers = {};
+
+ // map of view name to index
+ this.viewNames = {};
+
+ // import kind and user components into this.views
+ this.importViewConfig(this.kindComponents, this);
+ this.importViewConfig(this.components, this.getInstanceOwner());
+ this.importViewConfig(this.managers, managersOwner, true);
+ this.viewCount = this.views.length;
+
+ // clean up references
+ this.components = this.kindComponents = null;
+ },
+
+ /**
+ * If a newly added control doesn't exist in the view or manager array, add it
+ *
+ * @private
+ */
+ addControl: function (control, before) {
+ var viewIndex = this.viewNames[control.name];
+ Control.prototype.addControl.apply(this, arguments);
+
+ if (!control.isChrome && !(viewIndex || viewIndex === 0) && !this.viewManagers[control.name]) {
+ this.addView(control);
+ this.set('viewCount', this.views.length);
+ }
+ },
+
+ /**
+ * @private
+ */
+ removeControl: function (control) {
+ var i, l,
+ index = this.views.indexOf(control);
+
+ Control.prototype.removeControl.apply(this, arguments);
+ if (index >= 0) {
+ this.views.splice(index, 1);
+ this.viewNames[control.name] = null;
+
+ for (i = index, l = this.views.length; i < l; i++) {
+ this.viewNames[this.views[i].name] = i;
+ }
+ this.set('viewCount', this.viewCount - 1);
+ }
+ },
+
+ /**
+ * Activates the initial view
+ *
+ * @private
+ */
+ initFirstView: function () {
+ var name, view,
+ i = 0;
+
+ if (this.views.length === 0) return;
+
+ // find the first declared defaultView
+ while ((view = this.views[i++]) && !name) {
+ if (view.defaultView) {
+ name = view.name;
+ }
+ }
+
+ name = name || this.views[0].name;
+ if (this.generated) {
+ this.activate(name);
+ } else {
+ view = this.getView(name);
+ this.activateImmediate(view);
+ }
+ },
+
+ /**
+ * Adds the list of components as views
+ *
+ * @param {Object[]|module:enyo/Control~Control[]} components List of components
+ * @param {module:enyo/Control~Control|null} [owner] Owner of components
+ *
+ * @private
+ */
+ importViewConfig: function (components, owner, isManager) {
+ var c,
+ i = 0;
+
+ while (components && (c = components[i++])) {
+ this.addView(c, owner, isManager);
+ }
+ },
+
+ /**
+ * Adds a new view to the view set
+ *
+ * @param {Object|module:enyo/Control~Control} view View config or instance
+ * @param {module:enyo/Control~Control|null} [owner] Optional owner of view. Defaults to this.
+ *
+ * @private
+ */
+ addView: function (view, owner, isManager) {
+ var index,
+ isControl = view instanceof Control,
+ _view = isControl ? view : utils.clone(view),
+ name = _view.name = _view.name || 'view' + (++viewCount);
+
+ owner = _view.owner || owner || this;
+ if (isControl) {
+ _view.set('owner', owner);
+ isManager = _view instanceof ViewMgr;
+ } else {
+ _view.owner = owner;
+ }
+
+ if (isManager) {
+ // setting directly because the change handler is called manually during create
+ _view.manager = this;
+ this.viewManagers[name] = _view;
+ } else {
+ index = this.views.push(_view),
+ this.viewNames[name] = index - 1;
+ }
+ },
+
+
+ /**
+ * Returns the index of the provided view. For fixed ViewManagers, this reflects the view's ordered
+ * position. For floating ViewManagers, this reflects the last occurence of the view in the stack. If
+ * the view isn't found, -1 is returned.
+ *
+ * @param {module:enyo/Control~Control} view
+ * @return {Number} Index of `view`
+ * @public
+ */
+ indexOf: function (view) {
+ var name = view && view.name;
+ if (!name) return -1;
+
+ return this.floating ? this.stack.lastIndexOf(name) : this.views.indexOf(view);
+ },
+
+ /**
+ * Returns the currently active view
+ *
+ * @return {module:enyo/Control~Control}
+ * @public
+ */
+ getActive: function () {
+ return this.active;
+ },
+
+ /**
+ * Retrieves and creates, if necessary, a view or view manager by name
+ *
+ * @param {String} viewName Name of the view or view manager
+ * @return {module:enyo/Control~Control} View
+ * @public
+ */
+ getView: function (viewName) {
+ var view = this.viewManagers[viewName],
+ index = this.viewNames[viewName];
+
+ // if it's a manager
+ if (view) {
+ // but not created, create it
+ if (!(view instanceof ViewMgr)) {
+ view = this.viewManagers[viewName] = this.createComponent(view);
+ }
+ }
+ // otherwise, it's probably a view
+ else {
+ view = this.views[index];
+ // but it might need to be created too
+ if (view && !(view instanceof Control)) {
+ view = this.views[index] = this.createComponent(view);
+ view.addClass('enyo-view');
+ }
+ }
+
+ return view;
+ },
+
+ /**
+ * Navigates to the next view based on order of definition or creation
+ *
+ * @param {Object} [opts] Optional parameters to configure the activation
+ * @return {module:enyo/Control~Control} Activated view
+ * @public
+ */
+ next: function (opts) {
+ var index = this.views.indexOf(this.active) + 1,
+ view = this.views[index];
+ if (view) {
+ this.direction = 1;
+ return this.activate(view.name, opts);
+ }
+ },
+
+ /**
+ * Navigates to the previous view based on order of definition or creation
+ *
+ * @param {Object} [opts] Optional parameters to configure the activation
+ * @return {module:enyo/Control~Control} Activated view
+ * @public
+ */
+ previous: function (opts) {
+ var index = this.views.indexOf(this.active) - 1,
+ view = this.views[index];
+ if (view) {
+ this.direction = -1;
+ return this.activate(view.name, opts);
+ }
+ },
+
+ /**
+ * If this is a floating ViewManager, navigates back `count` views from the stack.
+ *
+ * @param {Number} [count] Number of views to pop off the stack. Defaults to 1.
+ * @param {Object} [opts] Optional parameters to configure the deactivation
+ * @return {module:enyo/Control~Control} Activated view
+ * @public
+ */
+ back: function (count, opts) {
+ var name,
+ depth = this.stack.length;
+ if (this.floating && depth > 0) {
+ if (this.dragging) {
+ name = this.stack[0];
+ } else {
+ count = count > depth ? depth : count || 1;
+ name = this.stack.splice(0, count).pop();
+ }
+ this.direction = -1;
+ return this._activate(name, opts);
+ }
+ },
+
+ /**
+ * Determines if the ViewManager can be dragged in the provided direction
+ *
+ * @param {Number} direction -1 or 1 indicating the direction of the drag
+ * @param {String} [mode] When provided, requires `draggable` be `true` or the provided value
+ * @private
+ */
+ canDrag: function (direction, mode) {
+ var index,
+ check = mode ? this.draggable === true || this.draggable == mode : this.draggable;
+ if (check) {
+ if (this.isDimissable() && direction == -1) {
+ return true;
+ }
+ else if (!this.floating) {
+ index = this.views.indexOf(this.active);
+ return (index > 0 && direction == -1) ||
+ (index < this.views.length - 1 && direction == 1);
+ }
+ }
+
+ return false;
+ },
+
+ /**
+ * @private
+ */
+ determineDirection: function (view) {
+ var isIndex, wasIndex;
+
+ // for a floating VM, the default direction is always forward
+ if (this.floating) {
+ this.direction = 1;
+ }
+ // fixed VMs direction is based on each view's ordered position
+ else {
+ isIndex = this.indexOf(view);
+ wasIndex = this.indexOf(this.active);
+ this.direction = wasIndex < isIndex ? 1 : -1;
+ }
+ },
+
+ /**
+ * Indicates if the view is dismissable via dragging
+ *
+ * @return {Boolean}
+ * @public
+ */
+ isDimissable: function () {
+ return this.dismissable === true || (this.dismissable == 'auto' && this.floating);
+ },
+
+ /**
+ * Dismisses a view manager. If this is a root (manager-less) view manager, it cannot be
+ * dismissed.
+ *
+ * @param {Object} [opts] Optional parameters to configure the deactivation
+ * @public
+ */
+ dismiss: function (opts) {
+ if (this.manager) {
+ this.direction = -1;
+ this.set('activationOptions', opts);
+ this.set('dismissed', true);
+ this.emit('dismiss', {dragging: false});
+ this.set('active', null);
+ this.stack = [];
+ }
+ },
+
+ /**
+ * When any view event (activate, activated, deactivate, deactivated) fires, notify the view of
+ * its change of state by calling a method matching the event (e.g. activate()), if it exists.
+ *
+ * @private
+ */
+ notifyViews: function (sender, name, event) {
+ var viewEvent = name == 'activate' || name == 'activated'
+ || name == 'deactivate' || name == 'deactivated';
+
+ // Any event for a view will have an event payload with a view property indicating the view
+ // that is changing.
+ if (event && event.view && viewEvent && utils.isFunction(event.view[name])) {
+ event.view[name](event);
+ }
+ },
+
+ /**
+ * @private
+ */
+ emitViewEvent: function (name, view) {
+ this.emit(name, {
+ view: view,
+ dragging: this.dragging,
+ direction: this.direction
+ });
+ },
+
+ /**
+ * @private
+ */
+ managerEvent: function (viewManager, event, view) {
+ if (event == 'dismissed') this.managerDismissed(viewManager);
+ this.emit('manager-' + event, {
+ manager: viewManager
+ });
+ },
+
+ /**
+ * Handles dismissal of child view managers
+ *
+ * @private
+ */
+ managerDismissed: function (viewManager) {
+ this.teardownView(viewManager);
+ },
+
+ /**
+ * Activates a new view.
+ *
+ * For floating ViewManagers, the view will be added to the stack and can be removed by `back()`.
+ *
+ * @param {String} viewName Name of the view to activate
+ * @param {Object} [opts] Optional parameters to configure the activation
+ * @public
+ */
+ activate: function (viewName, opts) {
+ var replace = !!(opts && opts.replace),
+ view = this._activate(viewName, opts);
+ if (!replace && view && !this.isManager(view) && this.active && this.floating) {
+ this.stack.unshift(this.active.name);
+ }
+
+ return view;
+ },
+
+ /**
+ * Activates a view
+ *
+ * @private
+ */
+ _activate: function (viewName, opts) {
+ var replace = !!(this.activationOptions && this.activationOptions.replace),
+ view = this.getView(viewName);
+ if (view) {
+ if (!this._toBeActivated) {
+ rAF(function () {
+ this.activateImmediate(this._toBeActivated, opts);
+ this._toBeActivated = null;
+ }.bind(this));
+ }
+ else if (!replace && this.floating && !this.isManager(view)) {
+ this.stack.unshift(this._toBeActivated.name);
+ }
+ this.set('activationOptions', opts);
+ this._toBeActivated = view;
+ }
+ return view;
+ },
+
+ /**
+ * @private
+ */
+ activateImmediate: function (view, opts) {
+ // render the activated view if not already
+ if (this.generated && !view.generated) {
+ view.set('canGenerate', true);
+ view.render();
+ }
+ if (this.isManager(view)) {
+ view.emit('manage');
+ }
+ else {
+ if (!this.direction) this.determineDirection(view);
+ this.emitViewEvent('activate', view);
+ if (!this.dragging) this.set('active', view);
+ }
+ },
+
+ /**
+ * @private
+ */
+ deactivate: function (viewName) {
+ var view = this.getView(viewName);
+ if (view) rAF(this.deactivateImmediate.bind(this, view));
+ return view;
+ },
+
+ /**
+ * @private
+ */
+ deactivateImmediate: function (view) {
+ this.teardownView(view);
+
+ if (!this.isManager(view)) this.emitViewEvent('deactivated', view);
+ if (!this.dragging && this.dismissed) this.emit('dismissed');
+ },
+
+ /**
+ * Tears down a view or ViewManager if not flagged `persistent`
+ *
+ * @private
+ */
+ teardownView: function (view) {
+ if (view.node && !view.persistent) {
+ if (!this.releaseDraggedView) {
+ view.node.remove();
+ view.node = null;
+ }
+ view.set('canGenerate', false);
+ view.teardownRender(true);
+ }
+ },
+
+ /**
+ * @private
+ */
+ isManager: function (view) {
+ return view && !!this.viewManagers[view.name];
+ },
+
+ // Layout
+
+ /**
+ * Handles the 'complete' event from its layout indicating a view has completed its layout
+ * @private
+ */
+ handleLayoutComplete: function (sender, name, event) {
+ if (event.was) this.deactivateImmediate(event.was);
+ if (event.is) this.emitViewEvent('activated', event.is);
+ this.direction = 0;
+ },
+
+ // Flick
+
+ /**
+ * Flicks are handled by the drag system so here we only test if there was a valid flick and rely
+ * on the ondragfinish handler to actually act on the flick as if it were a completed drag.
+ *
+ * @private
+ */
+ handleFlick: function (sender, event) {
+ var isHorizontal = this.orientation == 'horizontal',
+ dx = event.xVelocity,
+ dy = event.yVelocity,
+ adx = Math.abs(dx),
+ ady = Math.abs(dy),
+ direction = 0;
+
+ // Set direction iff the primary flick direction matches the orientation
+ if (isHorizontal && adx > ady) {
+ direction = dx < 0 ? 1 : -1;
+ }
+ else if (!this.isHorizontal && ady > adx) {
+ direction = dy < 0 ? 1 : -1;
+ }
+
+ // If we have a direction, are flickable, and flickable in that direction, indicate it
+ if (direction && this.canDrag(direction, 'flick')) {
+ this.flicked = true;
+ return true;
+ }
+ },
+
+ // Draggable
+
+ /**
+ * Handles `ondown` events
+ *
+ * @private
+ */
+ handleDown: function (sender, event) {
+ event.configureHoldPulse({endHold: 'onMove'});
+ },
+
+ /**
+ * Handles `ondragstart` events
+ *
+ * @private
+ */
+ handleDragStart: function (sender, event) {
+ if (!this.draggable || this.dismissed) return;
+ this.set('dragging', 'start');
+ this.direction = 0;
+ this.dragView = null;
+ this.dragBounds = this.getBounds();
+
+ return true;
+ },
+
+ /**
+ * Handles `ondrag` events
+ *
+ * @private
+ */
+ handleDrag: function (sender, event) {
+ if (this.validateDrag(event)) {
+ // clean up on change of direction
+ if (this.direction !== event.direction) {
+ this.direction = event.direction;
+ if (this.dragView === false) {
+ this.dragView = null;
+ } else {
+ this.resetDragView();
+ }
+ }
+
+ // dragView can be a View, `false`, or `null`. `null` indicates we need to (try to)
+ // activate the becoming-active view. It should be null when a drag starts or when
+ // there's a change of direction. `false` indicates that we've tried to activate a view
+ // but there isn't one in that direction.
+ if (this.dragView === null) {
+ if (this.direction == 1) {
+ this.dragView = this.next();
+ } else if (this.floating) {
+ this.dragView = this.back();
+ if (!this.dragView) this.emit('dismiss', {dragging: true});
+ } else {
+ this.dragView = this.previous();
+ }
+ this.dragView = this.dragView || false;
+ }
+ this.emit('drag', event);
+
+ return true;
+ } else {
+ // Reset the drag state when dragging in an invalid direction
+ this.resetDragView();
+ this.direction = 0;
+ }
+ },
+
+ /**
+ * Handles `ondragfinish` events
+ *
+ * @private
+ */
+ handleDragFinish: function (sender, event) {
+ if (this.releaseDraggedView) {
+ this.releaseDraggedView();
+ this.releaseDraggedView = null;
+ }
+ if (this.validateDrag(event)) {
+ // if the view has been dragged far enough
+ if (this.flicked || event.percentDelta * 100 > this.dragThreshold) {
+ this.set('dragging', false);
+ // normally, there will be a becoming-active view to activate
+ if (this.dragView) {
+ // dragging for floating views can only be a back action so shift it off the stack
+ if (this.floating) this.stack.shift();
+ // stack updates aren't necessary as we updated it above
+ this.activateImmediate(this.dragView);
+ }
+ // unless it's a floating ViewManager that is being dismissed
+ else if (this.isDimissable() && event.direction == -1) {
+ this.dismiss();
+ }
+ }
+ // otherwise the drag was small enough to be cancelled
+ else {
+ this.cancelDrag();
+ }
+ this.flicked = false;
+ event.preventTap();
+
+ this.dragView = null;
+ return true;
+ } else {
+ this.set('dragging', false);
+ this.dragView = null;
+ }
+ },
+
+ /**
+ * Deactivates drag view and resets `dragView`
+ *
+ * @private
+ */
+ resetDragView: function () {
+ if (this.dragView) {
+ this.emitViewEvent('deactivate', this.dragView);
+ this.deactivate(this.dragView.name);
+ this.dragView = null;
+ }
+ },
+
+ /**
+ * @protected
+ */
+ cancelDrag: function () {
+ var was = this.dragging;
+ this.set('dragging', false);
+ // only emit cancelDrag if a valid drag was encountered (=== true and != 'start')
+ if (was === true) {
+ // Since we're restoring the active view, the navigation direction is the opposite of the
+ // drag direction.
+ this.direction = -this.direction;
+ this.emit('cancelDrag');
+ }
+ },
+
+ /**
+ * Validates that the drag event should be processed
+ *
+ * @private
+ */
+ validateDrag: function (event) {
+ var dragging = false,
+ draggable = this.dragging && this.draggable && !this.dismissed;
+
+ if (draggable) {
+ this.decorateDragEvent(event);
+ dragging =
+ // check direction against orientation to ignore drags that don't apply to this. the
+ // check should only be necessary for the first drag event so it's further guarded
+ // by the special 'start' value of dragging.
+ !(this.dragging == 'start' && !event[this.orientation]) &&
+
+ // Intentionally ignoring draggable mode here so dragView will reference the
+ // becoming-active view even if we are only supporting flick and not drag
+ this.canDrag(event.direction);
+
+ this.set('dragging', dragging);
+ }
+
+ return draggable && dragging;
+ },
+
+ /**
+ * Calculates and adds a few additional properties to the event to aid in logic in ViewManager
+ * and ViewLayout
+ *
+ * @private
+ */
+ decorateDragEvent: function (event) {
+ var isHorizontal = this.orientation == 'horizontal',
+ size = isHorizontal ? this.dragBounds.width : this.dragBounds.height,
+ delta = isHorizontal ? event.dx : event.dy;
+
+ // 'natural' touch causes us to invert the physical change
+ event.direction = delta < 0 ? 1 : -1;
+
+ // if we're only flickable, we won't set the deltas to suppress the views moving until a
+ // flick is encountered.
+ if (this.canDrag(event.direction, 'drag')) {
+ event.delta = delta;
+ event.percentDelta = 1 - (size - Math.abs(event.delta)) / size;
+ } else {
+ event.delta = 0;
+ event.percentDelta = 0;
+ }
+ }
+});
+
+module.exports = ViewMgr;
+
+/**
+* The {@link module:enyo/ViewManager~ScrimSupport} mixin
+*
+* @private
+*/
+module.exports.ScrimSupport = ScrimSupport;
diff --git a/src/ViewManager/ViewManager.less b/src/ViewManager/ViewManager.less
new file mode 100644
index 000000000..396d83b4d
--- /dev/null
+++ b/src/ViewManager/ViewManager.less
@@ -0,0 +1,19 @@
+.enyo-viewmanager {
+ // promote any ViewManager children to ensure they are above the active view
+ & > & {
+ z-index: 20;
+ }
+}
+
+.enyo-viewmanager-scrim {
+ background: #fff;
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity 300ms linear;
+ z-index: 10;
+
+ &.showing {
+ opacity: 0.5;
+ pointer-events: auto;
+ }
+}
\ No newline at end of file
diff --git a/src/ViewManager/package.json b/src/ViewManager/package.json
new file mode 100644
index 000000000..fa1ca3039
--- /dev/null
+++ b/src/ViewManager/package.json
@@ -0,0 +1,6 @@
+{
+ "main": "ViewManager.js",
+ "styles": [
+ "ViewManager.less"
+ ]
+}
\ No newline at end of file
diff --git a/src/ViewPreloadSupport.js b/src/ViewPreloadSupport.js
index 4e0d0059f..b1cf4b78e 100644
--- a/src/ViewPreloadSupport.js
+++ b/src/ViewPreloadSupport.js
@@ -1,5 +1,6 @@
/**
* Exports the {@link module:enyo/ViewPreloadSupport~ViewPreloadSupport} mixin
+* @wip
* @module enyo/ViewPreloadSupport
*/
var
@@ -14,6 +15,7 @@ var
* A {@glossary mixin} used for preloading views.
*
* @mixin
+* @wip
* @private
*/
var ViewPreloadSupport = {
@@ -140,13 +142,28 @@ var ViewPreloadSupport = {
* @public
*/
restoreView: function (id) {
+ var view = this.popView(id);
+
+ if (view) {
+ this.addControl(view);
+ }
+
+ return view;
+ },
+
+ /**
+ * Pops the specified view that was previously cached.
+ *
+ * @param {String} id - The unique identifier for the cached view that is being popped.
+ * @return {Object} The popped view.
+ * @public
+ */
+ popView: function (id) {
var cp = this._cachedViews,
view = cp[id];
if (view) {
this.$.viewCache.removeControl(view);
- this.addControl(view);
-
this._cachedViews[id] = null;
}
diff --git a/src/VirtualDataRepeater.js b/src/VirtualDataRepeater.js
index 1c631602c..4c84186ce 100644
--- a/src/VirtualDataRepeater.js
+++ b/src/VirtualDataRepeater.js
@@ -2,6 +2,9 @@ require('enyo');
/**
* Contains the declaration for the {@link module:enyo/VirtualDataRepeater~VirtualDataRepeater} kind.
+*
+* @wip
+* @public
* @module enyo/VirtualDataRepeater
*/
@@ -12,18 +15,57 @@ var
DataRepeater = require('./DataRepeater');
/**
+* Like {@link module:enyo/DataRepeater~DataRepeater},
+* {@link module:enyo/VirtualDataRepeater~VirtualDataRepeater} repeats the
+* {@link module:enyo/Control~Control} provided in the `components` block over
+* the elements of the data set provided in the `collection` property (which
+* may be an instance of {@link module:enyo/Collection~Collection} or a plain
+* old JavaScript array).
+*
+* However, unlike {@link module:enyo/DataRepeater~DataRepeater},
+* {@link module:enyo/VirtualDataRepeater~VirtualDataRepeater} only generates
+* children for a given range of items in the provided collection.
+*
+* To specify the range of items to be generated, provide the initial index via
+* the `first` property and the maximum number of items to generate via the
+* `numItems` property. The repeater will refresh automatically when you change
+* either of these properties.
+*
* @class VirtualDataRepeater
* @extends module:enyo/DataRepeater~DataRepeater
+* @wip
* @public
*/
-module.exports = kind({
+module.exports = kind(
+ /** @lends module:enyo/VirtualDataRepeater~VirtualDataRepeater.prototype */ {
name: 'enyo.VirtualDataRepeater',
kind: DataRepeater,
+ /**
+ * The maximum number of items to generate. Fewer items will be
+ * generated if the provided collection does not contain enough
+ * elements (that is, if the length of the collection minus
+ * the `first` index is less than `numItems`).
+ *
+ * @type {Number}
+ * @default 10
+ * @public
+ */
numItems: 10,
+ /**
+ * The zero-based index of the provided collection from which
+ * the repeater should start repeating children. This property will
+ * be coerced to a legal value if you provide a value that is outside
+ * the range of the collection.
+ *
+ * @type {Number}
+ * @default 0
+ * @public
+ */
first: 0,
// TODO: Decide whether we want to implement node reordering
// reorderNodes: false,
+ // Not including JSDoc info here, as we want the inherited doc to be used.
reset: function () {
// If we are showing, go ahead and reset...
if (this.getAbsoluteShowing()) {
@@ -46,6 +88,9 @@ module.exports = kind({
}
},
+ /**
+ * @private
+ */
init: function () {
this.orderedChildren = [],
this.orderedChildren_alt = [],
@@ -57,6 +102,9 @@ module.exports = kind({
this.hasInitialized = true;
},
+ /**
+ * @private
+ */
setExtent: function(first, numItems) {
var pf = this.first,
pn = this.numItems;
@@ -81,6 +129,7 @@ module.exports = kind({
}
},
+ // Not including JSDoc info here, as we want the inherited doc to be used.
refresh: function (immediate) {
// If we haven't initialized, we need to reset instead
if (!this.hasInitialized) return this.reset();
@@ -153,15 +202,29 @@ module.exports = kind({
};
}),
+ // Not including JSDoc info here, as we want the inherited doc to be used.
childForIndex: function(idx) {
return this.childrenByIndex[idx];
},
+ /**
+ * Attempts to return the [control]{@link module:enyo/Control~Control} representation of a particular
+ * model (which may be an instance of [enyo/Model]{@link module:enyo/Model~Model} or a plain old
+ * JavaScript object).
+ *
+ * @param {Number} idx - The model whose [control]{@link module:enyo/Control~Control} you want to retrieve.
+ * @returns {module:enyo/Control~Control|undefined} The [control]{@link module:enyo/Control~Control} representing
+ * the specified model, or `undefined` if there is not currently a control representing the model.
+ * @public
+ */
childForModel: function(model) {
var idx = this.orderedModels.indexOf(model);
return this.orderedChildren[idx];
},
+ /**
+ * @private
+ */
assignChild: function(model, index, child) {
var pMod = child.model,
pIdx = child.index,
@@ -187,6 +250,9 @@ module.exports = kind({
child.show();
},
+ /**
+ * @private
+ */
doIt: function() {
var dd = this.get('data'),
f = this.first,
@@ -284,14 +350,21 @@ module.exports = kind({
}
},
+ /**
+ * @private
+ */
fwd: function() {
this.set('first', this.first + 1);
},
+ /**
+ * @private
+ */
bak: function() {
this.set('first', this.first - 1);
},
+ // Not including JSDoc info here, as we want the inherited doc to be used.
set: kind.inherit(function (sup) {
return function (prop, val) {
if (prop === 'first') {
@@ -306,6 +379,9 @@ module.exports = kind({
};
}),
+ /**
+ * @private
+ */
stabilizeExtent: function() {
var f = this.first,
n = this.numItems,
@@ -320,6 +396,9 @@ module.exports = kind({
}
},
+ /**
+ * @private
+ */
dataChanged: function() {
if (this.get('data') && this.hasRendered) {
this.reset();
diff --git a/src/WebService.js b/src/WebService.js
index 5a3677c21..89cbd02b6 100644
--- a/src/WebService.js
+++ b/src/WebService.js
@@ -93,12 +93,12 @@ module.exports = kind(
* @private
*/
published: {
+ /** @lends module:enyo/WebService~WebService.prototype */
/**
* Indicates whether or not to use the [JSONP]{@glossary JSONP} protocol (and
* {@link module:enyo/Jsonp~JsonpRequest} instead of {@link module:enyo/Ajax~Ajax}).
*
- * @memberof enyo.WebService.prototype
* @type {Boolean}
* @default false
* @public
@@ -111,7 +111,6 @@ module.exports = kind(
* parameter. Enyo will create an internal callback function as necessary.
*
* @see module:enyo/WebService~WebService.jsonp
- * @memberof enyo.WebService.prototype
* @type {String}
* @default 'callback'
* @public
@@ -123,7 +122,6 @@ module.exports = kind(
* interpret the return data.
*
* @see module:enyo/WebService~WebService.jsonp
- * @memberof enyo.WebService.prototype
* @type {String}
* @default null
* @public
@@ -135,7 +133,6 @@ module.exports = kind(
* [send()]{@link module:enyo/WebService~WebService#send} call before failing with a timeout
* error.
*
- * @memberof enyo.WebService.prototype
* @type {Number}
* @default 0
* @public
diff --git a/src/XhrSource.js b/src/XhrSource.js
index 283fdf4d7..0c030a4fe 100644
--- a/src/XhrSource.js
+++ b/src/XhrSource.js
@@ -166,7 +166,7 @@ var XhrSource = module.exports = kind(
});
/**
-* @name enyo.XhrSource.concat
+* @name module:enyo/XhrSource~XhrSource.concat
* @static
* @private
*/
diff --git a/src/animation.js b/src/animation.js
index 2aa09be80..746674314 100644
--- a/src/animation.js
+++ b/src/animation.js
@@ -7,20 +7,24 @@ require('enyo');
var
platform = require('./platform'),
- utils = require('./utils');
+ utils = require('./utils'),
+ easing = require('./easing');
-var ms = Math.round(1000/60);
-var prefix = ['webkit', 'moz', 'ms', 'o', ''];
-var r = 'requestAnimationFrame';
-var c = 'cancel' + utils.cap(r);
+var ms = Math.round(1000/60),
+ prefix = ['', 'webkit', 'moz', 'ms', 'o'],
+ rAF = 'requestAnimationFrame',
+ cRAF = 'cancelRequestAnimationFrame',
+ cAF = 'cancelAnimationFrame',
+ i, pl, p, wcRAF, wrAF, wcAF,
+ _requestFrame, _cancelFrame, cancelFrame;
/*
* Fallback on setTimeout
*
* @private
*/
-var _requestFrame = function(inCallback) {
- return global.setTimeout(inCallback, ms);
+_requestFrame = function(callback) {
+ return global.setTimeout(callback, ms);
};
/*
@@ -28,23 +32,26 @@ var _requestFrame = function(inCallback) {
*
* @private
*/
-var _cancelFrame = function(inId) {
- return global.clearTimeout(inId);
+_cancelFrame = function(id) {
+ return global.clearTimeout(id);
};
-for (var i = 0, pl = prefix.length, p, wc, wr; (p = prefix[i]) || i < pl; i++) {
- // if we're on ios 6 just use setTimeout, requestAnimationFrame has some kinks currently
- if (platform.ios >= 6) {
+for (i = 0, pl = prefix.length; (p = prefix[i]) || i < pl; i++) {
+ // if we're on ios 6 just use setTimeout, requestAnimationFrame has some kinks
+ if (platform.ios === 6) {
break;
}
// if prefixed, becomes Request and Cancel
- wc = p ? (p + utils.cap(c)) : c;
- wr = p ? (p + utils.cap(r)) : r;
+ wrAF = p ? (p + utils.cap(rAF)) : rAF;
+ wcRAF = p ? (p + utils.cap(cRAF)) : cRAF;
+ wcAF = p ? (p + utils.cap(cAF)) : cAF;
+
// Test for cancelRequestAnimationFrame, because some browsers (Firefix 4-10) have a request without a cancel
- if (global[wc]) {
- _cancelFrame = global[wc];
- _requestFrame = global[wr];
+ cancelFrame = global[wcAF] || global[wcRAF];
+ if (cancelFrame) {
+ _cancelFrame = cancelFrame;
+ _requestFrame = global[wrAF];
if (p == 'webkit') {
/*
Note: In Chrome, the first return value of webkitRequestAnimationFrame is 0.
@@ -76,67 +83,21 @@ exports.requestAnimationFrame = function(callback, node) {
/**
* Cancels a requested animation callback with the specified id.
*
+* @param {Number} id - The identifier of an animation request we wish to cancel.
+* @deprecated since 2.7.0
* @public
*/
-exports.cancelRequestAnimationFrame = function(inId) {
- return _cancelFrame(inId);
+exports.cancelRequestAnimationFrame = function(id) {
+ return _cancelFrame(id);
};
-
/**
-* A set of interpolation functions for animations, similar in function to CSS3
-* transitions.
-*
-* These are intended for use with {@link module:enyo/animation#easedLerp}. Each easing function
-* accepts one (1) [Number]{@glossary Number} parameter and returns one (1)
-* [Number]{@glossary Number} value.
+* Cancels a requested animation callback with the specified id.
*
+* @param {Number} id - The identifier of an animation request we wish to cancel.
* @public
*/
-exports.easing = /** @lends module:enyo/animation~easing.prototype */ {
- /**
- * cubicIn
- *
- * @public
- */
- cubicIn: function(n) {
- return Math.pow(n, 3);
- },
- /**
- * cubicOut
- *
- * @public
- */
- cubicOut: function(n) {
- return Math.pow(n - 1, 3) + 1;
- },
- /**
- * expoOut
- *
- * @public
- */
- expoOut: function(n) {
- return (n == 1) ? 1 : (-1 * Math.pow(2, -10 * n) + 1);
- },
- /**
- * quadInOut
- *
- * @public
- */
- quadInOut: function(n) {
- n = n * 2;
- if (n < 1) {
- return Math.pow(n, 2) / 2;
- }
- return -1 * ((--n) * (n - 2) - 1) / 2;
- },
- /**
- * linear
- *
- * @public
- */
- linear: function(n) {
- return n;
- }
+exports.cancelAnimationFrame = function(id) {
+ return _cancelFrame(id);
};
/**
diff --git a/src/dispatcher.js b/src/dispatcher.js
index e1244e2fc..55b387f35 100644
--- a/src/dispatcher.js
+++ b/src/dispatcher.js
@@ -8,8 +8,7 @@ require('enyo');
var
logger = require('./logger'),
master = require('./master'),
- utils = require('./utils'),
- platform = require('./platform');
+ utils = require('./utils');
var
Dom = require('./dom');
@@ -31,10 +30,6 @@ var
* any scroll offset.
*/
-/**
-* @private
-*/
-
/**
* @private
*/
@@ -47,17 +42,17 @@ var dispatcher = module.exports = dispatcher = {
*
* @private
*/
- events: ["mousedown", "mouseup", "mouseover", "mouseout", "mousemove", "mousewheel",
- "click", "dblclick", "change", "keydown", "keyup", "keypress", "input",
- "paste", "copy", "cut", "webkitTransitionEnd", "transitionend", "webkitAnimationEnd", "animationend",
- "webkitAnimationStart", "animationstart", "webkitAnimationIteration", "animationiteration"],
+ events: ['mousedown', 'mouseup', 'mouseover', 'mouseout', 'mousemove', 'mousewheel',
+ 'click', 'dblclick', 'change', 'keydown', 'keyup', 'keypress', 'input',
+ 'paste', 'copy', 'cut', 'webkitTransitionEnd', 'transitionend', 'webkitAnimationEnd', 'animationend',
+ 'webkitAnimationStart', 'animationstart', 'webkitAnimationIteration', 'animationiteration'],
/**
* These events come from window
*
* @private
*/
- windowEvents: ["resize", "load", "unload", "message", "hashchange", "popstate", "focus", "blur"],
+ windowEvents: ['resize', 'load', 'unload', 'message', 'hashchange', 'popstate', 'focus', 'blur'],
/**
* Feature plugins (aka filters)
@@ -76,8 +71,8 @@ var dispatcher = module.exports = dispatcher = {
}
for (i=0; (n=d.windowEvents[i]); i++) {
// Chrome Packaged Apps don't like "unload"
- if(n === "unload" &&
- (typeof global.chrome === "object") &&
+ if(n === 'unload' &&
+ (typeof global.chrome === 'object') &&
global.chrome.app) {
continue;
}
@@ -90,40 +85,14 @@ var dispatcher = module.exports = dispatcher = {
* @private
*/
listen: function(inListener, inEventName, inHandler) {
- if (inListener.addEventListener) {
- this.listen = function(inListener, inEventName, inHandler) {
- inListener.addEventListener(inEventName, inHandler || dispatch, false);
- };
- } else {
- //enyo.log("IE8 COMPAT: using 'attachEvent'");
- this.listen = function(inListener, inEvent, inHandler) {
- inListener.attachEvent("on" + inEvent, function(e) {
- e.target = e.srcElement;
- if (!e.preventDefault) {
- e.preventDefault = this.iePreventDefault;
- }
- return (inHandler || dispatch)(e);
- });
- };
- }
- this.listen(inListener, inEventName, inHandler);
+ inListener.addEventListener(inEventName, inHandler || dispatch, false);
},
/**
* @private
*/
stopListening: function(inListener, inEventName, inHandler) {
- if (inListener.addEventListener) {
- this.stopListening = function(inListener, inEventName, inHandler) {
- inListener.removeEventListener(inEventName, inHandler || dispatch, false);
- };
- } else {
- //enyo.log("IE8 COMPAT: using 'detachEvent'");
- this.stopListening = function(inListener, inEvent, inHandler) {
- inListener.detachEvent("on" + inEvent, inHandler || dispatch);
- };
- }
- this.stopListening(inListener, inEventName, inHandler);
+ inListener.removeEventListener(inEventName, inHandler || dispatch, false);
},
/**
@@ -188,7 +157,7 @@ var dispatcher = module.exports = dispatcher = {
*/
dispatchBubble: function(e, c) {
var type = e.type;
- type = e.customEvent ? type : "on" + type;
+ type = e.customEvent ? type : 'on' + type;
return c.bubble(type, e, c);
}
};
@@ -196,6 +165,9 @@ var dispatcher = module.exports = dispatcher = {
/**
* Called in the context of an event.
*
+* @name module:enyo/dispatcher.iePreventDefault
+* @static
+* @method
* @private
*/
dispatcher.iePreventDefault = function() {
@@ -215,29 +187,26 @@ function dispatch (inEvent) {
}
/**
+* @name module:enyo/dispatcher.bubble
+* @static
+* @method
* @private
*/
dispatcher.bubble = function(inEvent) {
- // '|| window.event' clause needed for IE8
- var e = inEvent || global.event;
- if (e) {
- // We depend on e.target existing for event tracking and dispatching.
- if (!e.target) {
- e.target = e.srcElement;
- }
- dispatcher.dispatch(e);
+ if (inEvent) {
+ dispatcher.dispatch(inEvent);
}
};
// This string is set on event handlers attributes for DOM elements that
// don't normally bubble (like onscroll) so that they can participate in the
// Enyo event system.
-dispatcher.bubbler = "enyo.bubble(arguments[0])";
+dispatcher.bubbler = 'enyo.bubble(arguments[0])';
// The code below helps make Enyo compatible with Google Packaged Apps
// Content Security Policy(http://developer.chrome.com/extensions/contentSecurityPolicy.html),
// which, among other things, forbids the use of inline scripts.
-// We replace online scripting with equivalent means, leaving enyo.bubbler
+// We replace online scripting with equivalent means, leaving dispatcher.bubbler
// for backward compatibility.
(function() {
var bubbleUp = function() {
@@ -247,13 +216,15 @@ dispatcher.bubbler = "enyo.bubble(arguments[0])";
/**
* Makes given events bubble on a specified Enyo control.
*
+ * @name: module:enyo/dispatcher.makeBubble
+ * @method
* @private
*/
dispatcher.makeBubble = function() {
var args = Array.prototype.slice.call(arguments, 0),
control = args.shift();
- if((typeof control === "object") && (typeof control.hasNode === "function")) {
+ if((typeof control === 'object') && (typeof control.hasNode === 'function')) {
utils.forEach(args, function(event) {
if(this.hasNode()) {
dispatcher.listen(this.node, event, bubbleUp);
@@ -264,15 +235,17 @@ dispatcher.bubbler = "enyo.bubble(arguments[0])";
/**
* Removes the event listening and bubbling initiated by
- * [enyo.makeBubble()]{@link enyo.makeBubble} on a specific control.
+ * [makeBubble()]{@link module:enyo/dispatcher.makeBubble} on a specific control.
*
+ * @name: module:enyo/dispatcher.unmakeBubble
+ * @method
* @private
*/
dispatcher.unmakeBubble = function() {
var args = Array.prototype.slice.call(arguments, 0),
control = args.shift();
- if((typeof control === "object") && (typeof control.hasNode === "function")) {
+ if((typeof control === 'object') && (typeof control.hasNode === 'function')) {
utils.forEach(args, function(event) {
if(this.hasNode()) {
dispatcher.stopListening(this.node, event, bubbleUp);
@@ -295,12 +268,12 @@ Dom.requiresWindow(dispatcher.connect);
*/
dispatcher.features.push(
function (e) {
- if ("click" === e.type) {
+ if ('click' === e.type) {
if (e.clientX === 0 && e.clientY === 0 && !e.detail) {
// this allows the click to dispatch as well
// but note the tap event will fire first
var cp = utils.clone(e);
- cp.type = "tap";
+ cp.type = 'tap';
cp.preventDefault = utils.nop;
dispatcher.dispatch(cp);
}
@@ -319,19 +292,20 @@ var _xy = {};
dispatcher.features.push(
function (e) {
if (
- (e.type == "mousemove") ||
- (e.type == "tap") ||
- (e.type == "click") ||
- (e.type == "touchmove")
+ (e.type == 'mousemove') ||
+ (e.type == 'tap') ||
+ (e.type == 'click') ||
+ (e.type == 'touchmove')
) {
- _xy.clientX = e.clientX;
- _xy.clientY = e.clientY;
+ var evt = (e.type == 'touchmove') ? e.touches[0] : e;
+ _xy.clientX = evt.clientX;
+ _xy.clientY = evt.clientY;
// note only ie8 does not support pageX/pageY
- _xy.pageX = e.pageX;
- _xy.pageY = e.pageY;
+ _xy.pageX = evt.pageX;
+ _xy.pageY = evt.pageY;
// note ie8 and opera report these values incorrectly
- _xy.screenX = e.screenX;
- _xy.screenY = e.screenY;
+ _xy.screenX = evt.screenX;
+ _xy.screenY = evt.screenY;
}
}
);
@@ -342,35 +316,27 @@ dispatcher.features.push(
* `clientY`, `pageX`, `pageY`, `screenX`, and `screenY` properties. It is
* important to note that IE8 and Opera have improper reporting for the
* `screenX` and `screenY` properties (they both use CSS pixels as opposed to
-* device pixels) and IE8 has no support for the `pageX` and `pageY` properties,
-* so they are facaded.
+* device pixels).
*
* @returns {module:enyo/dispatcher~CursorCoordinates} An [object]{@glossary Object} describing the
* the last known coordinates of the cursor or user-interaction point in touch environments.
* @public
*/
dispatcher.getPosition = function () {
- var p = utils.clone(_xy);
- // if we are in ie8 we facade the _pageX, pageY_ properties
- if (platform.ie < 9) {
- var d = (document.documentElement || document.body.parentNode || document.body);
- p.pageX = (p.clientX + d.scrollLeft);
- p.pageY = (p.clientY + d.scrollTop);
- }
- return p;
+ return utils.clone(_xy);
};
/**
* Key mapping feature: Adds a `keySymbol` property to key [events]{@glossary event},
* based on a global key mapping. Use
-* [enyo.dispatcher.registerKeyMap()]{@link enyo.dispatcher.registerKeyMap} to add
+* [registerKeyMap()]{@link module:enyo/dispatcher.registerKeyMap} to add
* keyCode-to-keySymbol mappings via a simple hash. This method may be called
* multiple times from different libraries to mix different maps into the global
* mapping table; if conflicts arise, the last-in wins.
*
* ```
-* enyo.dispatcher.registerKeyMap({
+* dispatcher.registerKeyMap({
* 415 : 'play',
* 413 : 'stop',
* 19 : 'pause',
@@ -378,7 +344,7 @@ dispatcher.getPosition = function () {
* 417 : 'fastforward'
* });
* ```
-*
+*
* @private
*/
dispatcher.features.push(function(e) {
@@ -402,8 +368,8 @@ utils.mixin(dispatcher, {
/**
* Event modal capture feature. Capture events to a specific control via
-* [enyo.dispatcher.capture(inControl, inShouldForward)]{@linkcode enyo.dispatcher.capture};
-* release events via [enyo.dispatcher.release()]{@link enyo.dispatcher.release}.
+* [capture(inControl, inShouldForward)]{@linkcode module:enyo/dispatcher.capture};
+* release events via [release()]{@link module:enyo/dispatcher.release}.
*
* @private
*/
@@ -427,7 +393,7 @@ dispatcher.features.push(function(e) {
//
// NOTE: This object is a plug-in; these methods should
-// be called on `enyo.dispatcher`, and not on the plug-in itself.
+// be called on `enyo/dispatcher`, and not on the plug-in itself.
//
utils.mixin(dispatcher, {
@@ -441,7 +407,7 @@ utils.mixin(dispatcher, {
*/
captures: [],
- /**
+ /**
* Captures [events]{@glossary event} for `inTarget`, where `inEvents` is specified as a
* hash of event names mapped to callback handler names to be called on `inTarget` (or,
* optionally, `inScope`). The callback is called when any of the captured events are
@@ -458,7 +424,7 @@ utils.mixin(dispatcher, {
/**
* Removes the specified target from the capture list.
- *
+ *
* @private
*/
release: function(inTarget) {
@@ -473,7 +439,7 @@ utils.mixin(dispatcher, {
/**
* Sets the information for a captured {@glossary event}.
- *
+ *
* @private
*/
setCaptureInfo: function(inInfo) {
@@ -487,28 +453,23 @@ utils.mixin(dispatcher, {
(function () {
/**
* Dispatcher preview feature
- *
+ *
* Allows {@link module:enyo/Control~Control} ancestors of the {@glossary event} target
* a chance (eldest first) to react by implementing `previewDomEvent`.
*
+ * @todo Revisit how/if we document this
* @private
*/
var fn = 'previewDomEvent';
- var preview =
- /** @lends enyo.dispatcher.features */ {
+ var preview = {
- /**
- * @private
- */
feature: function(e) {
preview.dispatch(e, e.dispatchTarget);
},
- /**
+ /*
* @returns {(Boolean|undefined)} Handlers return `true` to abort preview and prevent default
* event processing.
- *
- * @private
*/
dispatch: function(evt, control) {
var i, l,
@@ -521,12 +482,10 @@ utils.mixin(dispatcher, {
}
},
- /**
+ /*
* We ascend, making a list of Enyo [controls]{@link module:enyo/Control~Control}.
*
* Note that a control is considered to be its own ancestor.
- *
- * @private
*/
buildLineage: function(control) {
var lineage = [],
diff --git a/src/dom.js b/src/dom.js
index baf213a66..1d5e46f46 100644
--- a/src/dom.js
+++ b/src/dom.js
@@ -7,7 +7,8 @@ require('enyo');
var
roots = require('./roots'),
utils = require('./utils'),
- platform = require('./platform');
+ platform = require('./platform'),
+ transform = require('./transform');
var dom = module.exports = {
@@ -70,41 +71,11 @@ var dom = module.exports = {
}
},
- /**
- * This is designed to be copied into the `computedStyle` object.
- *
- * @private
- */
- _ie8GetComputedStyle: function(prop) {
- var re = /(\-([a-z]){1})/g;
- if (prop === 'float') {
- prop = 'styleFloat';
- } else if (re.test(prop)) {
- prop = prop.replace(re, function () {
- return arguments[2].toUpperCase();
- });
- }
- return this[prop] !== undefined ? this[prop] : null;
- },
-
/**
* @private
*/
getComputedStyle: function(node) {
- if(platform.ie < 9 && node && node.currentStyle) {
- //simple global.getComputedStyle polyfill for IE8
- var computedStyle = utils.clone(node.currentStyle);
- computedStyle.getPropertyValue = this._ie8GetComputedStyle;
- computedStyle.setProperty = function() {
- return node.currentStyle.setExpression.apply(node.currentStyle, arguments);
- };
- computedStyle.removeProperty = function() {
- return node.currentStyle.removeAttribute.apply(node.currentStyle, arguments);
- };
- return computedStyle;
- } else {
- return global.getComputedStyle && node && global.getComputedStyle(node, null);
- }
+ return global.getComputedStyle && node && global.getComputedStyle(node, null);
},
/**
@@ -118,9 +89,9 @@ var dom = module.exports = {
if (nIE) {
var oConversion = {
- 'thin' : (nIE > 8 ? 2 : 1) + 'px',
- 'medium' : (nIE > 8 ? 4 : 3) + 'px',
- 'thick' : (nIE > 8 ? 6 : 5) + 'px',
+ 'thin' : '2px',
+ 'medium' : '4px',
+ 'thick' : '6px',
'none' : '0'
};
if (typeof oConversion[s] != 'undefined') {
@@ -216,64 +187,11 @@ var dom = module.exports = {
/**
* @private
*/
- // Workaround for lack of compareDocumentPosition support in IE8
- // Code MIT Licensed, John Resig; source: http://ejohn.org/blog/comparing-document-position/
- compareDocumentPosition: function(a, b) {
- return a.compareDocumentPosition ?
- a.compareDocumentPosition(b) :
- a.contains ?
- (a != b && a.contains(b) && 16) +
- (a != b && b.contains(a) && 8) +
- (a.sourceIndex >= 0 && b.sourceIndex >= 0 ?
- (a.sourceIndex < b.sourceIndex && 4) +
- (a.sourceIndex > b.sourceIndex && 2) :
- 1) +
- 0 :
- 0;
- },
-
- /**
- * @private
- */
- // moved from FittableLayout.js into common protected code
- _ieCssToPixelValue: function(node, value) {
- var v = value;
- // From the awesome hack by Dean Edwards
- // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
- var s = node.style;
- // store style and runtime style values
- var l = s.left;
- var rl = node.runtimeStyle && node.runtimeStyle.left;
- // then put current style in runtime style.
- if (rl) {
- node.runtimeStyle.left = node.currentStyle.left;
- }
- // apply given value and measure its pixel value
- s.left = v;
- v = s.pixelLeft;
- // finally restore previous state
- s.left = l;
- if (rl) {
- s.runtimeStyle.left = rl;
- }
- return v;
- },
-
- /**
- * @private
- */
- _pxMatch: /px/i,
getComputedBoxValue: function(node, prop, boundary, computedStyle) {
var s = computedStyle || this.getComputedStyle(node);
- if (s && (!platform.ie || platform.ie >= 9)) {
+ if (s) {
var p = s.getPropertyValue(prop + '-' + boundary);
return p === 'auto' ? 0 : parseInt(p, 10);
- } else if (node && node.currentStyle) {
- var v = node.currentStyle[prop + utils.cap(boundary)];
- if (!v.match(this._pxMatch)) {
- v = this._ieCssToPixelValue(node, v);
- }
- return parseInt(v, 0);
}
return 0;
},
@@ -361,8 +279,7 @@ var dom = module.exports = {
if (node.offsetParent) {
do {
// Adjust the offset if relativeToNode is a child of the offsetParent
- // For IE 8 compatibility, have to use integer 8 instead of Node.DOCUMENT_POSITION_CONTAINS
- if (relativeToNode && this.compareDocumentPosition(relativeToNode, node.offsetParent) & 8) {
+ if (relativeToNode && relativeToNode.compareDocumentPosition(node.offsetParent) & Node.DOCUMENT_POSITION_CONTAINS) {
offsetAdjustLeft = relativeToNode.offsetLeft;
offsetAdjustTop = relativeToNode.offsetTop;
}
@@ -377,11 +294,7 @@ var dom = module.exports = {
}
// Need to correct for borders if any exist on parent elements
if (node !== targetNode) {
- if (node.currentStyle) {
- // Oh IE, we do so love working around your incompatibilities
- borderLeft = parseInt(node.currentStyle.borderLeftWidth, 10);
- borderTop = parseInt(node.currentStyle.borderTopWidth, 10);
- } else if (global.getComputedStyle) {
+ if (global.getComputedStyle) {
borderLeft = parseInt(global.getComputedStyle(node, '').getPropertyValue('border-left-width'), 10);
borderTop = parseInt(global.getComputedStyle(node, '').getPropertyValue('border-top-width'), 10);
} else {
@@ -397,8 +310,7 @@ var dom = module.exports = {
}
}
// Continue if we have an additional offsetParent, and either don't have a relativeToNode or the offsetParent is contained by the relativeToNode (if offsetParent contains relativeToNode, then we have already calculated up to the node, and can safely exit)
- // For IE 8 compatibility, have to use integer 16 instead of Node.DOCUMENT_POSITION_CONTAINED_BY
- } while ((node = node.offsetParent) && (!relativeToNode || this.compareDocumentPosition(relativeToNode, node) & 16));
+ } while ((node = node.offsetParent) && (!relativeToNode || relativeToNode.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_CONTAINED_BY));
}
return {
'top': top,
@@ -417,8 +329,7 @@ var dom = module.exports = {
* @public
*/
removeNode: function (node) {
- if (node.remove) node.remove();
- else if (node.parentNode) node.parentNode.removeChild(node);
+ if (node.parentNode) node.parentNode.removeChild(node);
},
/**
@@ -528,6 +439,68 @@ var dom = module.exports = {
}
},
+ /**
+ * Get DOM node animation properties.
+ * @public
+ * @param {HTMLElement} node DOM node
+ * @param {Object} props Properties to fetch from DOM.
+ * @param {Object} initial Default properties to be applied.
+ * @return {Object} Object with various animation properties.
+ */
+ getAnimatedProperty: function (node, props, initial) {
+ if(!node) return;
+
+ var eP = {},
+ sP = initial ? utils.mixin({}, initial) : {},
+ tP = {},
+ dP = {},
+ m, k, v,
+ s = initial ? undefined : this.getComputedStyle(node);
+
+ for (k in props) {
+ v = sP[k];
+ if (!utils.isTransform(k)) {
+ v = v || utils.getStyleValue(s || this.getComputedStyle(node), k);
+ sP[k] = utils.formatCSSValues(v, k);
+ eP[k] = utils.formatCSSValues(props[k], k, sP[k] ? sP[k].length : sP[k]);
+ } else {
+ v = utils.formatTransformValues(props[k], k);
+ if (k.match(/rotate/)) {
+ v = transform.Quaternion.toQuant(v);
+ tP.rotate = tP.rotate ? transform.Quaternion.multiplication(tP.rotate, v) : v;
+ } else {
+ t = k.replace(/[XYZ]$/,'');
+ tP[t] = tP[t] ? tP[t].map(function (num, id) {
+ return num + v[id];
+ }) : v;
+ }
+ if (k.match(/[XYZ]$/)) {
+ t = k.replace(/[XYZ]$/,'');
+ props[t] = tP[t].join();
+ delete props[k];
+ }
+ }
+ }
+
+ if (initial) {
+ dP.translate = initial.translate;
+ dP.rotate = initial.rotate.length < 4 ? transform.Quaternion.toQuant(initial.rotate) : initial.rotate;
+ dP.scale = initial.scale;
+ dP.skew = initial.skew;
+ dP.perspective = initial.perspective;
+ } else {
+ m = utils.getStyleValue(s || this.getComputedStyle(node), this.getCssTransformProp());
+ m = utils.formatTransformValues(m, 'matrix');
+ transform.Matrix.decompose(m, dP);
+ }
+
+ for(k in dP) {
+ sP[k] = dP[k];
+ eP[k] = tP[k] || dP[k];
+ }
+ return {_startAnim: sP, _endAnim: eP, _transform: dP, currentState: dP, matrix: m, props: props};
+ },
+
/**
* @private
*/
@@ -576,7 +549,7 @@ var dom = module.exports = {
};
// override setInnerHtml for Windows 8 HTML applications
-if (typeof global.MSApp !== 'undefined') {
+if (typeof global.MSApp !== 'undefined' && typeof global.MSApp.execUnsafeLocalFunction !== 'undefined') {
dom.setInnerHtml = function(node, html) {
global.MSApp.execUnsafeLocalFunction(function() {
node.innerHTML = html;
@@ -633,6 +606,7 @@ dom.calcCanAccelerate = function() {
}
return false;
};
+
/**
* @private
*/
@@ -660,6 +634,19 @@ dom.getStyleTransformProp = function() {
}
};
+/**
+* @private
+*/
+dom.toTransformValue = function(matrix, ret) {
+ var mat = transform.Matrix.toString(matrix);
+
+ ret = ret || {};
+ for (var i = 0, p; (p = styleTransformProps[i]); i++) {
+ ret[p] = mat;
+ }
+ return ret;
+};
+
/**
* @private
*/
@@ -792,8 +779,7 @@ dom.transformValue = function(control, transform, value) {
* directly, to be applied to `translateZ(value)`.
*
* @param {module:enyo/Control~Control} control - The {@link module:enyo/Control~Control} to accelerate.
-* @param {(String|Number)} [value] - An optional value to apply to the acceleration transform
-* property.
+* @param {(String|Number)} [value] - An optional value to apply to the acceleration transform property.
* @public
*/
dom.accelerate = function(control, value) {
@@ -801,7 +787,6 @@ dom.accelerate = function(control, value) {
this.transformValue(control, 'translateZ', v ? 0 : null);
};
-
/**
* The CSS `transition` property name for the current browser/platform, e.g.:
*
diff --git a/src/easing.js b/src/easing.js
new file mode 100644
index 000000000..e6dd104cb
--- /dev/null
+++ b/src/easing.js
@@ -0,0 +1,408 @@
+/**
+* Contains set of interpolation functions for animations, similar in function to CSS3 transitions.
+* @module enyo/easing
+*/
+
+var easing = module.exports = {
+ /**
+ * linear
+ *
+ * @public
+ */
+ linear: function(n) {
+ return n;
+ },
+ /**
+ * cubicIn
+ *
+ * @public
+ */
+ cubicIn: function(n) {
+ return Math.pow(n, 3);
+ },
+ /**
+ * cubicOut
+ *
+ * @public
+ */
+ cubicOut: function(n) {
+ return Math.pow(n - 1, 3) + 1;
+ },
+ /**
+ * expoOut
+ *
+ * @public
+ */
+ expoOut: function(n) {
+ return (n == 1) ? 1 : (-1 * Math.pow(2, -10 * n) + 1);
+ },
+ /**
+ * quadInOut
+ *
+ * @public
+ */
+ quadInOut: function(n) {
+ n = n * 2;
+ if (n < 1) {
+ return Math.pow(n, 2) / 2;
+ }
+ return -1 * ((--n) * (n - 2) - 1) / 2;
+ },
+
+ /**
+ * EaseInQuad
+ * @public
+ * @param {number} t - current time
+ * @return {number} - calculated time
+ */
+ easeInQuad: function(t) {
+ return t * t;
+ },
+
+ /**
+ * EaseOutQuad
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeOutQuad: function(t) {
+ return -1 * t * (t - 2);
+ },
+
+ /**
+ * EaseInOutQuad
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInOutQuad: function(t) {
+ if ((t *= 2) < 1) return 0.5 * t * t;
+ return -0.5 * ((--t) * (t - 2) - 1);
+ },
+
+ /**
+ * EaseInCubic
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInCubic: function(t) {
+ return t * t * t;
+ },
+
+ /**
+ * EaseOutCubic
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeOutCubic: function(t) {
+ return --t * t * t + 1;
+ },
+
+ /**
+ * EaseInOutCubic
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInOutCubic: function(t) {
+ if ((t *= 2) < 1) return 0.5 * t * t * t;
+ return 0.5 * ((t -= 2) * t * t + 2);
+ },
+
+ /**
+ * EaseInQuart
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInQuart: function(t) {
+ return t * t * t * t;
+ },
+
+ /**
+ * EaseOutQuart
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeOutQuart: function(t) {
+ return -1 * (--t * t * t * t - 1);
+ },
+
+ /**
+ * EaseInOutQuart
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInOutQuart: function(t) {
+ if ((t *= 2) < 1) return 0.5 * t * t * t * t;
+ return -0.5 * ((t -= 2) * t * t * t - 2);
+ },
+
+ /**
+ * EaseInQuint
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInQuint: function(t) {
+ return t * t * t * t * t;
+ },
+ /**
+ * EaseOutQuint
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeOutQuint: function(t) {
+ return --t * t * t * t * t + 1;
+ },
+
+ /**
+ * EaseInOutQuint
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInOutQuint: function(t, d) {
+ if ((t *= 2) < 1) return 0.5 * t * t * t * t * t;
+ return 0.5 * ((t -= 2) * t * t * t * t + 2);
+ },
+
+ /**
+ * EaseInSine
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInSine: function(t) {
+ return -1 * Math.cos(t * (Math.PI / 2)) + 1;
+ },
+
+ /**
+ * EaseOutSine
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeOutSine: function(t) {
+ return Math.sin(t * (Math.PI / 2));
+ },
+
+ /**
+ * EaseInOutSine
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInOutSine: function(t) {
+ return -0.5 * (Math.cos(Math.PI * t) - 1);
+ },
+
+ /**
+ * EaseInExpo
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInExpo: function(t) {
+ return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
+ },
+
+ /**
+ * EaseOutExpo
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeOutExpo: function(t) {
+ return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
+ },
+
+ /**
+ * EaseInOutExpo
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInOutExpo: function(t) {
+ if (t === 0) return 0;
+ if (t === 1) return 1;
+ if ((t *= 2) < 1) return 0.5 * Math.pow(2, 10 * (t - 1));
+ return 0.5 * (-Math.pow(2, -10 * --t) + 2);
+ },
+
+ /**
+ * EaseInCirc
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInCirc: function(t) {
+ return -1 * (Math.sqrt(1 - t * t) - 1);
+ },
+
+ /**
+ * EaseOutCirc
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeOutCirc: function(t) {
+ return Math.sqrt(1 - --t * t);
+ },
+
+ /**
+ * EaseInOutCirc
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInOutCirc: function(t) {
+ if ((t *= 2) < 1) return -0.5 * (Math.sqrt(1 - t * t) - 1);
+ return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
+ },
+
+ /**
+ * EaseInElastic
+ * @public
+ * @param {number} t - current time
+ * @param {number} d - duration
+ * @return {number} calculated time
+ */
+ easeInElastic: function(t, d) {
+ var a = 1,
+ p = 0,
+ s = 1.70158;
+ if (t === 0) return 0;
+ if (t === 1) return 1;
+ if (!p) p = d * 0.3;
+ if (a < 1) {
+ a = 1;
+ s = p / 4;
+ } else s = p / (2 * Math.PI) * Math.asin(1 / a);
+ return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p));
+ },
+
+ /**
+ * EaseInBounce
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInBounce: function(t) {
+ return 1 - easing.easeOutBounce(1 - t);
+ },
+
+ /**
+ * EaseOutBounce
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeOutBounce: function(t) {
+ if (t < 0.363636) {
+ return 7.5625 * t * t;
+ } else if (t < 0.727272) {
+ return 7.5625 * (t -= 0.545454) * t + 0.75;
+ } else if (t < (2.5 / 2.75)) {
+ return 7.5625 * (t -= 0.818182) * t + 0.9375;
+ } else {
+ return 7.5625 * (t -= 0.954545) * t + 0.984375;
+ }
+ },
+
+ /**
+ * EaseInOutBounce
+ * @public
+ * @param {number} t - current time
+ * @return {number} calculated time
+ */
+ easeInOutBounce: function(t) {
+ if (t < 0.5) return easing.easeInBounce(t * 2) * 0.5;
+ return easing.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
+ },
+
+ /**
+ * EaseOutElastic
+ * @public
+ * @param {number} t - current time
+ * @param {number} d - duration
+ * @return {number} calculated time
+ */
+ easeOutElastic: function(t, d) {
+ var a = 1,
+ p = 0,
+ s = 1.70158;
+ if (t === 0) return 0;
+ if (t === 1) return 1;
+ if (!p) p = d * 0.3;
+ if (a < 1) {
+ a = 1;
+ s = p / 4;
+ } else s = p / (2 * Math.PI) * Math.asin(1 / a);
+ return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + 1;
+ },
+
+ /**
+ * EaseInOutElastic
+ * @public
+ * @param {number} t - current time
+ * @param {number} d - duration
+ * @return {number} calculated time
+ */
+ easeInOutElastic: function(t, d) {
+ var a = 1,
+ p = 0,
+ s = 1.70158;
+ if (t === 0) return 0;
+ if ((t *= 2) === 2) return 1;
+ if (!p) p = d * (0.3 * 1.5);
+ if (a < 1) {
+ a = 1;
+ s = p / 4;
+ } else s = p / (2 * Math.PI) * Math.asin(1 / a);
+ if (t < 1) return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p));
+ return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + 1;
+ },
+
+ /**
+ * EaseInBack
+ * @public
+ * @param {number} t - current time
+ * @param {number} d - duration
+ * @return {number} calculated time
+ */
+ easeInBack: function(t, d, s) {
+ if (!s) s = 1.70158;
+ return t * t * ((s + 1) * t - s);
+ },
+
+ /**
+ * EaseOutBack
+ * @public
+ * @param {number} t - current time
+ * @param {number} d - duration
+ * @return {number} calculated time
+ */
+ easeOutBack: function(t, d, s) {
+ if (!s) s = 1.70158;
+ return --t * t * ((s + 1) * t + s) + 1;
+ },
+
+ /**
+ * EaseInOutBack
+ * @public
+ * @param {number} t - current time
+ * @param {number} d - duration
+ * @return {number} calculated time
+ */
+ easeInOutBack: function(t, d, s) {
+ if (!s) s = 1.70158;
+ if ((t *= 2) < 1) return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
+ return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
+ }
+};
\ No newline at end of file
diff --git a/src/gesture/drag.js b/src/gesture/drag.js
index 8de40002d..31cc721e3 100644
--- a/src/gesture/drag.js
+++ b/src/gesture/drag.js
@@ -1,6 +1,5 @@
var
dispatcher = require('../dispatcher'),
- platform = require('../platform'),
utils = require('../utils');
var
@@ -307,11 +306,6 @@ module.exports = {
e.shiftKey = inEvent.shiftKey;
e.srcEvent = inEvent.srcEvent;
// };
- //Fix for IE8, which doesn't include pageX and pageY properties
- if(platform.ie==8 && e.target) {
- e.pageX = e.clientX + e.target.scrollLeft;
- e.pageY = e.clientY + e.target.scrollTop;
- }
e.preventDefault = gestureUtil.preventDefault;
e.disablePrevention = gestureUtil.disablePrevention;
return e;
@@ -586,7 +580,7 @@ module.exports = {
}
this._pulsing = true;
dispatcher.dispatch(e);
- n = this._next = this._unsent.shift();
+ n = this._next = this._unsent && this._unsent.shift();
}
},
diff --git a/src/gesture/gesture.js b/src/gesture/gesture.js
index 4eaf02179..8759fc611 100644
--- a/src/gesture/gesture.js
+++ b/src/gesture/gesture.js
@@ -1,7 +1,6 @@
-require('enyo');
/**
- * @module enyo/gesture
- */
+* @module enyo/gesture
+*/
var
@@ -15,7 +14,6 @@ var
touchGestures = require('./touchGestures'),
gestureUtil = require('./util');
-
/**
* Enyo supports a set of normalized events that work similarly across all supported platforms.
* These events are provided so that users can write a single set of event handlers for
@@ -85,7 +83,7 @@ var gesture = module.exports = {
// We have added some logic to synchronize up and down events in certain scenarios (i.e.
// clicking multiple buttons with a mouse) and to generally guard against any potential
- // asymmetry, but a full solution would be to maintain a map of up/down events as an
+ // asymmetry, but a full solution would be to maintain a map of up/down events as an
// ideal solution, for future work.
e._tapPrevented = this.downEvent && this.downEvent._tapPrevented && this.downEvent.which == e.which;
e.preventTap = function() {
@@ -260,7 +258,7 @@ var gesture = module.exports = {
/**
* @todo I'd rather refine the public API of gesture rather than simply forwarding the internal
* drag module but this will work in the interim. - ryanjduffy
- *
+ *
* Known Consumers:
* - Spotlight.onAcceleratedKey - (prepare|begin|end)Hold()
* - Moonstone - configureHoldPulse()
@@ -335,13 +333,18 @@ module.exports.events = {
dom.requiresWindow(function() {
if (document.addEventListener) {
document.addEventListener('DOMMouseScroll', function(inEvent) {
- var e = utils.clone(inEvent);
+ var e = utils.clone(inEvent),
+ isVertical = e.VERTICAL_AXIS == e.axis,
+ wheelDelta;
e.preventDefault = function() {
inEvent.preventDefault();
};
e.type = 'mousewheel';
- var p = e.VERTICAL_AXIS == e.axis ? 'wheelDeltaY' : 'wheelDeltaX';
- e[p] = e.detail * -40;
+
+ wheelDelta = e.detail * -40;
+ e.wheelDeltaY = isVertical ? wheelDelta : 0;
+ e.wheelDeltaX = isVertical ? 0 : wheelDelta;
+
dispatcher.dispatch(e);
}, false);
}
diff --git a/src/gesture/touchGestures.js b/src/gesture/touchGestures.js
index eed1a4cb0..6010a0534 100644
--- a/src/gesture/touchGestures.js
+++ b/src/gesture/touchGestures.js
@@ -4,7 +4,7 @@ var
/**
* The extended {@glossary event} [object]{@glossary Object} that is provided when we
-* emulate iOS gesture events on non-iOS devices.
+* emulate iOS multitouch gesture events on non-iOS devices.
*
* @typedef {Object} module:enyo/gesture/touchGestures~EmulatedGestureEvent
* @property {Number} pageX - The x-coordinate of the center point between fingers.
diff --git a/src/gesture/util.js b/src/gesture/util.js
index e2466335c..0f2d9f8a5 100644
--- a/src/gesture/util.js
+++ b/src/gesture/util.js
@@ -50,11 +50,6 @@ module.exports = {
// Note that while 'which' works in IE9, it is broken for mousemove. Therefore,
// in IE, use global.event.button
if (platform.ie < 10) {
- //Fix for IE8, which doesn't include pageX and pageY properties
- if(platform.ie==8 && e.target) {
- e.pageX = e.clientX + e.target.scrollLeft;
- e.pageY = e.clientY + e.target.scrollTop;
- }
var b = global.event && global.event.button;
if (b) {
// multi-button not supported, priority: left, right, middle
diff --git a/src/i18n.js b/src/i18n.js
index 861ef5c9d..ef85b5901 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -43,8 +43,6 @@ exports.$L = new utils.Extensible(function (str) {
* `i18n.updateLocale()`. The default implementation of `i18n.updateLocale()` is a stub, but an
* i18n library may override it to update its internal state before the `onlocalechange` signal
* is broadcast.
-*
-* This feature is not supported on IE8, which doesn't support `addEventListener()`.
*
* @private
*/
diff --git a/src/kind.js b/src/kind.js
index a099198fd..9caf55de0 100644
--- a/src/kind.js
+++ b/src/kind.js
@@ -1,303 +1,301 @@
require('enyo');
var
- logger = require('./logger'),
- utils = require('./utils');
+ logger = require('./logger'),
+ Scene = require('./scene'),
+ utils = require('./utils');
var defaultCtor = null;
-
/**
-* Creates a JavaScript {@glossary constructor} function with
-* a prototype defined by `props`. **All constructors must have a unique name.**
-*
-* `kind()` makes it easy to build a constructor-with-prototype (like a
-* class) that has advanced features like prototype-chaining
-* ({@glossary inheritance}).
-*
-* A plug-in system is included for extending the abilities of the
-* {@glossary kind} generator, and constructors are allowed to
-* perform custom operations when subclassed.
-*
-* If you make changes to `enyo/kind`, be sure to add or update the appropriate
-* [unit tests](@link https://github.com/enyojs/enyo/tree/master/tools/test/core/tests).
-*
-* For more information, see the documentation on
-* [Kinds]{@linkplain $dev-guide/key-concepts/kinds.html} in the Enyo Developer Guide.
-*
-* @module enyo/kind
-* @param {Object} props - A [hash]{@glossary Object} of properties used to define and create
-* the {@glossary kind}
-* @public
-*/
+ * Creates a JavaScript {@glossary constructor} function with
+ * a prototype defined by `props`. **All constructors must have a unique name.**
+ *
+ * `kind()` makes it easy to build a constructor-with-prototype (like a
+ * class) that has advanced features like prototype-chaining
+ * ({@glossary inheritance}).
+ *
+ * A plug-in system is included for extending the abilities of the
+ * {@glossary kind} generator, and constructors are allowed to
+ * perform custom operations when subclassed.
+ *
+ * If you make changes to `enyo/kind`, be sure to add or update the appropriate
+ * [unit tests](@link https://github.com/enyojs/enyo/tree/master/tools/test/core/tests).
+ *
+ * For more information, see the documentation on
+ * [Kinds]{@linkplain $dev-guide/key-concepts/kinds.html} in the Enyo Developer Guide.
+ *
+ * @module enyo/kind
+ * @param {Object} props - A [hash]{@glossary Object} of properties used to define and create
+ * the {@glossary kind}
+ * @public
+ */
/*jshint -W120*/
-var kind = exports = module.exports = function (props) {
-/*jshint +W120*/
- // extract 'name' property
- var name = props.name || '';
- delete props.name;
- // extract 'kind' property
- var hasKind = ('kind' in props);
- var kindName = props.kind;
- delete props.kind;
- // establish base class reference
- var base = constructorForKind(kindName);
- var isa = base && base.prototype || null;
- // if we have an explicit kind property with value undefined, we probably
- // tried to reference a kind that is not yet in scope
- if (hasKind && kindName === undefined || base === undefined) {
- var problem = kindName === undefined ? 'undefined kind' : 'unknown kind (' + kindName + ')';
- throw 'enyo.kind: Attempt to subclass an ' + problem + '. Check dependencies for [' + (name || '') + '].';
- }
- // make a boilerplate constructor
- var ctor = kind.makeCtor();
- // semi-reserved word 'constructor' causes problems with Prototype and IE, so we rename it here
- if (props.hasOwnProperty('constructor')) {
- props._constructor = props.constructor;
- delete props.constructor;
- }
- // create our prototype
- //ctor.prototype = isa ? enyo.delegate(isa) : {};
- utils.setPrototype(ctor, isa ? utils.delegate(isa) : {});
- // there are special cases where a base class has a property
- // that may need to be concatenated with a subclasses implementation
- // as opposed to completely overwriting it...
- kind.concatHandler(ctor, props);
-
- // put in our props
- utils.mixin(ctor.prototype, props);
- // alias class name as 'kind' in the prototype
- // but we actually only need to set this if a new name was used,
- // not if it is inheriting from a kind anonymously
- if (name) {
- ctor.prototype.kindName = name;
- }
- // this is for anonymous constructors
- else {
- ctor.prototype.kindName = base && base.prototype? base.prototype.kindName: '';
- }
- // cache superclass constructor
- ctor.prototype.base = base;
- // reference our real constructor
- ctor.prototype.ctor = ctor;
- // support pluggable 'features'
- utils.forEach(kind.features, function(fn){ fn(ctor, props); });
-
- if (name) kindCtors[name] = ctor;
-
- return ctor;
+var kind = exports = module.exports = function(props) {
+ /*jshint +W120*/
+ // extract 'name' property
+ var name = props.name || '';
+ delete props.name;
+ // extract 'kind' property
+ var hasKind = ('kind' in props);
+ var kindName = props.kind;
+ delete props.kind;
+ // establish base class reference
+ var base = constructorForKind(kindName);
+ var isa = base && base.prototype || null;
+ // if we have an explicit kind property with value undefined, we probably
+ // tried to reference a kind that is not yet in scope
+ if (hasKind && kindName === undefined || base === undefined) {
+ var problem = kindName === undefined ? 'undefined kind' : 'unknown kind (' + kindName + ')';
+ throw 'enyo.kind: Attempt to subclass an ' + problem + '. Check dependencies for [' + (name || '') + '].';
+ }
+ // make a boilerplate constructor
+ var ctor = kind.makeCtor();
+ // semi-reserved word 'constructor' causes problems with Prototype and IE, so we rename it here
+ if (props.hasOwnProperty('constructor')) {
+ props._constructor = props.constructor;
+ delete props.constructor;
+ }
+ // create our prototype
+ //ctor.prototype = isa ? enyo.delegate(isa) : {};
+ utils.setPrototype(ctor, isa ? utils.delegate(isa) : {});
+ // there are special cases where a base class has a property
+ // that may need to be concatenated with a subclasses implementation
+ // as opposed to completely overwriting it...
+ kind.concatHandler(ctor, props);
+
+ // put in our props
+ utils.mixin(ctor.prototype, props);
+ // alias class name as 'kind' in the prototype
+ // but we actually only need to set this if a new name was used,
+ // not if it is inheriting from a kind anonymously
+ if (name) {
+ ctor.prototype.kindName = name;
+ }
+ // this is for anonymous constructors
+ else {
+ ctor.prototype.kindName = base && base.prototype ? base.prototype.kindName : '';
+ }
+ // cache superclass constructor
+ ctor.prototype.base = base;
+ // reference our real constructor
+ ctor.prototype.ctor = ctor;
+ // support pluggable 'features'
+ utils.forEach(kind.features, function(fn) { fn(ctor, props); });
+
+ if (name) kindCtors[name] = ctor;
+
+ return ctor;
};
-exports.setDefaultCtor = function (ctor) {
- defaultCtor = ctor;
+exports.setDefaultCtor = function(ctor) {
+ defaultCtor = ctor;
};
-var getDefaultCtor = exports.getDefaultCtor = function () {
- return defaultCtor;
+var getDefaultCtor = exports.getDefaultCtor = function() {
+ return defaultCtor;
};
/**
-* @private
-*/
+ * @private
+ */
var concatenated = exports.concatenated = [];
/**
-* Creates a singleton of a given {@glossary kind} with a given
-* definition. **The `name` property will be the instance name of the singleton
-* and must be unique.**
-*
-* ```javascript
-* var
-* kind = require('enyo/kind'),
-* Control = require('enyo/Control');
-*
-* module.exports = singleton({
-* kind: Control,
-* name: 'app.MySingleton',
-* published: {
-* value: 'foo'
-* },
-* makeSomething: function() {
-* //...
-* }
-* });
-*
-* app.MySingleton.makeSomething();
-* app.MySingleton.setValue('bar');
-*```
-*
-* @public
-*/
-exports.singleton = function (conf) {
- // extract 'name' property (the name of our singleton)
- delete(conf.name);
- // create an unnamed kind and save its constructor's function
- var Kind = kind(conf);
- var inst = new Kind();
- return inst;
+ * Creates a singleton of a given {@glossary kind} with a given
+ * definition. **The `name` property will be the instance name of the singleton
+ * and must be unique.**
+ *
+ * ```javascript
+ * var
+ * kind = require('enyo/kind'),
+ * Control = require('enyo/Control');
+ *
+ * module.exports = singleton({
+ * kind: Control,
+ * name: 'app.MySingleton',
+ * published: {
+ * value: 'foo'
+ * },
+ * makeSomething: function() {
+ * //...
+ * }
+ * });
+ *
+ * app.MySingleton.makeSomething();
+ * app.MySingleton.setValue('bar');
+ *```
+ *
+ * @public
+ */
+exports.singleton = function(conf) {
+ // extract 'name' property (the name of our singleton)
+ delete(conf.name);
+ // create an unnamed kind and save its constructor's function
+ var Kind = kind(conf);
+ var inst = new Kind();
+ return inst;
};
/**
-* @private
-*/
-kind.makeCtor = function () {
- var enyoConstructor = function () {
- if (!(this instanceof enyoConstructor)) {
- throw 'enyo.kind: constructor called directly, not using "new"';
- }
-
- // two-pass instantiation
- var result;
- if (this._constructor) {
- // pure construction
- result = this._constructor.apply(this, arguments);
- }
- // defer initialization until entire constructor chain has finished
- if (this.constructed) {
- // post-constructor initialization
- this.constructed.apply(this, arguments);
- }
-
- if (result) {
- return result;
- }
- };
- return enyoConstructor;
+ * @name module:enyo/kind.makeCtor
+ * @method
+ * @private
+ */
+kind.makeCtor = function() {
+ var enyoConstructor = function() {
+ if (!(this instanceof enyoConstructor)) {
+ throw 'enyo.kind: constructor called directly, not using "new"';
+ }
+
+ // two-pass instantiation
+ var result;
+ if (this._constructor) {
+ // pure construction
+ result = this._constructor.apply(this, arguments);
+ }
+ // defer initialization until entire constructor chain has finished
+ if (this.constructed) {
+ // post-constructor initialization
+ this.constructed.apply(this, arguments);
+ }
+
+ if (result) {
+ return result;
+ }
+ };
+ return enyoConstructor;
};
/**
-* Classes referenced by name may omit this namespace (e.g., "Button" instead of "enyo.Button")
-*
-* @private
-*/
-kind.defaultNamespace = 'enyo';
-
-/**
-* Feature hooks for the oop system
-*
-* @private
-*/
+ * Feature hooks for the oop system
+ *
+ * @name module:enyo/kind.features
+ * @private
+ */
kind.features = [];
/**
-* Used internally by several mechanisms to allow safe and normalized handling for extending a
-* [kind's]{@glossary kind} super-methods. It can take a
-* [constructor]{@glossary constructor}, a [prototype]{@glossary Object.prototype}, or an
-* instance.
-*
-* @private
-*/
-kind.extendMethods = function (ctor, props, add) {
- var proto = ctor.prototype || ctor,
- b = proto.base;
- if (!proto.inherited && b) {
- proto.inherited = kind.inherited;
- }
- // rename constructor to _constructor to work around IE8/Prototype problems
- if (props.hasOwnProperty('constructor')) {
- props._constructor = props.constructor;
- delete props.constructor;
- }
- // decorate function properties to support inherited (do this ex post facto so that
- // ctor.prototype is known, relies on elements in props being copied by reference)
- for (var n in props) {
- var p = props[n];
- if (isInherited(p)) {
- // ensure that if there isn't actually a super method to call, it won't
- // fail miserably - while this shouldn't happen often, it is a sanity
- // check for mixin-extensions for kinds
- if (add) {
- p = proto[n] = p.fn(proto[n] || utils.nop);
- } else {
- p = proto[n] = p.fn(b? (b.prototype[n] || utils.nop): utils.nop);
- }
- }
- if (utils.isFunction(p)) {
- if (add) {
- proto[n] = p;
- p.displayName = n + '()';
- } else {
- p._inherited = b? b.prototype[n]: null;
- // FIXME: we used to need some extra values for inherited, then inherited got cleaner
- // but in the meantime we used these values to support logging in Object.
- // For now we support this legacy situation, by suppling logging information here.
- p.displayName = proto.kindName + '.' + n + '()';
- }
- }
- }
+ * Used internally by several mechanisms to allow safe and normalized handling for extending a
+ * [kind's]{@glossary kind} super-methods. It can take a
+ * [constructor]{@glossary constructor}, a [prototype]{@glossary Object.prototype}, or an
+ * instance.
+ *
+ * @name module:enyo/kind.extendMethods
+ * @method
+ * @private
+ */
+kind.extendMethods = function(ctor, props, add) {
+ var proto = ctor.prototype || ctor,
+ b = proto.base;
+ if (!proto.inherited && b) {
+ proto.inherited = kind.inherited;
+ }
+ // rename constructor to _constructor to work around IE8/Prototype problems
+ if (props.hasOwnProperty('constructor')) {
+ props._constructor = props.constructor;
+ delete props.constructor;
+ }
+ // decorate function properties to support inherited (do this ex post facto so that
+ // ctor.prototype is known, relies on elements in props being copied by reference)
+ for (var n in props) {
+ var p = props[n];
+ if (isInherited(p)) {
+ // ensure that if there isn't actually a super method to call, it won't
+ // fail miserably - while this shouldn't happen often, it is a sanity
+ // check for mixin-extensions for kinds
+ if (add) {
+ p = proto[n] = p.fn(proto[n] || utils.nop);
+ } else {
+ p = proto[n] = p.fn(b ? (b.prototype[n] || utils.nop) : utils.nop);
+ }
+ }
+ if (utils.isFunction(p)) {
+ if (add) {
+ proto[n] = p;
+ p.displayName = n + '()';
+ } else {
+ p._inherited = b ? b.prototype[n] : null;
+ // FIXME: we used to need some extra values for inherited, then inherited got cleaner
+ // but in the meantime we used these values to support logging in Object.
+ // For now we support this legacy situation, by suppling logging information here.
+ p.displayName = proto.kindName + '.' + n + '()';
+ }
+ }
+ }
};
kind.features.push(kind.extendMethods);
/**
-* Called by {@link module:enyo/CoreObject~Object} instances attempting to access super-methods
-* of a parent class ([kind]{@glossary kind}) by calling
-* `this.inherited(arguments)` from within a kind method. This can only be done
-* safely when there is known to be a super class with the same method.
-*
-* @private
-*/
-kind.inherited = function (originals, replacements) {
- // one-off methods are the fast track
- var target = originals.callee;
- var fn = target._inherited;
-
- // regardless of how we got here, just ensure we actually
- // have a function to call or else we throw a console
- // warning to notify developers they are calling a
- // super method that doesn't exist
- if ('function' === typeof fn) {
- var args = originals;
- if (replacements) {
- // combine the two arrays, with the replacements taking the first
- // set of arguments, and originals filling up the rest.
- args = [];
- var i = 0, l = replacements.length;
- for (; i < l; ++i) {
- args[i] = replacements[i];
- }
- l = originals.length;
- for (; i < l; ++i) {
- args[i] = originals[i];
- }
- }
- return fn.apply(this, args);
- } else {
- logger.warn('enyo.kind.inherited: unable to find requested ' +
- 'super-method from -> ' + originals.callee.displayName + ' in ' + this.kindName);
- }
+ * Called by {@link module:enyo/CoreObject~Object} instances attempting to access super-methods
+ * of a parent class ([kind]{@glossary kind}) by calling
+ * `this.inherited(arguments)` from within a kind method. This can only be done
+ * safely when there is known to be a super class with the same method.
+ *
+ * @name module:enyo/kind.inherited
+ * @method
+ * @private
+ */
+kind.inherited = function(originals, replacements) {
+ // one-off methods are the fast track
+ var target = originals.callee;
+ var fn = target._inherited;
+
+ // regardless of how we got here, just ensure we actually
+ // have a function to call or else we throw a console
+ // warning to notify developers they are calling a
+ // super method that doesn't exist
+ if ('function' === typeof fn) {
+ var args = originals;
+ if (replacements) {
+ // combine the two arrays, with the replacements taking the first
+ // set of arguments, and originals filling up the rest.
+ args = [];
+ var i = 0,
+ l = replacements.length;
+ for (; i < l; ++i) {
+ args[i] = replacements[i];
+ }
+ l = originals.length;
+ for (; i < l; ++i) {
+ args[i] = originals[i];
+ }
+ }
+ return fn.apply(this, args);
+ } else {
+ logger.warn('enyo.kind.inherited: unable to find requested ' +
+ 'super-method from -> ' + originals.callee.displayName + ' in ' + this.kindName);
+ }
};
// dcl inspired super-inheritance
-/**
-* @private
-*/
-var Inherited = function (fn) {
- this.fn = fn;
+var Inherited = function(fn) {
+ this.fn = fn;
};
/**
-* When defining a method that overrides an existing method in a [kind]{@glossary kind}, you
-* can wrap the definition in this function and it will decorate it appropriately for inheritance
-* to work.
-*
-* The older `this.inherited(arguments)` method still works, but this version results in much
-* faster code and is the only one supported for kind [mixins]{@glossary mixin}.
-*
-* @param {Function} fn - A [function]{@glossary Function} that takes a single
-* argument (usually named `sup`) and returns a function where
-* `sup.apply(this, arguments)` is used as a mechanism to make the
-* super-call.
-* @public
-*/
-exports.inherit = function (fn) {
- return new Inherited(fn);
+ * When defining a method that overrides an existing method in a [kind]{@glossary kind}, you
+ * can wrap the definition in this function and it will decorate it appropriately for inheritance
+ * to work.
+ *
+ * The older `this.inherited(arguments)` method still works, but this version results in much
+ * faster code and is the only one supported for kind [mixins]{@glossary mixin}.
+ *
+ * @param {Function} fn - A [function]{@glossary Function} that takes a single
+ * argument (usually named `sup`) and returns a function where
+ * `sup.apply(this, arguments)` is used as a mechanism to make the
+ * super-call.
+ * @public
+ */
+exports.inherit = function(fn) {
+ return new Inherited(fn);
};
/**
-* @private
-*/
-var isInherited = exports.isInherited = function (fn) {
- return fn && (fn instanceof Inherited);
+ * @private
+ */
+var isInherited = exports.isInherited = function(fn) {
+ return fn && (fn instanceof Inherited);
};
@@ -305,193 +303,562 @@ var isInherited = exports.isInherited = function (fn) {
// 'statics' feature
//
kind.features.push(function(ctor, props) {
- // install common statics
- if (!ctor.subclass) {
- ctor.subclass = kind.statics.subclass;
- }
- if (!ctor.extend) {
- ctor.extend = kind.statics.extend;
- }
- if (!ctor.kind) {
- ctor.kind = kind.statics.kind;
- }
- // move props statics to constructor
- if (props.statics) {
- utils.mixin(ctor, props.statics);
- delete ctor.prototype.statics;
- }
- // also support protectedStatics which won't interfere with defer
- if (props.protectedStatics) {
- utils.mixin(ctor, props.protectedStatics);
- delete ctor.prototype.protectedStatics;
- }
- // allow superclass customization
- var base = ctor.prototype.base;
- while (base) {
- base.subclass(ctor, props);
- base = base.prototype.base;
- }
+ // install common statics
+ if (!ctor.subclass) {
+ ctor.subclass = kind.statics.subclass;
+ }
+ if (!ctor.extend) {
+ ctor.extend = kind.statics.extend;
+ }
+ if (!ctor.kind) {
+ ctor.kind = kind.statics.kind;
+ }
+ // move props statics to constructor
+ if (props.statics) {
+ utils.mixin(ctor, props.statics);
+ delete ctor.prototype.statics;
+ }
+ // also support protectedStatics which won't interfere with defer
+ if (props.protectedStatics) {
+ utils.mixin(ctor, props.protectedStatics);
+ delete ctor.prototype.protectedStatics;
+ }
+ // allow superclass customization
+ var base = ctor.prototype.base;
+ while (base) {
+ base.subclass(ctor, props);
+ base = base.prototype.base;
+ }
+});
+
+
+kind.features.push(function(ctor, props) {
+ // install common statics
+ if (props.scene) {
+ var fn,
+ proto = ctor.prototype || ctor,
+ sctor = Scene.create(proto);
+
+ extend(AnimationSupport, sctor);
+ fn = props.scene.isScene ? sceneToScene : updateScene;
+ proto.scene = fn.call(sctor, props.scene);
+ }
});
/**
-* @private
-*/
+ * Adds animation from a scene to other scene
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ * @return {Object} An instance of the constructor
+ */
+function sceneToScene(src) {
+ if (!src) return;
+ if (!src.id) extend(AnimationSupport, src);
+
+ var i, l = src.length(),
+ anim;
+
+ for (i = 0; i < l; i++) {
+ anim = utils.mixin({}, src.getAnimation(i));
+ this.addAnimation(anim.animate, anim.animate.duration);
+ }
+
+ var span = src.span + this.span;
+ src.rolePlays.push({
+ actor: this,
+ span: span,
+ dur: this.span
+ });
+ return this;
+}
+
+/**
+ * Add animations within a scene
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ * @return {Object} An instance of the constructor
+ */
+function updateScene(props) {
+ if (!props) return;
+
+ var anims = utils.isArray(props) ? props : [props];
+ for (var i = 0; i < anims.length; i++) {
+ this.addAnimation(anims[i], anims[i].duration || 0);
+ }
+ return this;
+}
+
+/**
+ * @private
+ */
kind.statics = {
- /**
- * A [kind]{@glossary kind} may set its own `subclass()` method as a
- * static method for its [constructor]{@glossary constructor}. Whenever
- * it is subclassed, the constructor and properties will be passed through
- * this method for special handling of important features.
- *
- * @param {Function} ctor - The [constructor]{@glossary constructor} of the
- * [kind]{@glossary kind} being subclassed.
- * @param {Object} props - The properties of the kind being subclassed.
- * @memberof enyo.kind
- * @public
- */
- subclass: function (ctor, props) {},
-
- /**
- * Allows for extension of the current [kind]{@glossary kind} without
- * creating a new kind. This method is available on all
- * [constructors]{@glossary constructor}, although calling it on a
- * [deferred]{@glossary deferred} constructor will force it to be
- * resolved at that time. This method does not re-run the
- * {@link module:enyo/kind~kind.features} against the constructor or instance.
- *
- * @param {Object|Object[]} props A [hash]{@glossary Object} or [array]{@glossary Array}
- * of [hashes]{@glossary Object}. Properties will override
- * [prototype]{@glossary Object.prototype} properties. If a
- * method that is being added already exists, the new method will
- * supersede the existing one. The method may call
- * `this.inherited()` or be wrapped with `kind.inherit()` to call
- * the original method (this chains multiple methods tied to a
- * single [kind]{@glossary kind}).
- * @param {Object} [target] - The instance to be extended. If this is not specified, then the
- * [constructor]{@glossary constructor} of the
- * [object]{@glossary Object} this method is being called on will
- * be extended.
- * @returns {Object} The constructor of the class, or specific
- * instance, that has been extended.
- * @memberof enyo.kind
- * @public
- */
- extend: function (props, target) {
- var ctor = this
- , exts = utils.isArray(props)? props: [props]
- , proto, fn;
-
- fn = function (key, value) {
- return !(typeof value == 'function' || isInherited(value)) && concatenated.indexOf(key) === -1;
- };
-
- proto = target || ctor.prototype;
- for (var i=0, ext; (ext=exts[i]); ++i) {
- kind.concatHandler(proto, ext, true);
- kind.extendMethods(proto, ext, true);
- utils.mixin(proto, ext, {filter: fn});
- }
-
- return target || ctor;
- },
-
- /**
- * Creates a new sub-[kind]{@glossary kind} of the current kind.
- *
- * @param {Object} props A [hash]{@glossary Object} of properties used to define and create
- * the [kind]{@glossary kind}
- * @return {Function} Constructor of the new kind
- * @memberof enyo.kind
- * @public
- */
- kind: function (props) {
- if (props.kind && props.kind !== this) {
- logger.warn('Creating a different kind from a constructor\'s kind() method is not ' +
- 'supported and will be replaced with the constructor.');
- }
- props.kind = this;
- return kind(props);
- }
+ /**
+ * A [kind]{@glossary kind} may set its own `subclass()` method as a
+ * static method for its [constructor]{@glossary constructor}. Whenever
+ * it is subclassed, the constructor and properties will be passed through
+ * this method for special handling of important features.
+ *
+ * @name module:enyo/kind.subclass
+ * @method
+ * @param {Function} ctor - The [constructor]{@glossary constructor} of the
+ * [kind]{@glossary kind} being subclassed.
+ * @param {Object} props - The properties of the kind being subclassed.
+ * @public
+ */
+ subclass: function(ctor, props) {},
+
+ /**
+ * Allows for extension of the current [kind]{@glossary kind} without
+ * creating a new kind. This method is available on all
+ * [constructors]{@glossary constructor}, although calling it on a
+ * [deferred]{@glossary deferred} constructor will force it to be
+ * resolved at that time. This method does not re-run the
+ * {@link module:enyo/kind.features} against the constructor or instance.
+ *
+ * @name module:enyo/kind.extend
+ * @method
+ * @param {Object|Object[]} props A [hash]{@glossary Object} or [array]{@glossary Array}
+ * of [hashes]{@glossary Object}. Properties will override
+ * [prototype]{@glossary Object.prototype} properties. If a
+ * method that is being added already exists, the new method will
+ * supersede the existing one. The method may call
+ * `this.inherited()` or be wrapped with `kind.inherit()` to call
+ * the original method (this chains multiple methods tied to a
+ * single [kind]{@glossary kind}).
+ * @param {Object} [target] - The instance to be extended. If this is not specified, then the
+ * [constructor]{@glossary constructor} of the
+ * [object]{@glossary Object} this method is being called on will
+ * be extended.
+ * @returns {Object} The constructor of the class, or specific
+ * instance, that has been extended.
+ * @public
+ */
+ extend: function(props, target) {
+ var ctor = this,
+ exts = utils.isArray(props) ? props : [props],
+ proto, fn;
+
+ fn = function(key, value) {
+ return !(typeof value == 'function' || isInherited(value)) && concatenated.indexOf(key) === -1;
+ };
+
+ proto = target || ctor.prototype;
+ for (var i = 0, ext;
+ (ext = exts[i]); ++i) {
+ kind.concatHandler(proto, ext, true);
+ kind.extendMethods(proto, ext, true);
+ utils.mixin(proto, ext, { filter: fn });
+ }
+
+ return target || ctor;
+ },
+
+ /**
+ * Creates a new sub-[kind]{@glossary kind} of the current kind.
+ *
+ * @name module:enyo/kind.kind
+ * @method
+ * @param {Object} props A [hash]{@glossary Object} of properties used to define and create
+ * the [kind]{@glossary kind}
+ * @return {Function} Constructor of the new kind
+ * @public
+ */
+ kind: function(props) {
+ if (props.kind && props.kind !== this) {
+ logger.warn('Creating a different kind from a constructor\'s kind() method is not ' +
+ 'supported and will be replaced with the constructor.');
+ }
+ props.kind = this;
+ return kind(props);
+ }
};
/**
-* @private
-*/
-exports.concatHandler = function (ctor, props, instance) {
- var proto = ctor.prototype || ctor
- , base = proto.ctor;
-
- while (base) {
- if (base.concat) base.concat(ctor, props, instance);
- base = base.prototype.base;
- }
+ * @method
+ * @private
+ */
+exports.concatHandler = function(ctor, props, instance) {
+ var proto = ctor.prototype || ctor,
+ base = proto.ctor;
+
+ while (base) {
+ if (base.concat) base.concat(ctor, props, instance);
+ base = base.prototype.base;
+ }
};
-/**
-* Factory for [kinds]{@glossary kind} identified by [strings]{@glossary String}.
-*
-* @private
-*/
-var kindCtors = exports._kindCtors = {};
+var kindCtors =
+ /**
+ * Factory for [kinds]{@glossary kind} identified by [strings]{@glossary String}.
+ *
+ * @type Object
+ * @deprecated Since 2.6.0
+ * @private
+ */
+ exports._kindCtors = {};
/**
-* @private
-*/
-var constructorForKind = exports.constructorForKind = function (kind) {
- if (kind === null) {
- return kind;
- } else if (kind === undefined) {
- return getDefaultCtor();
- }
- else if (utils.isFunction(kind)) {
- return kind;
- }
- logger.warn('Creating instances by name is deprecated. Name used:', kind);
- // use memoized constructor if available...
- var ctor = kindCtors[kind];
- if (ctor) {
- return ctor;
- }
- // otherwise look it up and memoize what we find
- //
- // if kind is an object in enyo, say "Control", then ctor = enyo["Control"]
- // if kind is a path under enyo, say "Heritage.Button", then ctor = enyo["Heritage.Button"] || enyo.Heritage.Button
- // if kind is a fully qualified path, say "enyo.Heritage.Button", then ctor = enyo["enyo.Heritage.Button"] || enyo.enyo.Heritage.Button || enyo.Heritage.Button
- //
- // Note that kind "Foo" will resolve to enyo.Foo before resolving to global "Foo".
- // This is important so "Image" will map to built-in Image object, instead of enyo.Image control.
- ctor = Theme[kind] || (global.enyo && global.enyo[kind]) || utils.getPath.call(global, 'enyo.' + kind) || global[kind] || utils.getPath.call(global, kind);
-
- // If what we found at this namespace isn't a function, it's definitely not a kind constructor
- if (!utils.isFunction(ctor)) {
- throw '[' + kind + '] is not the name of a valid kind.';
- }
- kindCtors[kind] = ctor;
- return ctor;
+ * @method
+ * @private
+ */
+var constructorForKind = exports.constructorForKind = function(kind) {
+ if (kind === null) {
+ return kind;
+ } else if (kind === undefined) {
+ return getDefaultCtor();
+ } else if (utils.isFunction(kind)) {
+ return kind;
+ }
+ logger.warn('Creating instances by name is deprecated. Name used:', kind);
+ // use memoized constructor if available...
+ var ctor = kindCtors[kind];
+ if (ctor) {
+ return ctor;
+ }
+ // otherwise look it up and memoize what we find
+ //
+ // if kind is an object in enyo, say "Control", then ctor = enyo["Control"]
+ // if kind is a path under enyo, say "Heritage.Button", then ctor = enyo["Heritage.Button"] || enyo.Heritage.Button
+ // if kind is a fully qualified path, say "enyo.Heritage.Button", then ctor = enyo["enyo.Heritage.Button"] || enyo.enyo.Heritage.Button || enyo.Heritage.Button
+ //
+ // Note that kind "Foo" will resolve to enyo.Foo before resolving to global "Foo".
+ // This is important so "Image" will map to built-in Image object, instead of enyo.Image control.
+ ctor = Theme[kind] || (global.enyo && global.enyo[kind]) || utils.getPath.call(global, 'enyo.' + kind) || global[kind] || utils.getPath.call(global, kind);
+
+ // If what we found at this namespace isn't a function, it's definitely not a kind constructor
+ if (!utils.isFunction(ctor)) {
+ throw '[' + kind + '] is not the name of a valid kind.';
+ }
+ kindCtors[kind] = ctor;
+ return ctor;
};
/**
-* Namespace for current theme (`enyo.Theme.Button` references the Button specialization for the
-* current theme).
-*
-* @private
-*/
+ * Namespace for current theme (`enyo.Theme.Button` references the Button specialization for the
+ * current theme).
+ *
+ * @deprecated Since 2.6.0
+ * @private
+ */
var Theme = exports.Theme = {};
/**
-* @private
-*/
-exports.registerTheme = function (ns) {
- utils.mixin(Theme, ns);
+ * @method
+ * @deprecated Since 2.6.0
+ * @private
+ */
+exports.registerTheme = function(ns) {
+ utils.mixin(Theme, ns);
};
/**
-* @private
-*/
-exports.createFromKind = function (nom, param) {
- var Ctor = nom && constructorForKind(nom);
- if (Ctor) {
- return new Ctor(param);
- }
+ * @method
+ * @private
+ */
+exports.createFromKind = function(nom, param) {
+ var Ctor = nom && constructorForKind(nom);
+ if (Ctor) {
+ return new Ctor(param);
+ }
+};
+/**
+ * Interface which accepts the animation details and returns a scene object
+ * @param {Array} proto Actors
+ * @param {Object} properties Animation Properties
+ * @param {String} completed Callback function on completion
+ * @return {Object} A scene constructor object
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+kind.animate = function(proto, properties, completed) {
+ var rolePlays, sctor, parentScene;
+ parentScene = Scene({ animation: properties });
+ if (properties && proto.length > 0) {
+ for (var i = 0; i <= proto.length; i++) {
+ sctor = Scene.create(proto[i]);
+ kind.statics.extend(AnimationSupport, sctor);
+ parentScene.rolePlays.push({
+ actor: updateScene.call(sctor, properties),
+ span: (sctor.span) * (i + 1),
+ dur: sctor.span
+ });
+ }
+ } else if (properties && proto) {
+ sctor = Scene.create(proto);
+ kind.statics.extend(AnimationSupport, sctor);
+ parentScene.rolePlays.push({
+ actor: updateScene.call(sctor, properties),
+ span: sctor.span,
+ dur: sctor.span
+ });
+ }
+ kind.statics.extend(AnimationSupport, parentScene);
+ parentScene.threshold = parentScene.rolePlays.length * parentScene.span;
+ parentScene.completed = completed;
+ return parentScene;
+};
+/**
+ * Interface for Sequence animations which accepts the animation details and returns a scene object
+ * @param {Array} actors Actors
+ * @param {Object} properties Animation Properties
+ * @param {String} completed Callback function on completion
+ * @return {Object} A scene constructor object
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+kind.sequenceAnimate = function(actors, properties, completed) {
+ var actorsList, arrayCheck, rolePlays, sctor, parentScene, sceneLocal;
+ actorsList = actors;
+ arrayCheck = utils.isArray(actorsList);
+ if (arrayCheck === true && actorsList.length !== 0) {
+ parentScene = Scene.create({ generated: true });
+ parentScene.sequencing = true;
+ kind.statics.extend(AnimationSupport, parentScene);
+ for (var i = 0; i < actorsList.length; i++) {
+ sceneLocal = Scene.create(actorsList[i]);
+ for (var j = 0; j < properties.length; j++) {
+ sceneLocal.addAnimation(properties[j], properties[j].duration);
+ }
+ kind.statics.extend(AnimationSupport, sceneLocal);
+ parentScene.addAnimation(sceneLocal);
+ }
+ parentScene.completed = completed;
+ return parentScene;
+ } else {
+ sceneLocal = kind.animate(actorsList, properties, completed);
+ return sceneLocal;
+ }
+};
+
+var AnimationSupport = {
+
+
+
+ handleLayers: false,
+
+ /**
+ * An exposed property to know if know the animating state of this scene.
+ * 'true' - the scene is asked for animation(doesn't mean animation is happening)
+ * 'false' - the scene is not active(has completed or its actors are not visible)
+ * @type {Boolean}
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ animating: false,
+
+ /**
+ * An exposed property to know if the scene is ready with actors performing action.
+ * 'true' - the scene actors are ready for action
+ * 'false' - some or all actors are not ready
+ * @type {Boolean}
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ active: this && this.generated,
+
+
+ /**
+ * @private
+ */
+ timeline: 0,
+ /**
+ * @private
+ */
+ _cachedValue: 0,
+ /**
+ * @private
+ */
+ speed: 0,
+ /**
+ * @private
+ */
+ seekInterval: 0,
+ /**
+ * @private
+ */
+ repeat: false,
+ /**
+ * @private
+ */
+ cache: function(actor) {
+ actor = actor || this;
+ if (actor.speed === 0) {
+ actor.speed = actor._cachedValue;
+ }
+ this.animating = true;
+ },
+
+ /**
+ * Starts the animation of the actor
given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be started.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ play: function(actor) {
+ actor = actor || this;
+ actor.speed = 1;
+ if (isNaN(actor.timeline) || !actor.timeline) {
+ actor.timeline = 0;
+ }
+ this.trigger();
+ actor._cachedValue = actor.speed;
+ this.animating = true;
+ },
+
+ /**
+ * Replays the animation of the actor
given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be started.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ replay: function(actor) {
+ this.stop();
+ this.play();
+ },
+ /**
+ * Resumes the paused animation of the actor
given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be resumed.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ resume: function(actor) {
+ this.cache(actor);
+ actor = actor || this;
+ actor.speed *= 1;
+ },
+
+ /**
+ * Pauses the animation of the actor
given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be paused.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ pause: function(actor) {
+ actor = actor || this;
+ actor._cachedValue = actor.speed;
+ actor.speed = 0;
+ },
+
+ /**
+ * Reverses the animation of the actor
given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be reversed.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ reverse: function(actor) {
+ this.cache(actor);
+ actor = actor || this;
+ actor._cachedValue = actor.speed;
+ actor.speed *= -1;
+ },
+
+ /**
+ * fast description goes here
+ * @param {Number} mul description goes here
+ * @param [Component]{@link module:enyo/Component~Component} actor description goes here
+ * @public
+ */
+ fast: function(mul, actor) {
+ this.cache(actor);
+ actor = actor || this;
+ actor.speed *= mul;
+ },
+
+ /**
+ * slow description goes here
+ * @param {Number} mul description goes here
+ * @param [Component]{@link module:enyo/Component~Component} actor description goes here
+ * @public
+ */
+ slow: function(mul, actor) {
+ this.cache(actor);
+ actor = actor || this;
+ actor.speed *= mul;
+ },
+
+ /**
+ * Changes the speed of the animation.
+ * Speed of the animation changed based on the factor
.
+ * To slow down the speed use values between 0 and 1. For Example 0.5 to reduce the speed by 50%.
+ * To increase the speed use values above 1. For Example 2 to increase the speed by 200%.
+ * Animation will be paused if factor is 0. To pause the animation use {@link enyo/AnimationSupport/Editor.pause pause}
API.
+ * Speed will not be affected incase of negative multiplication factor.
+ * @param {Number} factor Multiplication factor which changes the speed
+ * @param [Component {@link module:enyo/Component~Component}] actor The component whose animating speed should be changed
+ * @public
+ */
+ // speed: function(mul, actor) {
+ // if (mul < 0) return;
+ // this.cache(actor);
+ // actor = actor || this;
+ // actor.speed *= mul;
+ // },
+
+ /**
+ * Stops the animation of the actor given in argument.
+ * If actor is not provided, animation of all the components linked to the {@link module:enyo/AnimationSupport/Scene} will be stopped.
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ stop: function(actor) {
+ actor = actor || this;
+ actor._cachedValue = 1;
+ actor.speed = 0;
+ actor.timeline = 0;
+ // this.animating = false;
+ // this.cancel();
+ },
+
+ /**
+ * Seeks the animation of the actor
to the position provided in seek
+ * The value of seek
should be between 0 to duration
of the animation.
+ * @param {Number} seek Value in seek where the animation has to be seeked
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ seek: function(seek, actor) {
+ actor = actor || this;
+ actor.timeline = seek;
+ },
+
+ /**
+ * Seeks actor
with animation to the position provided in seek
+ * The value of seek
should be between 0 to duration
of the animation.
+ * @param {Number} seek Value in seek where the animation has to be seeked
+ * @param [Component]{@link module:enyo/Component~Component} actor The component to be animated
+ * @public
+ */
+ seekAnimate: function(seek, actor) {
+ actor = actor || this;
+ if (seek >= 0) {
+ if (!this.animating)
+ this.play(actor);
+ actor.speed = 1;
+ } else {
+ actor.speed = -1;
+ }
+ actor.seekInterval = actor.timeline + seek;
+ if (actor.seekInterval < 0) {
+ actor.speed = 0;
+ actor.seekInterval = 0;
+ }
+ },
+
+ //TODO: Move these events to Event Delegator
+ /**
+ * Event to identify when the scene has done animating.
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ completed: function() {
+ this.animating = false;
+ },
+
+ /**
+ * Event to identify when the scene has done a step(rAF updatation of time) in the animation.
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ step: function() {}
};
diff --git a/src/logger.js b/src/logger.js
index 83440115f..1dccd4dee 100644
--- a/src/logger.js
+++ b/src/logger.js
@@ -12,22 +12,22 @@ var
* * ios
* * webos
*
-* @private
+* @ignore
*/
var dumbConsole = Boolean(platform.android || platform.ios || platform.webos);
/**
* Internally used methods and properties associated with logging.
*
-* @module enyo/logging
+* @module enyo/logger
* @public
*/
exports = module.exports = {
-
+
/**
* The log level to use. Can be a value from -1 to 99, where -1 disables all
* logging, 0 is 'error', 10 is 'warn', and 20 is 'log'. It is preferred that
- * this value be set using the [setLogLevel()]{@link module:enyo/logging#setLogLevel}
+ * this value be set using the [setLogLevel()]{@link module:enyo/logger#setLogLevel}
* method.
*
* @type {Number}
@@ -35,14 +35,14 @@ exports = module.exports = {
* @public
*/
level: 99,
-
+
/**
* The known levels.
*
* @private
*/
levels: {log: 20, warn: 10, error: 0},
-
+
/**
* @private
*/
@@ -50,7 +50,7 @@ exports = module.exports = {
var ll = parseInt(this.levels[fn], 0);
return (ll <= this.level);
},
-
+
/**
* @private
*/
@@ -66,7 +66,7 @@ exports = module.exports = {
}
}
},
-
+
/**
* @private
*/
@@ -99,7 +99,7 @@ exports = module.exports = {
console.log(a$.join(' '));
}
},
-
+
/**
* This is exposed elsewhere.
*
@@ -125,12 +125,12 @@ exports = module.exports = {
* Sets the log level to the given value. This will restrict the amount of output depending on
* the settings. The higher the value, the more output that will be allowed. The default is
* 99. The value, -1, would silence all logging, even 'error' (0).
-* Without the 'see': {@link module:enyo/logging#log}.
+* Without the 'see': {@link module:enyo/logger#log}.
*
-* @see module:enyo/logging#level
-* @see module:enyo/logging#log
-* @see module:enyo/logging#warn
-* @see module:enyo/logging#error
+* @see module:enyo/logger#level
+* @see module:enyo/logger#log
+* @see module:enyo/logger#warn
+* @see module:enyo/logger#error
* @param {Number} level - The level to set logging to.
*/
exports.setLogLevel = function (level) {
@@ -143,7 +143,7 @@ exports.setLogLevel = function (level) {
/**
* A wrapper for [console.log()]{@glossary console.log}, compatible
* across supported platforms. Will output only if the current
-* [log level]{@link module:enyo/logging#level} allows it. [Object]{@glossary Object}
+* [log level]{@link module:enyo/logger#level} allows it. [Object]{@glossary Object}
* parameters will be serialized via [JSON.stringify()]{@glossary JSON.stringify}
* automatically.
*
@@ -156,7 +156,7 @@ exports.setLogLevel = function (level) {
/**
* A wrapper for [console.warn()]{@glossary console.warn}, compatible
* across supported platforms. Will output only if the current
-* [log level]{@link module:enyo/logging#level} allows it. [Object]{@glossary Object}
+* [log level]{@link module:enyo/logger#level} allows it. [Object]{@glossary Object}
* parameters will be serialized via [JSON.stringify()]{@glossary JSON.stringify}
* automatically.
*
@@ -172,7 +172,7 @@ exports.warn = function () {
/**
* A wrapper for [console.error()]{@glossary console.error}, compatible
* across supported platforms. Will output only if the current
-* [log level]{@link module:enyo/logging#level} allows it. [Object]{@glossary Object}
+* [log level]{@link module:enyo/logger#level} allows it. [Object]{@glossary Object}
* parameters will be serialized via [JSON.stringify()]{@glossary JSON.stringify}
* automatically.
*
diff --git a/src/pageVisibility.js b/src/pageVisibility.js
index c493e7ff9..6f45652f7 100644
--- a/src/pageVisibility.js
+++ b/src/pageVisibility.js
@@ -22,7 +22,7 @@ var
* module.exports = kind({
* name: 'App',
* components: [
-* {kind: 'Signals', onvisibilitychange: 'visibilitychanged'}
+* {kind: Signals, onvisibilitychange: 'visibilitychanged'}
* ],
* visibilitychanged: function() {
* if(enyo.hidden){
diff --git a/src/platform.js b/src/platform.js
index 831564c56..804c4a3ac 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -10,6 +10,7 @@ var utils = require('./utils');
* * androidChrome (Chrome on Android, standard starting in 4.1)
* * androidFirefox
* * ie
+* * edge
* * ios
* * webos
* * windowsPhone
@@ -35,24 +36,37 @@ var utils = require('./utils');
*
* @module enyo/platform
*/
-exports = module.exports =
- /** @lends module:enyo/platform~platform */ {
- //* `true` if the platform has native single-finger [events]{@glossary event}.
- touch: Boolean(('ontouchstart' in window) || window.navigator.msMaxTouchPoints),
- //* `true` if the platform has native double-finger [events]{@glossary event}.
- gesture: Boolean(('ongesturestart' in window) || window.navigator.msMaxTouchPoints)
+exports = module.exports = {
+ /**
+ * `true` if the platform has native single-finger [events]{@glossary event}.
+ * @public
+ */
+ touch: Boolean(('ontouchstart' in window) || window.navigator.msMaxTouchPoints || (window.navigator.msManipulationViewsEnabled && window.navigator.maxTouchPoints)),
+ /**
+ * `true` if the platform has native double-finger [events]{@glossary event}.
+ * @public
+ */
+ gesture: Boolean(('ongesturestart' in window) || ('onmsgesturestart' in window && (window.navigator.msMaxTouchPoints > 1 || window.navigator.maxTouchPoints > 1)))
+
+ /**
+ * The name of the platform that was detected or `undefined` if the platform
+ * was unrecognized. This value is the key name for the major version of the
+ * platform on the exported object.
+ * @member {String} platformName
+ * @public
+ */
+
};
-/**
-* @private
-*/
var ua = navigator.userAgent;
var ep = exports;
var platforms = [
+ // Windows Phone 7 - 10
+ {platform: 'windowsPhone', regex: /Windows Phone (?:OS )?(\d+)[.\d]+/},
// Android 4+ using Chrome
{platform: 'androidChrome', regex: /Android .* Chrome\/(\d+)[.\d]+/},
// Android 2 - 4
- {platform: 'android', regex: /Android (\d+)/},
+ {platform: 'android', regex: /Android(?:\s|\/)(\d+)/},
// Kindle Fire
// Force version to 2, (desktop mode does not list android version)
{platform: 'android', regex: /Silk\/1./, forceVersion: 2, extra: {silk: 1}},
@@ -60,12 +74,12 @@ var platforms = [
// Force version to 4
{platform: 'android', regex: /Silk\/2./, forceVersion: 4, extra: {silk: 2}},
{platform: 'android', regex: /Silk\/3./, forceVersion: 4, extra: {silk: 3}},
- // Windows Phone 7 - 8
- {platform: 'windowsPhone', regex: /Windows Phone (?:OS )?(\d+)[.\d]+/},
// IE 8 - 10
{platform: 'ie', regex: /MSIE (\d+)/},
// IE 11
{platform: 'ie', regex: /Trident\/.*; rv:(\d+)/},
+ // Edge
+ {platform: 'edge', regex: /Edge\/(\d+)/},
// iOS 3 - 5
// Apple likes to make this complicated
{platform: 'ios', regex: /iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/},
diff --git a/src/ready.js b/src/ready.js
index c9937bb8e..d77a36c98 100644
--- a/src/ready.js
+++ b/src/ready.js
@@ -56,7 +56,7 @@ init = function (event) {
flush();
}
}
- // for an IE8 fallback and legacy WebKit (including webOS 3.x and less) and assurance
+ // for legacy WebKit (including webOS 3.x and less) and assurance
if ((ready = ("complete" === doc.readyState || "loaded" === doc.readyState))) {
remove(event.type, init);
flush();
@@ -67,18 +67,14 @@ init = function (event) {
* @private
*/
add = function (event, fn) {
- var name = doc.addEventListener? "addEventListener": "attachEvent";
- var on = name === "attachEvent"? "on": "";
- doc[name](on + event, fn, false);
+ doc.addEventListener(event, fn, false);
};
/**
* @private
*/
remove = function (event, fn) {
- var name = doc.addEventListener? "removeEventListener": "detachEvent";
- var on = name === "detachEvent"? "on": "";
- doc[name](on + event, fn, false);
+ doc.removeEventListener(event, fn, false);
};
/**
diff --git a/src/resolution.js b/src/resolution.js
index 883bb97bd..c4714cd9d 100644
--- a/src/resolution.js
+++ b/src/resolution.js
@@ -37,7 +37,9 @@ var ri = module.exports = {
* Executing this method also initializes the rest of the resolution-independence code.
*
* ```
- * ri.defineScreenTypes([
+ * var resolution = require('enyo/resolution');
+ *
+ * resolution.defineScreenTypes([
* {name: 'vga', pxPerRem: 8, width: 640, height: 480, aspectRatioName: 'standard'},
* {name: 'xga', pxPerRem: 16, width: 1024, height: 768, aspectRatioName: 'standard'},
* {name: 'hd', pxPerRem: 16, width: 1280, height: 720, aspectRatioName: 'hdtv'},
@@ -182,14 +184,12 @@ var ri = module.exports = {
},
/**
- * The default configurable [options]{@link ri.selectSrc#options}.
+ * The default configurable [options]{@link module:enyo/resolution.selectSrc#options}.
*
- * @typedef {Object} ri.selectSrc~src
+ * @typedef {Object} module:enyo/resolution.selectSrcSrc
* @property {String} hd - HD / 720p Resolution image asset source URI/URL
* @property {String} fhd - FHD / 1080p Resolution image asset source URI/URL
* @property {String} uhd - UHD / 4K Resolution image asset source URI/URL
- *
- * @typedef {String} ri.selectSrc~src - Image asset source URI/URL
*/
/**
@@ -217,7 +217,7 @@ var ri = module.exports = {
* {kind: Image, src: http://lorempixel.com/128/128/city/1/', alt: 'Large'},
* ```
*
- * @param {(String|module:enyo/resolution#selectSrc~src)} src - A string containing
+ * @param {(String|module:enyo/resolution~selectSrcSrc)} src - A string containing
* a single image source or a key/value hash/object containing keys representing screen
* types (`'hd'`, `'fhd'`, `'uhd'`, etc.) and values containing the asset source for
* that target screen resolution.
diff --git a/src/scene.js b/src/scene.js
new file mode 100644
index 000000000..c0cb7713c
--- /dev/null
+++ b/src/scene.js
@@ -0,0 +1,457 @@
+var
+ tween = require('./tween'),
+ utils = require('./utils'),
+ animation = require('./animation');
+
+var _ts, _wasts, _framerate = 16.6;
+
+/**
+ * This module exports "Scene" which is a class/constructor so that we can create an instance of the same.
+ * We can define all the animation properties we want in the application in the instance of the "Scene".
+ *
+ * @module enyo/AnimationSupport/Scene
+ */
+var scene = module.exports = function(props) {
+ var ctx = scene.create();
+
+ if (props.animation) {
+ var anims = utils.isArray(props.animation) ? props.animation : [props.animation];
+ for (var i = 0; i < anims.length; i++) {
+ ctx.addAnimation(anims[i], anims[i].duration || 0);
+ }
+ }
+
+ utils.mixin(ctx, SceneAction);
+ ctx.rolePlays = [];
+ utils.mixin(ctx, props);
+ return ctx;
+};
+
+var SceneAction = {
+
+ isScene: true,
+
+ /**
+ * The boundary of scene within which the scene actors will be animating.
+ * @memberOf module:enyo/AnimationSupport/Scene
+ * @public
+ * @type {number}
+ */
+ threshold: 0,
+
+ /**
+ * The actors which are added to this scene. Each actor is responsible for its own role
+ * within a scene.
+ * @memberOf module:enyo/AnimationSupport/Scene
+ * @public
+ * @type {Array}
+ */
+ rolePlays: [],
+ /**
+ * An Array of ids of all the actors participating in animation for a scene.
+ * @memberOf module:enyo/AnimationSupport/Scene
+ * @public
+ * @type {Array}
+ */
+ actorsIds: [],
+ /**
+ * An array of ids of all the animation completed actors.
+ * @memberOf module:enyo/AnimationSupport/Scene
+ * @public
+ * @type {Array}
+ */
+ completedActors: [],
+ /**
+ * This function compares two arrays to know whether they are same or not.
+ * @memberOf module:enyo/AnimationSupport/Scene
+ * @private
+ * @param {Array} array1 First Array
+ * @param {Array} array2 Second Array
+ * @return {Boolean} True => Both arrays are same; False => Arrays are not same.
+ */
+ compareArrays: function(array1, array2) {
+ var array1 = array1;
+ var array2 = array2;
+ var is_same = array1.length == array2.length && array1.every(function(element, index) {
+ return element === array2[index];
+ });
+ return is_same;
+ },
+ /**
+ * This function initiates action on the animation
+ * from the list of animations for a given scene in sequence of actors.
+ * @param {number} ts - timespan
+ * @param {Object} pose - pose from the animation list
+ * @return {Object} - pose
+ * @memberOf module:enyo/AnimationSupport/Scene
+ * @private
+ */
+ sceneConstAction: function(ts, pose) {
+ var past, index, tm,
+ dur = this.span;
+
+ if (_actor && _actor.generated) {
+ tm = rolePlay(ts, this);
+ if (isNaN(tm) || tm < 0) return pose;
+ else if (tm <= dur) {
+ if (SceneAction.actorsIds.indexOf(this.id) === -1) {
+ SceneAction.actorsIds.push(this.id);
+ }
+ index = animateAtTime(_poses, tm);
+ pose = this.getAnimation(index);
+ past = index ? this.getAnimation(index - 1).span : 0;
+ if (pose.animate instanceof this.constructor === true) {
+ pose.animate.speed = this.speed;
+ pose.animate.action(ts);
+ } else {
+ _update(pose, _actor, tm - past, pose.span - past);
+ }
+ this.step && this.step(_actor);
+ } else {
+ this.timeline = this.repeat ? 0 : this.span;
+ if (!this.repeat) this.cut();
+ }
+ }
+ return pose;
+ },
+ /**
+ * This function initiates action on the animation
+ * from the list of animations for a given scene.
+ * @param {number} ts - timespan
+ * @param {Object} pose - pose from the animation list
+ * @return {Object} - pose
+ * @memberOf module:enyo/AnimationSupport/Scene
+ * @private
+ */
+ action: function(ts, pose) {
+
+ var i, role, actor, rolePlays,
+ s, e,
+ sts = 0,
+ tm = this.timeline,
+ th = this.threshold || this.span;
+ rolePlays = this.rolePlays;
+
+ if (this.sequencing && this.sequencing === true) {
+ sceneConstAction(ts, pose);
+ } else {
+ if (rolePlays && rolePlays.length > 0 && this.animating === true) {
+ if (this.actorsIds.length !== 0 && this.completedActors.length !== 0 && this.compareArrays(this.actorsIds, this.completedActors) === true) {
+ this.animating = false;
+ this.completedAction = true;
+ }
+ s = animateAtTime(rolePlays, tm);
+ e = animateAtTime(rolePlays, tm + th);
+ e += e == s ? 1 : 0;
+
+ for (i = 0;
+ (role = rolePlays[i]); i++) {
+ actor = role.actor;
+ if (i < s) {
+ actor.active = true;
+ actor.timeline = role.dur;
+ pose = actor.action(0, pose);
+ actor.cut();
+ } else if (i >= s && i < e) {
+ actor.active = true;
+ sts += ts;
+ actor.speed = this.speed;
+ actor.repeat = this.repeat;
+ pose = actor.action(ts, pose);
+ } else {
+ if (actor.active) {
+ pose = actor.action(0, pose);
+ actor.cut();
+ }
+ }
+ }
+ tm = rolePlay(sts);
+ }
+ }
+ return pose;
+ }
+};
+
+/**
+ * Connects an actor/s to a scene.
+ * All the actors should be added before initiating animation otherwise actors will animate for remaining time span
+ * @memberOf module:enyo/AnimationSupport/Scene
+ * @public
+ * @param {Object} actors - The elements which needs to be animated
+ * @param {Object} scene - The instance of the Scene we've created in the application
+ */
+scene.link = function(actors, scene) {
+ if (!scene && !actors) return;
+
+ var actorScene, span = 0,
+ acts = utils.isArray(actors) ? actors : [actors];
+
+ for (var act, i = 0;
+ (act = acts[i]); i++) {
+ if (scene.isScene) {
+ act.scene = act.scene || scene.create(scene, act);
+ actorScene = act.scene.isScene ? act.scene : scene.create(act.scene, act);
+ span += actorScene.span;
+ scene.rolePlays.push({
+ actor: actorScene,
+ span: span,
+ dur: actorScene.span
+ });
+ scene.span = span;
+ } else {
+ actorScene = scene.create(scene, act);
+ acts[i].scene = actorScene;
+ }
+ }
+};
+
+/**
+ * Creates a empty instance of scene.
+ * Can be used for runtime creation of animations
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ * @return {Object} An instance of the constructor
+ */
+scene.create = function(ctx) {
+ return new sceneConstructor(ctx);
+};
+
+
+function sceneConstructor(actor) {
+ var
+ _req,
+ _prevDur = 0,
+ _poses = [],
+ _actor = actor,
+ _update = function(pose, actor, since, dur) {
+ var t;
+ if (!pose._startAnim) tween.init(actor, pose);
+
+ if (since < 0) since = 0;
+ if (since <= dur && dur !== 0) {
+ t = since / dur;
+ // tween.step(actor, pose, t, dur);
+ tween.step(actor, pose, (t > 0.98) ? 1 : t, dur);
+ } else {
+ tween.step(actor, pose, 1, dur);
+ }
+ },
+ /**
+ * Function used to loop in all the animations in a scene
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @private
+ */
+ _loop = function() {
+ if (this.animating) {
+ _ts = utils.perfNow();
+ _ts = _ts - (_wasts !== undefined ? _wasts : _ts);
+ _ts = (_ts > _framerate) ? _framerate : _ts;
+ this.action(_ts);
+ _wasts = _ts;
+ this.trigger(true);
+ } else {
+ _wasts = undefined;
+ this.cancel();
+ this.completed && this.completed(_actor);
+ }
+ };
+
+ this.span = 0;
+ this.id = utils.uid("@");
+
+ /**
+ * This function initiates action on the animation
+ * from the list of animations for a given scene.
+ * @param {number} ts - timespan
+ * @param {Object} pose - pose from the animation list
+ * @return {Object} - pose
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @private
+ */
+ this.action = function(ts, pose) {
+ var past, index, tm,
+ dur = this.span;
+
+ if (_actor && _actor.generated) {
+ tm = rolePlay(ts, this);
+ if (isNaN(tm) || tm < 0) return pose;
+ else if (tm <= dur) {
+ if (SceneAction.actorsIds.indexOf(this.id) === -1) {
+ SceneAction.actorsIds.push(this.id);
+ }
+ index = animateAtTime(_poses, tm);
+ pose = this.getAnimation(index);
+ past = index ? this.getAnimation(index - 1).span : 0;
+ if (pose.animate instanceof this.constructor === true) {
+ pose.animate.speed = this.speed;
+ pose.animate.action(ts);
+ } else {
+ _update(pose, _actor, tm - past, pose.span - past);
+ }
+ this.step && this.step(_actor);
+ } else {
+ if (typeof this.repeat === "boolean")
+ this.repeat = this.repeat ? Infinity : 1;
+ this.timeline = --this.repeat ? 0 : this.span;
+ if (this.timeline === this.span) this.cut();
+ }
+ }
+ return pose;
+ };
+
+ this.cut = function() {
+ if (this.handleLayers) {
+ this.speed = 0;
+ if (this.active) {
+ this.active = false;
+ tween.halt(actor);
+ }
+ }
+ this.animating = false;
+ if (SceneAction.completedActors.indexOf(this.id) === -1) {
+ SceneAction.completedActors.push(this.id);
+ }
+ this.completed && this.completed(_actor);
+
+ };
+
+ /**
+ * Cancel the animation
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ this.cancel = function() {
+ animation.cancelRequestAnimationFrame(_req);
+ };
+
+ /**
+ * Triggers the Request Animation Frame
+ * @param {boolean} force - A boolean value for letting the rAF start.
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ this.trigger = function(force) {
+ if (force || !this.animating) {
+ _req = animation.requestAnimationFrame(utils.bindSafely(this, _loop));
+ }
+ };
+
+ /**
+ * Returns animation pose based on index from the list of
+ * animations added to this scene.
+ * @param {number} index - animation's index from the list of animations
+ * @return {Object} pose of the animation based on the index in the list
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ this.getAnimation = function(index) {
+ return index < 0 || _poses[index];
+ };
+
+ /**
+ * Adds new animation on already existing animation for this character.
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ this.addAnimation = function(newProp, span) {
+ span = span ? span : newProp.span;
+ var delay = newProp.delay;
+ if (delay) {
+ this.span += delay;
+ _poses.push({
+ animate: {
+ duration: delay
+ },
+ span: this.span
+ });
+ }
+ _prevDur = span || _prevDur;
+ this.span += _prevDur;
+ _poses.push({
+ animate: newProp,
+ span: this.span
+ });
+ };
+ /**
+ * Adds new animation on the actors in a parent scene.
+ * @param {Object} newProp New animation properties
+ * @param {Number} span duration of animation
+ */
+ this.extend = function(newProp, span) {
+ for (var i = 0; i < this.rolePlays.length; i++) {
+ this.rolePlays[i].actor.addAnimation(newProp, span);
+ }
+ };
+ /**
+ * Clears/removes the animation
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ */
+ this.clearAnimation = function() {
+ for (var i = 0; i < _poses.length; i++) {
+ _poses[i]._startAnim = undefined;
+ }
+ };
+
+ /**
+ * Function which returns the length of the poses.
+ * @memberOf module:enyo/AnimationSupport/Actor
+ * @public
+ * @return {number} - length of the poses
+ */
+ this.length = function() {
+ return _poses.length;
+ };
+}
+
+/**
+ * rolePlay
updated the timeline of the actor which is currently animating.
+ * @param {Number} t Elapsed time since the animation of this pose has started (ratio in factor of 1)
+ * @param {@link module:enyo/Component~Component} actor The component which is animating
+ * @return {Number} Returns the updated timeline of the actor
+ * @private
+ */
+function rolePlay(t, actor) {
+ actor = actor || this;
+ actor.timeline += (t * actor.speed);
+
+ if (actor.seekInterval !== 0) {
+ if ((actor.seekInterval - actor.timeline) * actor.speed < 0) {
+ actor.seekInterval = 0;
+ actor.speed = 0;
+ }
+ }
+
+ if (actor.timeline === undefined || actor.timeline < 0)
+ actor.timeline = 0;
+ return actor.timeline;
+}
+
+/**
+ * Returns animation pose index for a particular
+ * instance of time from the list of
+ * animations added to the scene.
+ * @param {number} span - Time span from the animation timeline
+ * @return {number} - index of the animation
+ * @private
+ */
+function animateAtTime(anims, span) {
+ var startIndex = 0,
+ stopIndex = anims.length - 1,
+ middle = Math.floor((stopIndex + startIndex) / 2);
+
+ if (span === 0) {
+ return startIndex;
+ }
+
+ while (anims[middle].span != span && startIndex < stopIndex) {
+ if (span < anims[middle].span) {
+ stopIndex = middle;
+ } else if (span > anims[middle].span) {
+ startIndex = middle + 1;
+ }
+
+ middle = Math.floor((stopIndex + startIndex) / 2);
+ }
+ return (anims[middle].span != span) ? startIndex : middle;
+}
diff --git a/src/touch.js b/src/touch.js
index d31a64662..99ee7eca2 100644
--- a/src/touch.js
+++ b/src/touch.js
@@ -1,3 +1,9 @@
+/**
+* This module has no exports. It merely extends {@link module:enyo/gesture} to enable touch events.
+*
+* @private
+* @module enyo/touch
+*/
require('enyo');
var
@@ -31,7 +37,7 @@ Dom.requiresWindow(function() {
var oldevents = gesture.events;
/**
- * @private
+ * @ignore
*/
gesture.events.touchstart = function (e) {
// for duration of this touch, only handle touch events. Old event
@@ -41,16 +47,18 @@ Dom.requiresWindow(function() {
};
/**
- * @private
+ * @ignore
*/
var touchGesture = {
/**
+ * @ignore
* @private
*/
_touchCount: 0,
/**
+ * @ignore
* @private
*/
touchstart: function (e) {
@@ -67,6 +75,7 @@ Dom.requiresWindow(function() {
},
/**
+ * @ignore
* @private
*/
touchmove: function (e) {
@@ -99,6 +108,7 @@ Dom.requiresWindow(function() {
},
/**
+ * @ignore
* @private
*/
touchend: function (e) {
@@ -124,6 +134,7 @@ Dom.requiresWindow(function() {
* back to default; this works as long as no one did a `preventDefault()` on
* the touch events.
*
+ * @ignore
* @private
*/
mouseup: function () {
@@ -134,6 +145,7 @@ Dom.requiresWindow(function() {
},
/**
+ * @ignore
* @private
*/
makeEvent: function (e) {
@@ -147,6 +159,7 @@ Dom.requiresWindow(function() {
},
/**
+ * @ignore
* @private
*/
calcNodeOffset: function (node) {
@@ -162,6 +175,7 @@ Dom.requiresWindow(function() {
},
/**
+ * @ignore
* @private
*/
findTarget: function (e) {
@@ -172,6 +186,7 @@ Dom.requiresWindow(function() {
* NOTE: Will find only 1 element under the touch and will fail if an element is
* positioned outside the bounding box of its parent.
*
+ * @ignore
* @private
*/
findTargetTraverse: function (node, x, y) {
@@ -196,16 +211,13 @@ Dom.requiresWindow(function() {
},
/**
+ * @ignore
* @private
*/
connect: function () {
utils.forEach(['touchstart', 'touchmove', 'touchend', 'gesturestart', 'gesturechange', 'gestureend'], function(e) {
- if(platform.ie < 9){
- document['on' + e] = dispatch;
- } else {
- // on iOS7 document.ongesturechange is never called
- document.addEventListener(e, dispatch, false);
- }
+ // on iOS7 document.ongesturechange is never called
+ document.addEventListener(e, dispatch, false);
});
if (platform.androidChrome <= 18 || platform.silk === 2) {
diff --git a/src/transform.js b/src/transform.js
new file mode 100644
index 000000000..08b47bc13
--- /dev/null
+++ b/src/transform.js
@@ -0,0 +1,743 @@
+require('enyo');
+
+/**
+ * To create a Typed_array
+ * @param {Number} size The size of the buffer required
+ * @return {Number[]} Typed_array
+ */
+function typedArray (size) {
+ return new Float32Array(new ArrayBuffer(size));
+}
+
+/**
+ * To input the specified indices with value 1
+ * @param {Number[]} matrix typedArray sent
+ * @param {Number[]} numberMat indices where value has to be 1
+ */
+function inputValues (matrix, numberMat) {
+ for (var i = 0; i < numberMat.length; i++) {
+ matrix[numberMat[i]] = 1;
+ }
+}
+
+/**
+ * Transform module for transform related calculation
+ *
+ * @module enyo/AnimationSupport/Transform
+ */
+
+
+/**
+ * To create Identity Matrix3d as array.
+ * @public
+ * @return {Number[]} Identity Matrix3d
+ */
+var identity = exports.identity = function() {
+ var identityMatrix, modifiedMat;
+ identityMatrix = typedArray(64);
+ modifiedMat = inputValues(identityMatrix, new Uint8Array([0, 5, 10, 15]));
+ return identityMatrix;
+};
+
+/**
+ * To create Identity Matrix2d as array.
+ * @public
+ * @return {Number[]} Identity Matrix2d as array
+ */
+exports.identity2D = function() {
+ var identity2D, modifiedMat;
+ identity2D = typedArray(36);
+ modifiedMat = inputValues(identity2D, new Uint8Array([0, 4, 8]));
+ return identity2D;
+};
+
+/**
+ * To translate in any dimension based on co-ordinates.
+ * @public
+ * @param {Number} x Translate value in X axis
+ * @param {Number} y Translate value in Y axis
+ * @param {Number} z Translate value in Z axis
+ * @return {Number[]} Matrix3d
+ */
+exports.translate = function(x, y, z) {
+ var translateMat, modifiedMat;
+ translateMat = typedArray(64);
+ modifiedMat = inputValues(translateMat, new Uint8Array([0, 5, 10, 15]));
+ translateMat[12] = x;
+ translateMat[13] = y ? y : 0;
+ translateMat[14] = z ? z : 0;
+ return translateMat;
+};
+
+/**
+ * To translate in x dimension
+ * @public
+ * @param {Number} x Translate value in X axis
+ * @return {Number[]} Matrix3d
+ */
+exports.translateX = function(x) {
+ var translateX, modifiedMat;
+ translateX = typedArray(64);
+ modifiedMat = inputValues(translateX, new Uint8Array([0, 5, 10, 15]));
+ translateX[12] = x ? x : 0;
+ return translateX;
+};
+
+/**
+ * To translate in y dimension
+ * @public
+ * @param {Number} y Translate value in Y axis
+ * @return {Number[]} Matrix3d
+ */
+exports.translateY = function(y) {
+ var translateY, modifiedMat;
+ translateY = typedArray(64);
+ modifiedMat = inputValues(translateY, new Uint8Array([0, 5, 10, 15]));
+ translateY[13] = y ? y : 0;
+ return translateY;
+};
+
+/**
+ * To translate in z dimension
+ * @public
+ * @param {Number} z Translate value in Z axis
+ * @return {Number[]} Matrix3d
+ */
+exports.translateZ = function(z) {
+ var translateZ, modifiedMat;
+ translateZ = typedArray(64);
+ modifiedMat = inputValues(translateZ, new Uint8Array([0, 5, 10, 15]));
+ translateZ[14] = z ? z : 0;
+ return translateZ;
+};
+
+/**
+ * To scale in any dimension
+ * @public
+ * @param {Number} x Scale value in X axis
+ * @param {Number} y Scale value in Y axis
+ * @param {Number} z Scale value in Z axis
+ * @return {Number[]} Matrix3d
+ */
+exports.scale = function(x, y, z) {
+ var scaleMat = typedArray(64);
+ scaleMat[0] = x;
+ scaleMat[5] = y ? y : 1;
+ scaleMat[10] = z ? z : 1;
+ scaleMat[15] = 1;
+ return scaleMat;
+};
+
+/**
+ * To skew in any dimension (skew can only happen in 2d)
+ * @public
+ * @param {Number} a Skew value in X axis
+ * @param {Number} b Skew value in Y axis
+ * @return {Number[]} Matrix3d
+ */
+exports.skew =function(a, b) {
+ var skewMat, modifiedMat;
+ a = a ? Math.tan(a * Math.PI / 180) : 0;
+ b = b ? Math.tan(b * Math.PI / 180) : 0;
+
+ skewMat = typedArray(64);
+ modifiedMat = inputValues(skewMat, new Uint8Array([0, 5, 10, 15]));
+ skewMat[1] = b;
+ skewMat[4] = a;
+ return skewMat;
+};
+
+/**
+ * To rotate in x-axis
+ * @public
+ * @param {Number} a Rotate value in X axis
+ * @return {Number[]} Matrix3d
+ */
+exports.rotateX = function(a) {
+ var cosa, sina, rotateXMat, modifiedMat;
+ a = a ? a * Math.PI / 180 : 0;
+ cosa = Math.cos(a);
+ sina = Math.sin(a);
+
+ rotateXMat = typedArray(64);
+ modifiedMat = inputValues(rotateXMat, new Uint8Array([0, 15]));
+ rotateXMat[5] = cosa;
+ rotateXMat[6] = -sina;
+ rotateXMat[9] = sina;
+ rotateXMat[10] = cosa;
+ return rotateXMat;
+};
+
+/**
+ * To rotate in y-axis
+ * @public
+ * @param {Number} b Rotate value in Y axis
+ * @return {Number[]} Matrix3d
+ */
+exports.rotateY = function(b) {
+ var cosb, sinb, rotateYMat, modifiedMat;
+ b = b ? b * Math.PI / 180 : 0;
+ cosb = Math.cos(b);
+ sinb = Math.sin(b);
+
+ rotateYMat = typedArray(64);
+ modifiedMat = inputValues(rotateYMat, new Uint8Array([5, 15]));
+ rotateYMat[0] = cosb;
+ rotateYMat[2] = sinb;
+ rotateYMat[8] = -sinb;
+ rotateYMat[10] = cosb;
+ return rotateYMat;
+};
+
+/**
+ * To rotate in z-axis
+ * @public
+ * @param {Number} g Rotate value in Z axis
+ * @return {Number[]} Matrix3d
+ */
+exports.rotateZ = function(g) {
+ var cosg, sing, rotateZMat;
+ g = g ? g * Math.PI / 180 : 0;
+ cosg = Math.cos(g);
+ sing = Math.sin(g);
+
+ rotateZMat = typedArray(64);
+ rotateZMat[0] = cosg;
+ rotateZMat[1] = -sing;
+ rotateZMat[4] = sing;
+ rotateZMat[5] = cosg;
+ rotateZMat[15] = 1;
+ return rotateZMat;
+};
+
+/**
+ * To rotate in any dimension
+ * @public
+ * @param {Number} a Rotate value in X axis
+ * @param {Number} b Rotate value in Y axis
+ * @param {Number} g Rotate value in Z axis
+ * @return {Number[]} Matrix3d
+ */
+exports.rotate = function(a, b, g) {
+ var ca, sa, cb, sb, cg, sg, rotateMat;
+ a = a ? a * Math.PI / 180 : 0;
+ b = b ? b * Math.PI / 180 : 0;
+ g = g ? g * Math.PI / 180 : 0;
+ ca = Math.cos(a);
+ sa = Math.sin(a);
+ cb = Math.cos(b);
+ sb = Math.sin(b);
+ cg = Math.cos(g);
+ sg = Math.sin(g);
+
+ rotateMat = typedArray(64);
+ rotateMat[0] = cb * cg;
+ rotateMat[1] = ca * sg + sa * sb * cg;
+ rotateMat[2] = sa * sg - ca * sb * cg;
+ rotateMat[4] = -cb * sg;
+ rotateMat[5] = ca * cg - sa * sb * sg;
+ rotateMat[6] = sa * cg + ca * sb * sg;
+ rotateMat[8] = sb;
+ rotateMat[9] = -sa * cb;
+ rotateMat[10] = ca * cb;
+ rotateMat[15] = 1;
+ return rotateMat;
+};
+
+var matrix = exports.Matrix = {
+
+ /**
+ * To create Identity Matrix (NXN order).
+ * @public
+ * @param {Number} N Order of Identity Matrix
+ * @return {Number[][]} Identity Matrix of order N
+ */
+ identityMatrix: function(N) {
+ var i, j, row, result = [];
+ for (i = 0; i < N; i++) {
+ row = [];
+ for (j = 0; j < N; j++) {
+ if (i === j) {
+ row.push(1);
+ } else {
+ row.push(0);
+ }
+ }
+ result.push(row);
+ }
+ return result;
+ },
+ /**
+ * To multiply 2 Martix3d (4x4 order)
+ * @public
+ * @param {Number[]} m1 1st Matrix3d
+ * @param {Number[]} m2 2nd Matrix3d
+ * @return {Number[]} Resultant Matrix3d
+ */
+ multiply: function(m1, m2) {
+ var multiplyMat = typedArray(64);
+ if (m1.length !== 16 || m2.length !== 16) return;
+ multiplyMat[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2];
+ multiplyMat[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2];
+ multiplyMat[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2];
+ multiplyMat[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6];
+ multiplyMat[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6];
+ multiplyMat[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6];
+ multiplyMat[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10];
+ multiplyMat[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10];
+ multiplyMat[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10];
+ multiplyMat[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12];
+ multiplyMat[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13];
+ multiplyMat[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14];
+ multiplyMat[15] = 1;
+ return multiplyMat;
+ },
+
+ /**
+ * To multiply 2 Martix3d (n*n order)
+ * @param {Number[]} m1 1st Matrix3d
+ * @param {Number[]} m2 2nd Matrix3d
+ * @return {[type]} Resultant Matrix3d
+ */
+ multiplyN: function(m1, m2) {
+ var i, j, sum,
+ m = [],
+ l1 = m1.length,
+ l2 = m2.length;
+
+ for (i = 0; i < l1; i++) {
+ sum = 0;
+ for (j = 0; j < l2; j++) {
+ sum += m1[i][j] * m2[j];
+ }
+ m.push(sum);
+ }
+ return m;
+ },
+
+ /**
+ * To inverse matrix of order N
+ * @public
+ * @param {Number[]} matrix Matrix (NxN order)
+ * @param {Number} n Order of the matrix
+ * @return {Number[]} Inverted Matrix
+ */
+ inverseN: function(matrix, n) {
+ var i, j, k, r, t,
+ result = this.identityMatrix(n);
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++) {
+ if (i != j) {
+ r = matrix[j][i] / matrix[i][i];
+ for (k = 0; k < n; k++) {
+ matrix[j][k] -= r * matrix[i][k];
+ result[j][k] -= r * result[i][k];
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < n; i++) {
+ t = matrix[i][i];
+ for (j = 0; j < n; j++) {
+ matrix[i][j] = matrix[i][j] / t;
+ result[i][j] = result[i][j] / t;
+ }
+ }
+
+ return result;
+ },
+
+ /**
+ * Calculate matrix3d of a frame based on transformation vectors.
+ * @public
+ * @param {Number[]} trns Translate vector
+ * @param {Number[]} rot Rotate quaternion vector
+ * @param {Number[]} sc Scale vector
+ * @param {Number[]} sq Skew vector
+ * @param {Number[]} per Perspective vector
+ * @return {Number[]} Final Matrix3d for particular frame
+ */
+ recompose: function(trns, rot, sc, sq, per) {
+ var i,
+ x = rot[0],
+ y = rot[1],
+ z = rot[2],
+ w = rot[3],
+ m = identity.call(),
+ sM = identity.call(),
+ rM = identity.call();
+
+
+ // apply perspective
+ if (per) {
+ m[3] = per[0];
+ m[7] = per[1];
+ m[11] = per[2];
+ m[15] = per[3];
+ }
+
+ m[12] = trns[0];
+ m[13] = trns[1];
+ m[14] = trns[2];
+
+ // apply rotate
+ rM[0] = 1 - 2 * (y * y + z * z);
+ rM[1] = 2 * (x * y - z * w);
+ rM[2] = 2 * (x * z + y * w);
+ rM[4] = 2 * (x * y + z * w);
+ rM[5] = 1 - 2 * (x * x + z * z);
+ rM[6] = 2 * (y * z - x * w);
+ rM[8] = 2 * (x * z - y * w);
+ rM[9] = 2 * (y * z + x * w);
+ rM[10] = 1 - 2 * (x * x + y * y);
+
+ m = this.multiply(m, rM);
+
+ // apply skew
+ if (sq[2]) {
+ sM[9] = sq[2];
+ m = this.multiply(m, sM);
+ }
+
+ if (sq[1]) {
+ sM[9] = 0;
+ sM[8] = sq[1];
+ m = this.multiply(m, sM);
+ }
+
+ if (sq[0]) {
+ sM[8] = 0;
+ sM[4] = sq[0];
+ m = this.multiply(m, sM);
+ }
+
+ // apply scale
+ for (i = 0; i < 12; i += 4) {
+ m[0 + i] *= sc[0];
+ m[1 + i] *= sc[1];
+ m[2 + i] *= sc[2];
+ }
+ return m;
+ },
+
+ /**
+ * Decompose transformation vectors into various properties out of matrix3d.
+ * @public
+ * @param {Number[]} matrix Matrix3d
+ * @param {Object} ret To store various transformation properties like translate, rotate, scale, skew and perspective.
+ * @return {Boolean} true, if matrix exists else false.
+ */
+ decompose: function(matrix, ret) {
+ var i,
+ tV = [],
+ rV = [],
+ pV = [],
+ skV = [],
+ scV = [],
+ row = [],
+ pdum3 = [];
+
+ if (matrix[15] === 0) return false;
+
+ for (i = 0; i < 16; i++)
+ matrix[i] /= matrix[15];
+
+ //TODO: decompose perspective
+ pV = [0, 0, 0, 0];
+
+ for (i = 0; i < 3; i++)
+ tV[i] = matrix[12 + i];
+
+ for (i = 0; i < 12; i += 4) {
+ row.push([
+ matrix[0 + i],
+ matrix[1 + i],
+ matrix[2 + i]
+ ]);
+ }
+
+ scV[0] = vector.length(row[0]);
+ row[0] = quaternion.normalize(row[0]);
+ skV[0] = vector.dot(row[0], row[1]);
+ row[1] = vector.combine(row[1], row[0], 1.0, -skV[0]);
+
+ scV[1] = vector.length(row[1]);
+ row[1] = quaternion.normalize(row[1]);
+ skV[0] /= scV[1];
+
+ // Compute XZ and YZ shears, orthogonalized 3rd row
+ skV[1] = vector.dot(row[0], row[2]);
+ row[2] = vector.combine(row[2], row[0], 1.0, -skV[1]);
+ skV[2] = vector.dot(row[1], row[2]);
+ row[2] = vector.combine(row[2], row[1], 1.0, -skV[2]);
+
+ // Next, get Z scale and normalize 3rd row.
+ scV[2] = vector.length(row[2]);
+ row[2] = quaternion.normalize(row[2]);
+ skV[1] /= scV[2];
+ skV[2] /= scV[2];
+
+ pdum3 = vector.cross(row[1], row[2]);
+ if (vector.dot(row[0], pdum3) < 0) {
+ for (i = 0; i < 3; i++) {
+ scV[i] *= -1;
+ row[i][0] *= -1;
+ row[i][1] *= -1;
+ row[i][2] *= -1;
+ }
+ }
+
+ rV[0] = 0.5 * Math.sqrt(Math.max(1 + row[0][0] - row[1][1] - row[2][2], 0));
+ rV[1] = 0.5 * Math.sqrt(Math.max(1 - row[0][0] + row[1][1] - row[2][2], 0));
+ rV[2] = 0.5 * Math.sqrt(Math.max(1 - row[0][0] - row[1][1] + row[2][2], 0));
+ rV[3] = 0.5 * Math.sqrt(Math.max(1 + row[0][0] + row[1][1] + row[2][2], 0));
+
+ if (row[2][1] > row[1][2]) rV[0] = -rV[0];
+ if (row[0][2] > row[2][0]) rV[1] = -rV[1];
+ if (row[1][0] > row[0][1]) rV[2] = -rV[2];
+
+ ret.translate = tV;
+ ret.rotate = rV;
+ ret.scale = scV;
+ ret.skew = skV;
+ ret.perspective = pV;
+ return true;
+ },
+
+ /**
+ * Decompose transformation matrix2d from matrix3d.
+ * @public
+ * @param {Number[]} matrix Matrix3d
+ * @param {Object} ret To store various transformation properties like translate, angle and matrix.
+ * @return {Boolean} ret To store various transformation properties like translate, angle and matrix.
+ */
+ decompose2D: function(m, ret) {
+ var scale = [],
+ matrix = [],
+ row0x = m[0],
+ row0y = m[1],
+ row1x = m[4],
+ row1y = m[5],
+ det, angle, sn, cs,
+ m11, m12, m21, m22;
+
+ ret = ret || {};
+ scale = [
+ Math.sqrt(row0x * row0x + row0y * row0y),
+ Math.sqrt(row1x * row1x + row1y * row1y)
+ ];
+
+ // If determinant is negative, one axis was flipped.
+ det = row0x * row1y - row0y * row1x;
+ if (det < 0)
+ // Flip axis with minimum unit vector dot product.
+ if (row0x < row1y)
+ scale[0] = -scale[0];
+ else
+ scale[1] = -scale[1];
+
+ // Renormalize matrix to remove scale.
+ if (scale[0]) {
+ row0x *= 1 / scale[0];
+ row0y *= 1 / scale[0];
+ }
+
+ if (scale[1]) {
+ row1x *= 1 / scale[1];
+ row1y *= 1 / scale[1];
+ }
+ ret.scale = scale;
+
+
+ // Compute rotation and renormalize matrix.
+ angle = Math.atan2(row0y, row0x);
+
+ if (angle) {
+ sn = -row0y;
+ cs = row0x;
+ m11 = row0x;
+ m12 = row0y;
+ m21 = row1x;
+ m22 = row1y;
+ row0x = cs * m11 + sn * m21;
+ row0y = cs * m12 + sn * m22;
+ row1x = -sn * m11 + cs * m21;
+ row1y = -sn * m12 + cs * m22;
+ }
+
+ // Rotate(-angle) = [cos(angle), sin(angle), -sin(angle), cos(angle)]
+ // = [row0x, -row0y, row0y, row0x]
+ // Thanks to the normalization above.
+ matrix[0] = row0x;
+ matrix[1] = row0y;
+ matrix[2] = row1x;
+ matrix[3] = row1y;
+ matrix[4] = m[12];
+ matrix[5] = m[13];
+ ret.matrix2D = matrix;
+
+ // Convert into degrees because our rotation functions expect it.
+ ret.angle = angle * 180 / Math.PI;
+
+ return ret;
+ },
+
+ /**
+ * Convert Matrix3d array to Matrix3d String
+ * @public
+ * @param {Number[]} m Matrix3d Array
+ * @return {String} Matrix3d String
+ */
+ toString: function(m) {
+ var i, ms = m.length > 10 ? 'matrix3d(' : 'matrix(';
+ for (i = 0; i < m.length - 1; i++) {
+ ms += (m[i] < 0.000001 && m[i] > -0.000001) ? '0,' : m[i] + ',';
+ }
+ ms += m[m.length - 1] + ')';
+ return ms;
+ }
+};
+
+var vector = exports.Vector = {
+ /**
+ * Length of a vector
+ * @param {Number[]} v - vector
+ * @return {Number} resultant length
+ * @public
+ */
+ length: function(v) {
+ return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ },
+
+ /**
+ * Divides vector with a scalar value.
+ * @param {Number[]} v - vector
+ * @param {Number} s - scalar value to divide
+ * @return {Number[]} resultant vector
+ * @public
+ */
+ divide: function(v, s) {
+ var divideVector = new Float32Array([v[0] / s, v[1] / s, v[2] / s]);
+ return divideVector;
+ },
+
+ /**
+ * Dot product of 3D vectors
+ * @param {Number[]} v1 - vector
+ * @param {Number[]} v2 - vector
+ * @return {Number} resultant dot product
+ * @public
+ */
+ dot: function(v1, v2) {
+ return (v1[0] * v2[0]) + (v1[1] * v2[1]) + (v1[2] * v2[2]) + (v1[3] !== undefined && v2[3] !== undefined ? (v1[3] * v2[3]) : 0);
+ },
+
+ /**
+ * Cross product of two vectors
+ * @param {Number[]} v1 - vector
+ * @param {Number[]} v2 - vector
+ * @return {Number[]} resultant cross product
+ * @public
+ */
+ cross: function(v1, v2) {
+ var crossProdMat = new Float32Array([v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0]]);
+ return crossProdMat;
+ },
+
+ /**
+ * Combine scalar values with two vectors.
+ * Required during parsing scaler values matrix.
+ * @param {Number[]} a - first vector
+ * @param {Number[]} b - second vector
+ * @param {Number[]} ascl - first vector scalar
+ * @param {Number[]} bscl - second vector scalar
+ * @return {Number[]} resultant vector
+ * @public
+ */
+ combine: function(a, b, ascl, bscl) {
+ var combineMat = new Float32Array([(ascl * a[0]) + (bscl * b[0]), (ascl * a[1]) + (bscl * b[1]), (ascl * a[2]) + (bscl * b[2])]);
+ return combineMat;
+
+ }
+};
+
+var quaternion = exports.Quaternion = {
+ /**
+ * Gives the direction of motion from one vector to other.
+ * Returns true if moving towards positive direction.
+ * @param {Number[]} q1 - quant
+ * @param {Number[]} q2 - quant
+ * @return {boolean} true if positive, false otherwise.
+ * @public
+ */
+ direction: function(q1, q2) {
+ return (q1[0] - q2[0]) < 0 || (q1[1] - q2[1]) < 0 || (q1[2] - q2[2]) < 0;
+ },
+
+ /**
+ * Dot product of 3D quanterion
+ * @param {Number[]} q1 - quanterion
+ * @param {Number[]} q2 - quanterion
+ * @return {Number} resultant dot product
+ * @public
+ */
+ quantDot: function(q1, q2) {
+ return (q1[0] * q2[0]) + (q1[1] * q2[1]) + (q1[2] * q2[2]) + (q1[3] * q2[3]);
+ },
+
+ /**
+ * Multiplication of two quanternions
+ * @param {Number[]} q1 quanternion
+ * @param {Number[]} q2 quanternion
+ * @return {Number[]} quanternion
+ */
+ multiplication: function(q1, q2) {
+ return [q2[0] * q1[0] - q2[1] * q1[1] - q2[2] * q1[2] - q2[3] * q1[3],
+ q2[0] * q1[1] + q2[1] * q1[0] - q2[2] * q1[3] + q2[3] * q1[2],
+ q2[0] * q1[2] + q2[1] * q1[3] + q2[2] * q1[0] - q2[3] * q1[1],
+ q2[0] * q1[3] - q2[1] * q1[2] + q2[2] * q1[1] + q2[3] * q1[0]];
+ },
+
+ /**
+ * Normalizing a vector is obtaining another unit vector in the same direction.
+ * To normalize a vector, divide the vector by its magnitude.
+ * @param {Number[]} q1 - quanterion
+ * @return {Number[]} resultant quanterion
+ * @public
+ */
+ normalize: function(q) {
+ return vector.divide(q, vector.length(q));
+ },
+
+ /**
+ * Converts a rotation vector to a quaternion vector.
+ * @param {Number[]} v - vector
+ * @return {Number[]} resultant quaternion
+ * @public
+ */
+ toQuant: function(v) {
+ if (!v) v = [];
+ var p = parseFloat(v[1] || 0) * Math.PI / 360,
+ y = parseFloat(v[2] || 0) * Math.PI / 360,
+ r = parseFloat(v[0] || 0) * Math.PI / 360,
+ c1 = Math.cos(p),
+ c2 = Math.cos(y),
+ c3 = Math.cos(r),
+ s1 = Math.sin(p),
+ s2 = Math.sin(y),
+ s3 = Math.sin(r),
+ q;
+
+ q = new Float32Array([
+ Math.round((s1 * s2 * c3 + c1 * c2 * s3) * 100000) / 100000,
+ Math.round((s1 * c2 * c3 + c1 * s2 * s3) * 100000) / 100000,
+ Math.round((c1 * s2 * c3 - s1 * c2 * s3) * 100000) / 100000,
+ Math.round((c1 * c2 * c3 - s1 * s2 * s3) * 100000) / 100000
+ ]);
+
+ return q;
+ }
+ //TODO: Acheive the same fucntionality for other 11 choices XYX, XZX, XZY, YXY, YXZ, YZX, YZY, ZXY, ZXZ, ZYX, ZYZ
+};
\ No newline at end of file
diff --git a/src/AnimationSupport/Tween.js b/src/tween.js
similarity index 72%
rename from src/AnimationSupport/Tween.js
rename to src/tween.js
index d4319771f..bfbed0aea 100644
--- a/src/AnimationSupport/Tween.js
+++ b/src/tween.js
@@ -1,20 +1,18 @@
require('enyo');
var
- frame = require('./Frame'),
- Easings = require('./Easings'),
- Vector = require('./Vector'),
- Matrix = require('./Matrix'),
- utils = require('../utils');
+ dom = require('./dom'),
+ utils = require('./utils'),
+ transform = require('./transform');
-var fn, state, ease, points, path, oldState, newState, node, matrix, cState = [];
+var fn, state, ease, points, path, oldState, newState, node, matrix, cState = [], domCSS = {};
/**
* Tween is a module responsible for creating intermediate frames for an animation.
* The responsibilities of this module is to;
* - Interpolating current state of character.
* - Update DOM based on current state, using matrix for tranform and styles for others.
*
- * @module enyo/AnimationSupport/Tween
+ * @module enyo/tween
*/
module.exports = {
@@ -24,7 +22,7 @@ module.exports = {
init: function (actor, pose, initial) {
if (!(actor && pose && pose.animate)) return;
node = actor.hasNode();
- utils.mixin(pose, frame.getComputedProperty(node, pose.animate, initial || actor.currentState));
+ utils.mixin(pose, dom.getAnimatedProperty(node, pose.animate, initial || actor.currentState));
actor.currentState = pose.currentState;
return pose;
},
@@ -35,14 +33,16 @@ module.exports = {
* @param {Object} pose - Current behavior in the animation (at a given time)
* @param {Number} t - Fraction which represents the animation (between 0 to 1)
* @param {Number} d - Duration of the current pose
- * @memberOf module:enyo/AnimationSupport/Tween
+ * @memberOf module:enyo/tween
* @private
*/
step: function(actor, pose, t, d) {
if (!(actor && pose && pose.animate)) return;
- if (t<0) t=0;
- if (t>1) t=1;
+ t = t < 0 ? 0 : t;
+ t = t > 1 ? 1 : t;
+
var k;
+ domCSS = {};
node = actor.hasNode();
state = actor.currentState = actor.currentState || pose.currentState || {};
points = pose.controlPoints = pose.controlPoints || {};
@@ -51,17 +51,16 @@ module.exports = {
if (pose.props) {
for (k in pose.props) {
- if (!pose._endAnim[k]) {
+ if (k === 'delay' || k === 'duration' || k === 'ease' || !pose._endAnim[k]) {
continue;
}
cState = utils.clone(state[k] || []);
- newState = utils.clone(pose._endAnim[k]);
- oldState = utils.clone(pose._startAnim[k]);
+ newState = utils.cloneArray(pose._endAnim[k]);
+ oldState = utils.cloneArray(pose._startAnim[k]);
if (ease && (typeof ease !== 'function')) {
- if (k == 'rotate') {
- newState = Vector.toQuant(newState);
+ if (k === 'rotate') {
points[k] = points[k] ||
this.bezierSPoints(ease, oldState, newState, pose.props[k], points[k]);
fn = this.bezierSpline;
@@ -72,18 +71,12 @@ module.exports = {
}
cState = fn.call(this, t, points[k], cState);
} else {
- if (k == 'rotate') {
- newState = Vector.toQuant(newState);
- fn = this.slerp;
- } else {
- fn = this.lerp;
- }
+ fn = (k === 'rotate') ? this.slerp : this.lerp;
cState = fn.call(this, oldState, newState, ease(t, d), cState);
}
- if (!frame.isTransform(k)) {
-
- frame.setProperty(actor, k, cState);
+ if (!utils.isTransform(k)) {
+ domCSS = utils.toPropertyValue(k, cState, domCSS);
}
state[k] = cState;
}
@@ -96,16 +89,24 @@ module.exports = {
this.traversePath(t, path, state.translate);
}
- matrix = frame.recomposeMatrix(
+ matrix = transform.Matrix.recompose(
state.translate,
state.rotate,
state.scale,
state.skew,
state.perspective
);
- frame.accelerate(actor, matrix);
state.matrix = matrix;
- pose.currentState = state;
+ actor.currentState = pose.currentState = state;
+ domCSS = dom.toTransformValue(matrix, domCSS);
+
+ actor.addStyles(domCSS);
+ },
+
+ halt: function (actor, pose) {
+ var matrix = actor.currentState && actor.currentState.matrix;
+ pose = frame.decompose2DMatrix(matrix, pose);
+ frame.accelerate(actor, pose.matrix2D);
},
/**
@@ -157,12 +158,12 @@ module.exports = {
var a,
b,
theta,
- dot = Vector.quantDot(qA, qB),
+ dot = transform.Quaternion.quantDot(qA, qB),
l = qA.length;
dot = Math.min(Math.max(dot, -1.0), 1.0);
if (dot == 1.0) {
- qR = frame.copy(qA);
+ qR = utils.clone(qA);
return qR;
}
theta = Math.acos(dot);
@@ -192,7 +193,7 @@ module.exports = {
lastIndex = (c - 1),
startPoint = points[0],
endPoint = points[lastIndex],
- values = Easings.getBezierValues(t, lastIndex);
+ values = this.getBezierValues(t, lastIndex);
for (i = 0; i < l; i++) {
vR[i] = 0;
@@ -231,17 +232,21 @@ module.exports = {
for (var key in easeObj) {
t = parseFloat(key) / 100;
a = parseFloat(easeObj[key]) / 100;
- bValues = Easings.getBezierValues(t, order);
+ bValues = this.getBezierValues(t, order);
bValues.shift();
m1.push(a - bValues.pop());
m2.push(bValues);
}
- m3 = Matrix.inverseN(m2, bValues.length);
- m4 = Matrix.multiplyN(m3, m1);
+ m3 = transform.Matrix.inverseN(m2, bValues.length);
+ m4 = transform.Matrix.multiplyN(m3, m1);
l = m4.length;
for (var i = 0; i < l; i++) {
- points.push([m4[i], m4[i], m4[i]]);
+ var pValues = [];
+ for( var j = 0; j < endPoint.length; j++) {
+ pValues.push(m4[i]);
+ }
+ points.push(pValues);
}
points.push(endPoint);
@@ -264,7 +269,7 @@ module.exports = {
c = path.length,
l = path[0].length,
lastIndex = (c - 1),
- values = Easings.getBezierValues(t, lastIndex);
+ values = this.getBezierValues(t, lastIndex);
for (i = 0; i < l; i++) {
vR[i] = 0;
@@ -290,26 +295,24 @@ module.exports = {
var time = [0],
quats = [startQuat];
- var t, a, q, n, _a, aI, bN,
- eD = frame.parseValue(endPoint);
+ var a, n, _a, aI, bN, eP,
+ eD = utils.stringToMatrix(endPoint);
splinePoints = splinePoints || {};
- quats.push(startQuat);
- time.push(0);
if (Object.keys(ease).length > 0) {
for (var key in ease) {
- t = parseFloat(key) / 100;
- a = parseFloat(ease[key]);
- eD.pop(); // remove angle from end point.
- eD[eD.length] = a;
- q = Vector.toQuant(frame.copy(eD));
- quats.push(q);
- time.push(t);
+ eP = utils.clone(eD);
+ a = parseFloat(ease[key]) / 100;
+ for (var i in eP) {
+ eP[i] *= a;
+ }
+ quats.push(transform.Quaternion.toQuant(eP));
+ time.push(parseFloat(key) / 100);
}
quats.push(endQuat);
time.push(1);
n = quats.length - 1;
- ai = this.slerp(startQuat, endQuat, 0);
+ aI = this.slerp(startQuat, endQuat, 0);
splinePoints[0] = [quats[0], aI, aI, quats[1]];
for (var i = 0, j = 1; i < n; i++, j++) {
if (i === 0) {
@@ -361,5 +364,67 @@ module.exports = {
} else
vR = this.slerp(pts[0], pts[1], t);
return vR;
+ },
+
+ /**
+ * This function returns the coefficents based on the order and the current position
+ * @private
+ * @param {number} n - order
+ * @param {number} k - current position
+ * @return {object} - coefficients
+ */
+ getCoeff: function(n, k) {
+ n = parseInt(n, 10);
+ k = parseInt(k, 10);
+ // Credits
+ // https://math.stackexchange.com/questions/202554/how-do-i-compute-binomial-coefficients-efficiently#answer-927064
+ if (isNaN(n) || isNaN(k))
+ return void 0;
+ if ((n < 0) || (k < 0))
+ return void 0;
+ if (k > n)
+ return void 0;
+ if (k === 0)
+ return 1;
+ if (k === n)
+ return 1;
+ if (k > n / 2)
+ return this.getCoeff(n, n - k);
+
+ return n * this.getCoeff(n - 1, k - 1) / k;
+ },
+
+ /**
+ * Function to get the bezier coeffients based on the time and order
+ * @public
+ * @param {number} t - time
+ * @param {number} n - order
+ * @return {object} - bezier coefficients
+ */
+ getBezierValues: function(t, n) {
+ t = parseFloat(t, 10),
+ n = parseInt(n, 10);
+
+ if (isNaN(t) || isNaN(n))
+ return void 0;
+ if ((t < 0) || (n < 0))
+ return void 0;
+ if (t > 1)
+ return void 0;
+
+ var c,
+ values = [],
+
+ x = (1 - t),
+ y = t;
+ //
+ // Binomial theorem to expand (x+y)^n
+ //
+ for (var k = 0; k <= n; k++) {
+ c = this.getCoeff(n, k) * Math.pow(x, (n - k)) * Math.pow(y, k);
+ values.push(c);
+ }
+
+ return values;
}
};
\ No newline at end of file
diff --git a/src/utils.js b/src/utils.js
index c4204fc9d..2d0a44026 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,5 +1,7 @@
require('enyo');
+var transform = require('./transform');
+
/**
* A collection of utilities
* @module enyo/utils
@@ -143,6 +145,30 @@ var exists = exports.exists = function (target) {
var uidCounter = 0;
+var
+ BORDER = {
+ 'border-radius': 1, 'border-image-slice': 1,
+ 'border-top-left-radius': 1, 'border-top-right-radius': 1, 'border-bottom-left-radius': 1, 'border-bottom-right-radius': 1
+ },
+ COLOR = {
+ 'color': 1, 'background-color': 1, 'fill': 1, 'flood-color': 1,'lighting-color': 1, 'stop-color': 1, 'outline-color': 1,
+ 'border-color': 1, 'border-top-color': 1, 'border-left-color': 1, 'border-right-color': 1, 'border-bottom-color': 1
+ },
+ INT_UNIT = {
+ 'z-index': 1
+ },
+ SHADOW = {
+ 'box-shadow': 1, 'text-shadow': 1
+ },
+ OPACITY = {
+ 'opacity': 1, 'flood-opacity': 1, 'stop-opacity': 1, 'fill-opacity': 1, 'stroke-opacity': 1
+ },
+ TRANSFORM = {
+ translate: 1, translateX: 1, translateY: 1, translateZ: 1, rotate: 1, rotateX: 1, rotateY: 1, rotateZ: 1,
+ skew: 1, skewX: 1, skewY: 1, scale: 1, scaleX: 1, scaleY: 1, scaleZ: 1, perspective: 1
+ };
+
+
/**
* Creates a unique identifier (with an optional prefix) and returns the identifier as a string.
*
@@ -233,8 +259,7 @@ var isArray = exports.isArray = Array.isArray || function (it) {
* @public
*/
exports.isObject = Object.isObject || function (it) {
- // explicit null/undefined check for IE8 compatibility
- return (it != null) && (toString.call(it) === '[object Object]');
+ return toString.call(it) === '[object Object]';
};
/**
@@ -369,7 +394,8 @@ exports.asyncMethod = function (scope, method) {
* arguments `args` ([Array]{@glossary Array}), if the object and method exist.
*
* @example
-* enyo.call(myWorkObject, 'doWork', [3, 'foo']);
+* utils = require('enyo/utils');
+* utils.call(myWorkObject, 'doWork', [3, 'foo']);
*
* @param {Object} scope - The `this` context for the method.
* @param {(Function|String)} method - A Function or the name of a method to bind.
@@ -736,23 +762,6 @@ Object.keys = Object.keys || function (obj) {
results.push(prop);
}
}
- // *sigh* IE 8
- if (!({toString: null}).propertyIsEnumerable('toString')) {
- var dontEnums = [
- 'toString',
- 'toLocaleString',
- 'valueOf',
- 'hasOwnProperty',
- 'isPrototypeOf',
- 'propertyIsEnumerable',
- 'constructor'
- ];
- for (var i = 0, p; (p = dontEnums[i]); i++) {
- if (hop.call(obj, p)) {
- results.push(p);
- }
- }
- }
return results;
};
@@ -999,60 +1008,6 @@ exports.values = function (obj) {
// Array Functions
// ----------------------------------
-/**
-* Because our older API parameters are not consistent with other array API methods, and also
-* because only [IE8 lacks integrated support]{@glossary polyfill} for
-* [indexOf()]{@linkcode external:Array.indexOf}, we ensure it is defined (only IE8) and advise,
-* moving forward, that the built-in method be used. But to preserve our original API, it will
-* simply call this method, knowing it exists.
-*
-* @private
-*/
-Array.prototype.indexOf = Array.prototype.indexOf || function (el, offset) {
- var len = this.length >>> 0;
-
- offset = +offset || 0;
-
- if (Math.abs(offset) === Infinity) offset = 0;
- if (offset < 0) offset += len;
- if (offset < 0) offset = 0;
-
- for (; offset < len; ++offset) {
- if (this[offset] === el) return offset;
- }
-
- return -1;
-};
-
-/**
-* Because our older API parameters are not consistent with other array API methods, and also
-* because only [IE8 lacks integrated support]{@glossary polyfill} for
-* [lastIndexOf()]{@glossary Array.lastIndexOf} we ensure it is defined (only IE8) and
-* advise, moving forward, that the built-in method be used. But to preserve our original API, it
-* will simply call this method, knowing it exists.
-*
-* @private
-*/
-Array.prototype.lastIndexOf = Array.prototype.lastIndexOf || function (el, offset) {
- var array = Object(this)
- , len = array.length >>> 0;
-
- if (len === 0) return -1;
-
- if (offset !== undefined) {
- offset = Number(offset);
- if (Math.abs(offset) > len) offset = len;
- if (offset === Infinity || offset === -Infinity) offset = len;
- if (offset < 0) offset += len;
- } else offset = len;
-
- for (; offset > -1; --offset) {
- if (array[offset] === el) return offset;
- }
-
- return -1;
-};
-
/**
* A [polyfill]{@glossary polyfill} for platforms that don't support
* [Array.findIndex()]{@glossary Array.findIndex}.
@@ -1074,38 +1029,6 @@ Array.prototype.find = Array.prototype.find || function (fn, ctx) {
}
};
-/**
-* A [polyfill]{@glossary polyfill} for platforms that don't support
-* [Array.forEach()]{@glossary Array.forEach}.
-*/
-Array.prototype.forEach = Array.prototype.forEach || function (fn, ctx) {
- for (var i=0, len=this.length >>> 0; i>> 0; i>> 0; i