You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by gm...@apache.org on 2014/07/11 18:23:29 UTC

svn commit: r1609737 [10/18] - in /roller/trunk/app/src/main/webapp: WEB-INF/jsps/editor/ WEB-INF/jsps/tiles/ roller-ui/yui3/arraylist/ roller-ui/yui3/assets/ roller-ui/yui3/assets/skins/ roller-ui/yui3/assets/skins/sam/ roller-ui/yui3/async-queue/ rol...

Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/features/features.js
URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/features/features.js?rev=1609737&view=auto
==============================================================================
--- roller/trunk/app/src/main/webapp/roller-ui/yui3/features/features.js (added)
+++ roller/trunk/app/src/main/webapp/roller-ui/yui3/features/features.js Fri Jul 11 16:23:25 2014
@@ -0,0 +1,412 @@
+/*
+YUI 3.17.2 (build 9c3c78e)
+Copyright 2014 Yahoo! Inc. All rights reserved.
+Licensed under the BSD License.
+http://yuilibrary.com/license/
+*/
+
+YUI.add('features', function (Y, NAME) {
+
+var feature_tests = {};
+
+/**
+Contains the core of YUI's feature test architecture.
+@module features
+*/
+
+/**
+* Feature detection
+* @class Features
+* @static
+*/
+
+Y.mix(Y.namespace('Features'), {
+
+    /**
+    * Object hash of all registered feature tests
+    * @property tests
+    * @type Object
+    */
+    tests: feature_tests,
+
+    /**
+    * Add a test to the system
+    *
+    *   ```
+    *   Y.Features.add("load", "1", {});
+    *   ```
+    *
+    * @method add
+    * @param {String} cat The category, right now only 'load' is supported
+    * @param {String} name The number sequence of the test, how it's reported in the URL or config: 1, 2, 3
+    * @param {Object} o Object containing test properties
+    * @param {String} o.name The name of the test
+    * @param {Function} o.test The test function to execute, the only argument to the function is the `Y` instance
+    * @param {String} o.trigger The module that triggers this test.
+    */
+    add: function(cat, name, o) {
+        feature_tests[cat] = feature_tests[cat] || {};
+        feature_tests[cat][name] = o;
+    },
+    /**
+    * Execute all tests of a given category and return the serialized results
+    *
+    *   ```
+    *   caps=1:1;2:1;3:0
+    *   ```
+    * @method all
+    * @param {String} cat The category to execute
+    * @param {Array} args The arguments to pass to the test function
+    * @return {String} A semi-colon separated string of tests and their success/failure: 1:1;2:1;3:0
+    */
+    all: function(cat, args) {
+        var cat_o = feature_tests[cat],
+            // results = {};
+            result = [];
+        if (cat_o) {
+            Y.Object.each(cat_o, function(v, k) {
+                result.push(k + ':' + (Y.Features.test(cat, k, args) ? 1 : 0));
+            });
+        }
+
+        return (result.length) ? result.join(';') : '';
+    },
+    /**
+    * Run a specific test and return a Boolean response.
+    *
+    *   ```
+    *   Y.Features.test("load", "1");
+    *   ```
+    *
+    * @method test
+    * @param {String} cat The category of the test to run
+    * @param {String} name The name of the test to run
+    * @param {Array} args The arguments to pass to the test function
+    * @return {Boolean} True or false if the test passed/failed.
+    */
+    test: function(cat, name, args) {
+        args = args || [];
+        var result, ua, test,
+            cat_o = feature_tests[cat],
+            feature = cat_o && cat_o[name];
+
+        if (!feature) {
+        } else {
+
+            result = feature.result;
+
+            if (Y.Lang.isUndefined(result)) {
+
+                ua = feature.ua;
+                if (ua) {
+                    result = (Y.UA[ua]);
+                }
+
+                test = feature.test;
+                if (test && ((!ua) || result)) {
+                    result = test.apply(Y, args);
+                }
+
+                feature.result = result;
+            }
+        }
+
+        return result;
+    }
+});
+
+// Y.Features.add("load", "1", {});
+// Y.Features.test("load", "1");
+// caps=1:1;2:0;3:1;
+
+/* This file is auto-generated by (yogi.js loader --mix --yes) */
+/*jshint maxlen:900, eqeqeq: false */
+var add = Y.Features.add;
+// app-transitions-native
+add('load', '0', {
+    "name": "app-transitions-native",
+    "test": function (Y) {
+    var doc  = Y.config.doc,
+        node = doc ? doc.documentElement : null;
+
+    if (node && node.style) {
+        return ('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style);
+    }
+
+    return false;
+},
+    "trigger": "app-transitions"
+});
+// autocomplete-list-keys
+add('load', '1', {
+    "name": "autocomplete-list-keys",
+    "test": function (Y) {
+    // Only add keyboard support to autocomplete-list if this doesn't appear to
+    // be an iOS or Android-based mobile device.
+    //
+    // There's currently no feasible way to actually detect whether a device has
+    // a hardware keyboard, so this sniff will have to do. It can easily be
+    // overridden by manually loading the autocomplete-list-keys module.
+    //
+    // Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari
+    // doesn't fire the keyboard events used by AutoCompleteList, so there's
+    // no point loading the -keys module even when a bluetooth keyboard may be
+    // available.
+    return !(Y.UA.ios || Y.UA.android);
+},
+    "trigger": "autocomplete-list"
+});
+// dd-gestures
+add('load', '2', {
+    "name": "dd-gestures",
+    "trigger": "dd-drag",
+    "ua": "touchEnabled"
+});
+// dom-style-ie
+add('load', '3', {
+    "name": "dom-style-ie",
+    "test": function (Y) {
+
+    var testFeature = Y.Features.test,
+        addFeature = Y.Features.add,
+        WINDOW = Y.config.win,
+        DOCUMENT = Y.config.doc,
+        DOCUMENT_ELEMENT = 'documentElement',
+        ret = false;
+
+    addFeature('style', 'computedStyle', {
+        test: function() {
+            return WINDOW && 'getComputedStyle' in WINDOW;
+        }
+    });
+
+    addFeature('style', 'opacity', {
+        test: function() {
+            return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style;
+        }
+    });
+
+    ret =  (!testFeature('style', 'opacity') &&
+            !testFeature('style', 'computedStyle'));
+
+    return ret;
+},
+    "trigger": "dom-style"
+});
+// editor-para-ie
+add('load', '4', {
+    "name": "editor-para-ie",
+    "trigger": "editor-para",
+    "ua": "ie",
+    "when": "instead"
+});
+// event-base-ie
+add('load', '5', {
+    "name": "event-base-ie",
+    "test": function(Y) {
+    var imp = Y.config.doc && Y.config.doc.implementation;
+    return (imp && (!imp.hasFeature('Events', '2.0')));
+},
+    "trigger": "node-base"
+});
+// graphics-canvas
+add('load', '6', {
+    "name": "graphics-canvas",
+    "test": function(Y) {
+    var DOCUMENT = Y.config.doc,
+        useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas",
+		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
+        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
+    return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d"));
+},
+    "trigger": "graphics"
+});
+// graphics-canvas-default
+add('load', '7', {
+    "name": "graphics-canvas-default",
+    "test": function(Y) {
+    var DOCUMENT = Y.config.doc,
+        useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas",
+		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
+        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
+    return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d"));
+},
+    "trigger": "graphics"
+});
+// graphics-svg
+add('load', '8', {
+    "name": "graphics-svg",
+    "test": function(Y) {
+    var DOCUMENT = Y.config.doc,
+        useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas",
+		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
+        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
+    
+    return svg && (useSVG || !canvas);
+},
+    "trigger": "graphics"
+});
+// graphics-svg-default
+add('load', '9', {
+    "name": "graphics-svg-default",
+    "test": function(Y) {
+    var DOCUMENT = Y.config.doc,
+        useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas",
+		canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
+        svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
+    
+    return svg && (useSVG || !canvas);
+},
+    "trigger": "graphics"
+});
+// graphics-vml
+add('load', '10', {
+    "name": "graphics-vml",
+    "test": function(Y) {
+    var DOCUMENT = Y.config.doc,
+		canvas = DOCUMENT && DOCUMENT.createElement("canvas");
+    return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
+},
+    "trigger": "graphics"
+});
+// graphics-vml-default
+add('load', '11', {
+    "name": "graphics-vml-default",
+    "test": function(Y) {
+    var DOCUMENT = Y.config.doc,
+		canvas = DOCUMENT && DOCUMENT.createElement("canvas");
+    return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
+},
+    "trigger": "graphics"
+});
+// history-hash-ie
+add('load', '12', {
+    "name": "history-hash-ie",
+    "test": function (Y) {
+    var docMode = Y.config.doc && Y.config.doc.documentMode;
+
+    return Y.UA.ie && (!('onhashchange' in Y.config.win) ||
+            !docMode || docMode < 8);
+},
+    "trigger": "history-hash"
+});
+// io-nodejs
+add('load', '13', {
+    "name": "io-nodejs",
+    "trigger": "io-base",
+    "ua": "nodejs"
+});
+// json-parse-shim
+add('load', '14', {
+    "name": "json-parse-shim",
+    "test": function (Y) {
+    var _JSON = Y.config.global.JSON,
+        Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON,
+        nativeSupport = Y.config.useNativeJSONParse !== false && !!Native;
+
+    function workingNative( k, v ) {
+        return k === "ok" ? true : v;
+    }
+    
+    // Double check basic functionality.  This is mainly to catch early broken
+    // implementations of the JSON API in Firefox 3.1 beta1 and beta2
+    if ( nativeSupport ) {
+        try {
+            nativeSupport = ( Native.parse( '{"ok":false}', workingNative ) ).ok;
+        }
+        catch ( e ) {
+            nativeSupport = false;
+        }
+    }
+
+    return !nativeSupport;
+},
+    "trigger": "json-parse"
+});
+// json-stringify-shim
+add('load', '15', {
+    "name": "json-stringify-shim",
+    "test": function (Y) {
+    var _JSON = Y.config.global.JSON,
+        Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON,
+        nativeSupport = Y.config.useNativeJSONStringify !== false && !!Native;
+
+    // Double check basic native functionality.  This is primarily to catch broken
+    // early JSON API implementations in Firefox 3.1 beta1 and beta2.
+    if ( nativeSupport ) {
+        try {
+            nativeSupport = ( '0' === Native.stringify(0) );
+        } catch ( e ) {
+            nativeSupport = false;
+        }
+    }
+
+
+    return !nativeSupport;
+},
+    "trigger": "json-stringify"
+});
+// scrollview-base-ie
+add('load', '16', {
+    "name": "scrollview-base-ie",
+    "trigger": "scrollview-base",
+    "ua": "ie"
+});
+// selector-css2
+add('load', '17', {
+    "name": "selector-css2",
+    "test": function (Y) {
+    var DOCUMENT = Y.config.doc,
+        ret = DOCUMENT && !('querySelectorAll' in DOCUMENT);
+
+    return ret;
+},
+    "trigger": "selector"
+});
+// transition-timer
+add('load', '18', {
+    "name": "transition-timer",
+    "test": function (Y) {
+    var DOCUMENT = Y.config.doc,
+        node = (DOCUMENT) ? DOCUMENT.documentElement: null,
+        ret = true;
+
+    if (node && node.style) {
+        ret = !('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style);
+    }
+
+    return ret;
+},
+    "trigger": "transition"
+});
+// widget-base-ie
+add('load', '19', {
+    "name": "widget-base-ie",
+    "trigger": "widget-base",
+    "ua": "ie"
+});
+// yql-jsonp
+add('load', '20', {
+    "name": "yql-jsonp",
+    "test": function (Y) {
+    /* Only load the JSONP module when not in nodejs or winjs
+    TODO Make the winjs module a CORS module
+    */
+    return (!Y.UA.nodejs && !Y.UA.winjs);
+},
+    "trigger": "yql"
+});
+// yql-nodejs
+add('load', '21', {
+    "name": "yql-nodejs",
+    "trigger": "yql",
+    "ua": "nodejs"
+});
+// yql-winjs
+add('load', '22', {
+    "name": "yql-winjs",
+    "trigger": "yql",
+    "ua": "winjs"
+});
+
+}, '3.17.2', {"requires": ["yui-base"]});

Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/gesture-simulate/gesture-simulate-min.js
URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/gesture-simulate/gesture-simulate-min.js?rev=1609737&view=auto
==============================================================================
--- roller/trunk/app/src/main/webapp/roller-ui/yui3/gesture-simulate/gesture-simulate-min.js (added)
+++ roller/trunk/app/src/main/webapp/roller-ui/yui3/gesture-simulate/gesture-simulate-min.js Fri Jul 11 16:23:25 2014
@@ -0,0 +1,9 @@
+/*
+YUI 3.17.2 (build 9c3c78e)
+Copyright 2014 Yahoo! Inc. All rights reserved.
+Licensed under the BSD License.
+http://yuilibrary.com/license/
+*/
+
+YUI.add("gesture-simulate",function(e,t){function T(n){n||e.error(t+": invalid target node"),this.node=n,this.target=e.Node.getDOMNode(n);var r=this.node.getXY(),i=this._getDims();a=r[0]+i[0]/2,f=r[1]+i[1]/2}var t="gesture-simulate",n=e.config.win&&"ontouchstart"in e.config.win&&!e.UA.phantomjs&&!(e.UA.chrome&&e.UA.chrome<6),r={tap:1,doubletap:1,press:1,move:1,flick:1,pinch:1,rotate:1},i={touchstart:1,touchmove:1,touchend:1,touchcancel:1},s=e.config.doc,o,u=20,a,f,l={HOLD_TAP:10,DELAY_TAP:10,HOLD_PRESS:3e3,MIN_HOLD_PRESS:1e3,MAX_HOLD_PRESS:6e4,DISTANCE_MOVE:200,DURATION_MOVE:1e3,MAX_DURATION_MOVE:5e3,MIN_VELOCITY_FLICK:1.3,DISTANCE_FLICK:200,DURATION_FLICK:1e3,MAX_DURATION_FLICK:5e3,DURATION_PINCH:1e3},c="touchstart",h="touchmove",p="touchend",d="gesturestart",v="gesturechange",m="gestureend",g="mouseup",y="mousemove",b="mousedown",w="click",E="dblclick",S="x",x="y";T.prototype={_toRadian:function(e){return e*(Math.PI/180)},_getDims:function(){var e,t,n;return this.target.getBoundin
 gClientRect?(e=this.target.getBoundingClientRect(),"height"in e?n=e.height:n=Math.abs(e.bottom-e.top),"width"in e?t=e.width:t=Math.abs(e.right-e.left)):(e=this.node.get("region"),t=e.width,n=e.height),[t,n]},_calculateDefaultPoint:function(t){var n;return!e.Lang.isArray(t)||t.length===0?t=[a,f]:(t.length==1&&(n=this._getDims[1],t[1]=n/2),t[0]=this.node.getX()+t[0],t[1]=this.node.getY()+t[1]),t},rotate:function(n,r,i,s,o,u,a){var f,l=i,c=s;if(!e.Lang.isNumber(l)||!e.Lang.isNumber(c)||l<0||c<0)f=this.target.offsetWidth<this.target.offsetHeight?this.target.offsetWidth/4:this.target.offsetHeight/4,l=f,c=f;e.Lang.isNumber(a)||e.error(t+"Invalid rotation detected."),this.pinch(n,r,l,c,o,u,a)},pinch:function(n,r,i,s,o,a,f){var g,y,b=u,w,E=0,S=i,x=s,T,N,C,k,L,A,O,M,_,D={start:[],end:[]},P={start:[],end:[]},H,B;r=this._calculateDefaultPoint(r),(!e.Lang.isNumber(S)||!e.Lang.isNumber(x)||S<0||x<0)&&e.error(t+"Invalid startRadius and endRadius detected.");if(!e.Lang.isNumber(o)||o<=0)o=l.DURATI
 ON_PINCH;if(!e.Lang.isNumber(a))a=0;else{a%=360;while(a<0)a+=360}e.Lang.isNumber(f)||(f=0),e.AsyncQueue.defaults.timeout=b,g=new e.AsyncQueue,N=r[0],C=r[1],O=a,M=a+f,D.start=[N+S*Math.sin(this._toRadian(O)),C-S*Math.cos(this._toRadian(O))],D.end=[N+x*Math.sin(this._toRadian(M)),C-x*Math.cos(this._toRadian(M))],P.start=[N-S*Math.sin(this._toRadian(O)),C+S*Math.cos(this._toRadian(O))],P.end=[N-x*Math.sin(this._toRadian(M)),C+x*Math.cos(this._toRadian(M))],k=1,L=s/i,g.add({fn:function(){var t,n,r,i;t={pageX:D.start[0],pageY:D.start[1],clientX:D.start[0],clientY:D.start[1]},n={pageX:P.start[0],pageY:P.start[1],clientX:P.start[0],clientY:P.start[1]},i=this._createTouchList([e.merge({identifier:E++},t),e.merge({identifier:E++},n)]),r={pageX:(D.start[0]+P.start[0])/2,pageY:(D.start[0]+P.start[1])/2,clientX:(D.start[0]+P.start[0])/2,clientY:(D.start[0]+P.start[1])/2},this._simulateEvent(this.target,c,e.merge({touches:i,targetTouches:i,changedTouches:i,scale:k,rotation:O},r)),e.UA.ios>=2&&th
 is._simulateEvent(this.target,d,e.merge({scale:k,rotation:O},r))},timeout:0,context:this}),H=Math.floor(o/b),T=(x-S)/H,A=(L-k)/H,_=(M-O)/H,B=function(t){var n=S+T*t,r=N+n*Math.sin(this._toRadian(O+_*t)),i=C-n*Math.cos(this._toRadian(O+_*t)),s=N-n*Math.sin(this._toRadian(O+_*t)),o=C+n*Math.cos(this._toRadian(O+_*t)),u=(r+s)/2,a=(i+o)/2,f,l,c,p;f={pageX:r,pageY:i,clientX:r,clientY:i},l={pageX:s,pageY:o,clientX:s,clientY:o},p=this._createTouchList([e.merge({identifier:E++},f),e.merge({identifier:E++},l)]),c={pageX:u,pageY:a,clientX:u,clientY:a},this._simulateEvent(this.target,h,e.merge({touches:p,targetTouches:p,changedTouches:p,scale:k+A*t,rotation:O+_*t},c)),e.UA.ios>=2&&this._simulateEvent(this.target,v,e.merge({scale:k+A*t,rotation:O+_*t},c))};for(y=0;y<H;y++)g.add({fn:B,args:[y],context:this});g.add({fn:function(){var t=this._getEmptyTouchList(),n,r,i,s;n={pageX:D.end[0],pageY:D.end[1],clientX:D.end[0],clientY:D.end[1]},r={pageX:P.end[0],pageY:P.end[1],clientX:P.end[0],clientY:P.e
 nd[1]},s=this._createTouchList([e.merge({identifier:E++},n),e.merge({identifier:E++},r)]),i={pageX:(D.end[0]+P.end[0])/2,pageY:(D.end[0]+P.end[1])/2,clientX:(D.end[0]+P.end[0])/2,clientY:(D.end[0]+P.end[1])/2},e.UA.ios>=2&&this._simulateEvent(this.target,m,e.merge({scale:L,rotation:M},i)),this._simulateEvent(this.target,p,e.merge({touches:t,targetTouches:t,changedTouches:s,scale:L,rotation:M},i))},context:this}),n&&e.Lang.isFunction(n)&&g.add({fn:n,context:this.node}),g.run()},tap:function(t,r,i,s,o){var u=new e.AsyncQueue,a=this._getEmptyTouchList(),f,h,d,v,m;r=this._calculateDefaultPoint(r);if(!e.Lang.isNumber(i)||i<1)i=1;e.Lang.isNumber(s)||(s=l.HOLD_TAP),e.Lang.isNumber(o)||(o=l.DELAY_TAP),h={pageX:r[0],pageY:r[1],clientX:r[0],clientY:r[1]},f=this._createTouchList([e.merge({identifier:0},h)]),v=function(){this._simulateEvent(this.target,c,e.merge({touches:f,targetTouches:f,changedTouches:f},h))},m=function(){this._simulateEvent(this.target,p,e.merge({touches:a,targetTouches:a,ch
 angedTouches:f},h))};for(d=0;d<i;d++)u.add({fn:v,context:this,timeout:d===0?0:o}),u.add({fn:m,context:this,timeout:s});i>1&&!n&&u.add({fn:function(){this._simulateEvent(this.target,E,h)},context:this}),t&&e.Lang.isFunction(t)&&u.add({fn:t,context:this.node}),u.run()},flick:function(n,r,i,s,o){var u;r=this._calculateDefaultPoint(r),e.Lang.isString(i)?(i=i.toLowerCase(),i!==S&&i!==x&&e.error(t+"(flick): Only x or y axis allowed")):i=S,e.Lang.isNumber(s)||(s=l.DISTANCE_FLICK),e.Lang.isNumber(o)?o>l.MAX_DURATION_FLICK&&(o=l.MAX_DURATION_FLICK):o=l.DURATION_FLICK,Math.abs(s)/o<l.MIN_VELOCITY_FLICK&&(o=Math.abs(s)/l.MIN_VELOCITY_FLICK),u={start:e.clone(r),end:[i===S?r[0]+s:r[0],i===x?r[1]+s:r[1]]},this._move(n,u,o)},move:function(t,n,r){var i;e.Lang.isObject(n)?(e.Lang.isArray(n.point)?n.point=this._calculateDefaultPoint(n.point):n.point=this._calculateDefaultPoint([]),e.Lang.isNumber(n.xdist)||(n.xdist=l.DISTANCE_MOVE),e.Lang.isNumber(n.ydist)||(n.ydist=0)):n={point:this._calculateDefaul
 tPoint([]),xdist:l.
+DISTANCE_MOVE,ydist:0},e.Lang.isNumber(r)?r>l.MAX_DURATION_MOVE&&(r=l.MAX_DURATION_MOVE):r=l.DURATION_MOVE,i={start:e.clone(n.point),end:[n.point[0]+n.xdist,n.point[1]+n.ydist]},this._move(t,i,r)},_move:function(t,n,r){var i,s,o=u,d,v,m,g=0,y;e.Lang.isNumber(r)?r>l.MAX_DURATION_MOVE&&(r=l.MAX_DURATION_MOVE):r=l.DURATION_MOVE,e.Lang.isObject(n)?(e.Lang.isArray(n.start)||(n.start=[a,f]),e.Lang.isArray(n.end)||(n.end=[a+l.DISTANCE_MOVE,f])):n={start:[a,f],end:[a+l.DISTANCE_MOVE,f]},e.AsyncQueue.defaults.timeout=o,i=new e.AsyncQueue,i.add({fn:function(){var t={pageX:n.start[0],pageY:n.start[1],clientX:n.start[0],clientY:n.start[1]},r=this._createTouchList([e.merge({identifier:g++},t)]);this._simulateEvent(this.target,c,e.merge({touches:r,targetTouches:r,changedTouches:r},t))},timeout:0,context:this}),d=Math.floor(r/o),v=(n.end[0]-n.start[0])/d,m=(n.end[1]-n.start[1])/d,y=function(t){var r=n.start[0]+v*t,i=n.start[1]+m*t,s={pageX:r,pageY:i,clientX:r,clientY:i},o=this._createTouchList([e.
 merge({identifier:g++},s)]);this._simulateEvent(this.target,h,e.merge({touches:o,targetTouches:o,changedTouches:o},s))};for(s=0;s<d;s++)i.add({fn:y,args:[s],context:this});i.add({fn:function(){var t={pageX:n.end[0],pageY:n.end[1],clientX:n.end[0],clientY:n.end[1]},r=this._createTouchList([e.merge({identifier:g},t)]);this._simulateEvent(this.target,h,e.merge({touches:r,targetTouches:r,changedTouches:r},t))},timeout:0,context:this}),i.add({fn:function(){var t={pageX:n.end[0],pageY:n.end[1],clientX:n.end[0],clientY:n.end[1]},r=this._getEmptyTouchList(),i=this._createTouchList([e.merge({identifier:g},t)]);this._simulateEvent(this.target,p,e.merge({touches:r,targetTouches:r,changedTouches:i},t))},context:this}),t&&e.Lang.isFunction(t)&&i.add({fn:t,context:this.node}),i.run()},_getEmptyTouchList:function(){return o||(o=this._createTouchList([])),o},_createTouchList:function(n){var r=[],i,o=this;return!!n&&e.Lang.isArray(n)?e.UA.android&&e.UA.android>=4||e.UA.ios&&e.UA.ios>=2?(e.each(n,fun
 ction(t){t.identifier||(t.identifier=0),t.pageX||(t.pageX=0),t.pageY||(t.pageY=0),t.screenX||(t.screenX=0),t.screenY||(t.screenY=0),r.push(s.createTouch(e.config.win,o.target,t.identifier,t.pageX,t.pageY,t.screenX,t.screenY))}),i=s.createTouchList.apply(s,r)):e.UA.ios&&e.UA.ios<2?e.error(t+": No touch event simulation framework present."):(i=[],e.each(n,function(e){e.identifier||(e.identifier=0),e.clientX||(e.clientX=0),e.clientY||(e.clientY=0),e.pageX||(e.pageX=0),e.pageY||(e.pageY=0),e.screenX||(e.screenX=0),e.screenY||(e.screenY=0),i.push({target:o.target,identifier:e.identifier,clientX:e.clientX,clientY:e.clientY,pageX:e.pageX,pageY:e.pageY,screenX:e.screenX,screenY:e.screenY})}),i.item=function(e){return i[e]}):e.error(t+": Invalid touchPoints passed"),i},_simulateEvent:function(t,r,s){var o;i[r]?n?e.Event.simulate(t,r,s):this._isSingleTouch(s.touches,s.targetTouches,s.changedTouches)?(r={touchstart:b,touchmove:y,touchend:g}[r],s.button=0,s.relatedTarget=null,o=r===g?s.changedT
 ouches:s.touches,s=e.mix(s,{screenX:o.item(0).screenX,screenY:o.item(0).screenY,clientX:o.item(0).clientX,clientY:o.item(0).clientY},!0),e.Event.simulate(t,r,s),r==g&&e.Event.simulate(t,w,s)):e.error("_simulateEvent(): Event '"+r+"' has multi touch objects that can't be simulated in your platform."):e.Event.simulate(t,r,s)},_isSingleTouch:function(e,t,n){return e&&e.length<=1&&t&&t.length<=1&&n&&n.length<=1}},e.GestureSimulation=T,e.GestureSimulation.defaults=l,e.GestureSimulation.GESTURES=r,e.Event.simulateGesture=function(n,i,s,o){n=e.one(n);var u=new e.GestureSimulation(n);i=i.toLowerCase(),!o&&e.Lang.isFunction(s)&&(o=s,s={}),s=s||{};if(r[i])switch(i){case"tap":u.tap(o,s.point,s.times,s.hold,s.delay);break;case"doubletap":u.tap(o,s.point,2);break;case"press":e.Lang.isNumber(s.hold)?s.hold<l.MIN_HOLD_PRESS?s.hold=l.MIN_HOLD_PRESS:s.hold>l.MAX_HOLD_PRESS&&(s.hold=l.MAX_HOLD_PRESS):s.hold=l.HOLD_PRESS,u.tap(o,s.point,1,s.hold);break;case"move":u.move(o,s.path,s.duration);break;case
 "flick":u.flick(o,s.point,s.axis,s.distance,s.duration);break;case"pinch":u.pinch(o,s.center,s.r1,s.r2,s.duration,s.start,s.rotation);break;case"rotate":u.rotate(o,s.center,s.r1,s.r2,s.duration,s.start,s.rotation)}else e.error(t+": Not a supported gesture simulation: "+i)}},"3.17.2",{requires:["async-queue","event-simulate","node-screen"]});

Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/gesture-simulate/gesture-simulate.js
URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/gesture-simulate/gesture-simulate.js?rev=1609737&view=auto
==============================================================================
--- roller/trunk/app/src/main/webapp/roller-ui/yui3/gesture-simulate/gesture-simulate.js (added)
+++ roller/trunk/app/src/main/webapp/roller-ui/yui3/gesture-simulate/gesture-simulate.js Fri Jul 11 16:23:25 2014
@@ -0,0 +1,1328 @@
+/*
+YUI 3.17.2 (build 9c3c78e)
+Copyright 2014 Yahoo! Inc. All rights reserved.
+Licensed under the BSD License.
+http://yuilibrary.com/license/
+*/
+
+YUI.add('gesture-simulate', function (Y, NAME) {
+
+/**
+ * Simulate high-level user gestures by generating a set of native DOM events.
+ *
+ * @module gesture-simulate
+ * @requires event-simulate, async-queue, node-screen
+ */
+
+var NAME = "gesture-simulate",
+
+    // phantomjs check may be temporary, until we determine if it really support touch all the way through, like it claims to (http://code.google.com/p/phantomjs/issues/detail?id=375)
+    SUPPORTS_TOUCH = ((Y.config.win && ("ontouchstart" in Y.config.win)) && !(Y.UA.phantomjs) && !(Y.UA.chrome && Y.UA.chrome < 6)),
+
+    gestureNames = {
+        tap: 1,
+        doubletap: 1,
+        press: 1,
+        move: 1,
+        flick: 1,
+        pinch: 1,
+        rotate: 1
+    },
+
+    touchEvents = {
+        touchstart: 1,
+        touchmove: 1,
+        touchend: 1,
+        touchcancel: 1
+    },
+
+    document = Y.config.doc,
+    emptyTouchList,
+
+    EVENT_INTERVAL = 20,        // 20ms
+    START_PAGEX,                // will be adjusted to the node element center
+    START_PAGEY,                // will be adjusted to the node element center
+
+    // defaults that user can override.
+    DEFAULTS = {
+        // tap gestures
+        HOLD_TAP: 10,           // 10ms
+        DELAY_TAP: 10,          // 10ms
+
+        // press gesture
+        HOLD_PRESS: 3000,       // 3sec
+        MIN_HOLD_PRESS: 1000,   // 1sec
+        MAX_HOLD_PRESS: 60000,  // 1min
+
+        // move gesture
+        DISTANCE_MOVE: 200,     // 200 pixels
+        DURATION_MOVE: 1000,    // 1sec
+        MAX_DURATION_MOVE: 5000,// 5sec
+
+        // flick gesture
+        MIN_VELOCITY_FLICK: 1.3,
+        DISTANCE_FLICK: 200,     // 200 pixels
+        DURATION_FLICK: 1000,    // 1sec
+        MAX_DURATION_FLICK: 5000,// 5sec
+
+        // pinch/rotation
+        DURATION_PINCH: 1000     // 1sec
+    },
+
+    TOUCH_START = 'touchstart',
+    TOUCH_MOVE = 'touchmove',
+    TOUCH_END = 'touchend',
+
+    GESTURE_START = 'gesturestart',
+    GESTURE_CHANGE = 'gesturechange',
+    GESTURE_END = 'gestureend',
+
+    MOUSE_UP    = 'mouseup',
+    MOUSE_MOVE  = 'mousemove',
+    MOUSE_DOWN  = 'mousedown',
+    MOUSE_CLICK = 'click',
+    MOUSE_DBLCLICK = 'dblclick',
+
+    X_AXIS = 'x',
+    Y_AXIS = 'y';
+
+
+function Simulations(node) {
+    if(!node) {
+        Y.error(NAME+': invalid target node');
+    }
+    this.node = node;
+    this.target = Y.Node.getDOMNode(node);
+
+    var startXY = this.node.getXY(),
+        dims = this._getDims();
+
+    START_PAGEX = startXY[0] + (dims[0])/2;
+    START_PAGEY = startXY[1] + (dims[1])/2;
+}
+
+Simulations.prototype = {
+
+    /**
+     * Helper method to convert a degree to a radian.
+     *
+     * @method _toRadian
+     * @private
+     * @param {Number} deg A degree to be converted to a radian.
+     * @return {Number} The degree in radian.
+     */
+    _toRadian: function(deg) {
+        return deg * (Math.PI/180);
+    },
+
+    /**
+     * Helper method to get height/width while accounting for
+     * rotation/scale transforms where possible by using the
+     * bounding client rectangle height/width instead of the
+     * offsetWidth/Height which region uses.
+     * @method _getDims
+     * @private
+     * @return {Array} Array with [height, width]
+     */
+    _getDims : function() {
+        var region,
+            width,
+            height;
+
+        // Ideally, this should be in DOM somewhere.
+        if (this.target.getBoundingClientRect) {
+            region = this.target.getBoundingClientRect();
+
+            if ("height" in region) {
+                height = region.height;
+            } else {
+                // IE7,8 has getBCR, but no height.
+                height = Math.abs(region.bottom - region.top);
+            }
+
+            if ("width" in region) {
+                width = region.width;
+            } else {
+                // IE7,8 has getBCR, but no width.
+                width = Math.abs(region.right - region.left);
+            }
+        } else {
+            region = this.node.get("region");
+            width = region.width;
+            height = region.height;
+        }
+
+        return [width, height];
+    },
+
+    /**
+     * Helper method to convert a point relative to the node element into
+     * the point in the page coordination.
+     *
+     * @method _calculateDefaultPoint
+     * @private
+     * @param {Array} point A point relative to the node element.
+     * @return {Array} The same point in the page coordination.
+     */
+    _calculateDefaultPoint: function(point) {
+
+        var height;
+
+        if(!Y.Lang.isArray(point) || point.length === 0) {
+            point = [START_PAGEX, START_PAGEY];
+        } else {
+            if(point.length == 1) {
+                height = this._getDims[1];
+                point[1] = height/2;
+            }
+            // convert to page(viewport) coordination
+            point[0] = this.node.getX() + point[0];
+            point[1] = this.node.getY() + point[1];
+        }
+
+        return point;
+    },
+
+    /**
+     * The "rotate" and "pinch" methods are essencially same with the exact same
+     * arguments. Only difference is the required parameters. The rotate method
+     * requires "rotation" parameter while the pinch method requires "startRadius"
+     * and "endRadius" parameters.
+     *
+     * @method rotate
+     * @param {Function} cb The callback to execute when the gesture simulation
+     *      is completed.
+     * @param {Array} center A center point where the pinch gesture of two fingers
+     *      should happen. It is relative to the top left corner of the target
+     *      node element.
+     * @param {Number} startRadius A radius of start circle where 2 fingers are
+     *      on when the gesture starts. This is optional. The default is a fourth of
+     *      either target node width or height whichever is smaller.
+     * @param {Number} endRadius A radius of end circle where 2 fingers will be on when
+     *      the pinch or spread gestures are completed. This is optional.
+     *      The default is a fourth of either target node width or height whichever is less.
+     * @param {Number} duration A duration of the gesture in millisecond.
+     * @param {Number} start A start angle(0 degree at 12 o'clock) where the
+     *      gesture should start. Default is 0.
+     * @param {Number} rotation A rotation in degree. It is required.
+     */
+    rotate: function(cb, center, startRadius, endRadius, duration, start, rotation) {
+        var radius,
+            r1 = startRadius,   // optional
+            r2 = endRadius;     // optional
+
+        if(!Y.Lang.isNumber(r1) || !Y.Lang.isNumber(r2) || r1<0 || r2<0) {
+            radius = (this.target.offsetWidth < this.target.offsetHeight)?
+                this.target.offsetWidth/4 : this.target.offsetHeight/4;
+            r1 = radius;
+            r2 = radius;
+        }
+
+        // required
+        if(!Y.Lang.isNumber(rotation)) {
+            Y.error(NAME+'Invalid rotation detected.');
+        }
+
+        this.pinch(cb, center, r1, r2, duration, start, rotation);
+    },
+
+    /**
+     * The "rotate" and "pinch" methods are essencially same with the exact same
+     * arguments. Only difference is the required parameters. The rotate method
+     * requires "rotation" parameter while the pinch method requires "startRadius"
+     * and "endRadius" parameters.
+     *
+     * The "pinch" gesture can simulate various 2 finger gestures such as pinch,
+     * spread and/or rotation. The "startRadius" and "endRadius" are required.
+     * If endRadius is larger than startRadius, it becomes a spread gesture
+     * otherwise a pinch gesture.
+     *
+     * @method pinch
+     * @param {Function} cb The callback to execute when the gesture simulation
+     *      is completed.
+     * @param {Array} center A center point where the pinch gesture of two fingers
+     *      should happen. It is relative to the top left corner of the target
+     *      node element.
+     * @param {Number} startRadius A radius of start circle where 2 fingers are
+     *      on when the gesture starts. This paramenter is required.
+     * @param {Number} endRadius A radius of end circle where 2 fingers will be on when
+     *      the pinch or spread gestures are completed. This parameter is required.
+     * @param {Number} duration A duration of the gesture in millisecond.
+     * @param {Number} start A start angle(0 degree at 12 o'clock) where the
+     *      gesture should start. Default is 0.
+     * @param {Number} rotation If rotation is desired during the pinch or
+     *      spread gestures, this parameter can be used. Default is 0 degree.
+     */
+    pinch: function(cb, center, startRadius, endRadius, duration, start, rotation) {
+        var eventQueue,
+            i,
+            interval = EVENT_INTERVAL,
+            touches,
+            id = 0,
+            r1 = startRadius,   // required
+            r2 = endRadius,     // required
+            radiusPerStep,
+            centerX, centerY,
+            startScale, endScale, scalePerStep,
+            startRot, endRot, rotPerStep,
+            path1 = {start: [], end: []}, // paths for 1st and 2nd fingers.
+            path2 = {start: [], end: []},
+            steps,
+            touchMove;
+
+        center = this._calculateDefaultPoint(center);
+
+        if(!Y.Lang.isNumber(r1) || !Y.Lang.isNumber(r2) || r1<0 || r2<0) {
+            Y.error(NAME+'Invalid startRadius and endRadius detected.');
+        }
+
+        if(!Y.Lang.isNumber(duration) || duration <= 0) {
+            duration = DEFAULTS.DURATION_PINCH;
+        }
+
+        if(!Y.Lang.isNumber(start)) {
+            start = 0.0;
+        } else {
+            start = start%360;
+            while(start < 0) {
+                start += 360;
+            }
+        }
+
+        if(!Y.Lang.isNumber(rotation)) {
+            rotation = 0.0;
+        }
+
+        Y.AsyncQueue.defaults.timeout = interval;
+        eventQueue = new Y.AsyncQueue();
+
+        // range determination
+        centerX = center[0];
+        centerY = center[1];
+
+        startRot = start;
+        endRot = start + rotation;
+
+        // 1st finger path
+        path1.start = [
+            centerX + r1*Math.sin(this._toRadian(startRot)),
+            centerY - r1*Math.cos(this._toRadian(startRot))
+        ];
+        path1.end   = [
+            centerX + r2*Math.sin(this._toRadian(endRot)),
+            centerY - r2*Math.cos(this._toRadian(endRot))
+        ];
+
+        // 2nd finger path
+        path2.start = [
+            centerX - r1*Math.sin(this._toRadian(startRot)),
+            centerY + r1*Math.cos(this._toRadian(startRot))
+        ];
+        path2.end   = [
+            centerX - r2*Math.sin(this._toRadian(endRot)),
+            centerY + r2*Math.cos(this._toRadian(endRot))
+        ];
+
+        startScale = 1.0;
+        endScale = endRadius/startRadius;
+
+        // touch/gesture start
+        eventQueue.add({
+            fn: function() {
+                var coord1, coord2, coord, touches;
+
+                // coordinate for each touch object.
+                coord1 = {
+                    pageX: path1.start[0],
+                    pageY: path1.start[1],
+                    clientX: path1.start[0],
+                    clientY: path1.start[1]
+                };
+                coord2 = {
+                    pageX: path2.start[0],
+                    pageY: path2.start[1],
+                    clientX: path2.start[0],
+                    clientY: path2.start[1]
+                };
+                touches = this._createTouchList([Y.merge({
+                    identifier: (id++)
+                }, coord1), Y.merge({
+                    identifier: (id++)
+                }, coord2)]);
+
+                // coordinate for top level event
+                coord = {
+                    pageX: (path1.start[0] + path2.start[0])/2,
+                    pageY: (path1.start[0] + path2.start[1])/2,
+                    clientX: (path1.start[0] + path2.start[0])/2,
+                    clientY: (path1.start[0] + path2.start[1])/2
+                };
+
+                this._simulateEvent(this.target, TOUCH_START, Y.merge({
+                    touches: touches,
+                    targetTouches: touches,
+                    changedTouches: touches,
+                    scale: startScale,
+                    rotation: startRot
+                }, coord));
+
+                if(Y.UA.ios >= 2.0) {
+                    /* gesture starts when the 2nd finger touch starts.
+                    * The implementation will fire 1 touch start event for both fingers,
+                    * simulating 2 fingers touched on the screen at the same time.
+                    */
+                    this._simulateEvent(this.target, GESTURE_START, Y.merge({
+                        scale: startScale,
+                        rotation: startRot
+                    }, coord));
+                }
+            },
+            timeout: 0,
+            context: this
+        });
+
+        // gesture change
+        steps = Math.floor(duration/interval);
+        radiusPerStep = (r2 - r1)/steps;
+        scalePerStep = (endScale - startScale)/steps;
+        rotPerStep = (endRot - startRot)/steps;
+
+        touchMove = function(step) {
+            var radius = r1 + (radiusPerStep)*step,
+                px1 = centerX + radius*Math.sin(this._toRadian(startRot + rotPerStep*step)),
+                py1 = centerY - radius*Math.cos(this._toRadian(startRot + rotPerStep*step)),
+                px2 = centerX - radius*Math.sin(this._toRadian(startRot + rotPerStep*step)),
+                py2 = centerY + radius*Math.cos(this._toRadian(startRot + rotPerStep*step)),
+                px = (px1+px2)/2,
+                py = (py1+py2)/2,
+                coord1, coord2, coord, touches;
+
+            // coordinate for each touch object.
+            coord1 = {
+                pageX: px1,
+                pageY: py1,
+                clientX: px1,
+                clientY: py1
+            };
+            coord2 = {
+                pageX: px2,
+                pageY: py2,
+                clientX: px2,
+                clientY: py2
+            };
+            touches = this._createTouchList([Y.merge({
+                identifier: (id++)
+            }, coord1), Y.merge({
+                identifier: (id++)
+            }, coord2)]);
+
+            // coordinate for top level event
+            coord = {
+                pageX: px,
+                pageY: py,
+                clientX: px,
+                clientY: py
+            };
+
+            this._simulateEvent(this.target, TOUCH_MOVE, Y.merge({
+                touches: touches,
+                targetTouches: touches,
+                changedTouches: touches,
+                scale: startScale + scalePerStep*step,
+                rotation: startRot + rotPerStep*step
+            }, coord));
+
+            if(Y.UA.ios >= 2.0) {
+                this._simulateEvent(this.target, GESTURE_CHANGE, Y.merge({
+                    scale: startScale + scalePerStep*step,
+                    rotation: startRot + rotPerStep*step
+                }, coord));
+            }
+        };
+
+        for (i=0; i < steps; i++) {
+            eventQueue.add({
+                fn: touchMove,
+                args: [i],
+                context: this
+            });
+        }
+
+        // gesture end
+        eventQueue.add({
+            fn: function() {
+                var emptyTouchList = this._getEmptyTouchList(),
+                    coord1, coord2, coord, touches;
+
+                // coordinate for each touch object.
+                coord1 = {
+                    pageX: path1.end[0],
+                    pageY: path1.end[1],
+                    clientX: path1.end[0],
+                    clientY: path1.end[1]
+                };
+                coord2 = {
+                    pageX: path2.end[0],
+                    pageY: path2.end[1],
+                    clientX: path2.end[0],
+                    clientY: path2.end[1]
+                };
+                touches = this._createTouchList([Y.merge({
+                    identifier: (id++)
+                }, coord1), Y.merge({
+                    identifier: (id++)
+                }, coord2)]);
+
+                // coordinate for top level event
+                coord = {
+                    pageX: (path1.end[0] + path2.end[0])/2,
+                    pageY: (path1.end[0] + path2.end[1])/2,
+                    clientX: (path1.end[0] + path2.end[0])/2,
+                    clientY: (path1.end[0] + path2.end[1])/2
+                };
+
+                if(Y.UA.ios >= 2.0) {
+                    this._simulateEvent(this.target, GESTURE_END, Y.merge({
+                        scale: endScale,
+                        rotation: endRot
+                    }, coord));
+                }
+
+                this._simulateEvent(this.target, TOUCH_END, Y.merge({
+                    touches: emptyTouchList,
+                    targetTouches: emptyTouchList,
+                    changedTouches: touches,
+                    scale: endScale,
+                    rotation: endRot
+                }, coord));
+            },
+            context: this
+        });
+
+        if(cb && Y.Lang.isFunction(cb)) {
+            eventQueue.add({
+                fn: cb,
+
+                // by default, the callback runs the node context where
+                // simulateGesture method is called.
+                context: this.node
+
+                //TODO: Use args to pass error object as 1st param if there is an error.
+                //args:
+            });
+        }
+
+        eventQueue.run();
+    },
+
+    /**
+     * The "tap" gesture can be used for various single touch point gestures
+     * such as single tap, N number of taps, long press. The default is a single
+     * tap.
+     *
+     * @method tap
+     * @param {Function} cb The callback to execute when the gesture simulation
+     *      is completed.
+     * @param {Array} point A point(relative to the top left corner of the
+     *      target node element) where the tap gesture should start. The default
+     *      is the center of the taget node.
+     * @param {Number} times The number of taps. Default is 1.
+     * @param {Number} hold The hold time in milliseconds between "touchstart" and
+     *      "touchend" event generation. Default is 10ms.
+     * @param {Number} delay The time gap in millisecond between taps if this
+     *      gesture has more than 1 tap. Default is 10ms.
+     */
+    tap: function(cb, point, times, hold, delay) {
+        var eventQueue = new Y.AsyncQueue(),
+            emptyTouchList = this._getEmptyTouchList(),
+            touches,
+            coord,
+            i,
+            touchStart,
+            touchEnd;
+
+        point = this._calculateDefaultPoint(point);
+
+        if(!Y.Lang.isNumber(times) || times < 1) {
+            times = 1;
+        }
+
+        if(!Y.Lang.isNumber(hold)) {
+            hold = DEFAULTS.HOLD_TAP;
+        }
+
+        if(!Y.Lang.isNumber(delay)) {
+            delay = DEFAULTS.DELAY_TAP;
+        }
+
+        coord = {
+            pageX: point[0],
+            pageY: point[1],
+            clientX: point[0],
+            clientY: point[1]
+        };
+
+        touches = this._createTouchList([Y.merge({identifier: 0}, coord)]);
+
+        touchStart = function() {
+            this._simulateEvent(this.target, TOUCH_START, Y.merge({
+                touches: touches,
+                targetTouches: touches,
+                changedTouches: touches
+            }, coord));
+        };
+
+        touchEnd = function() {
+            this._simulateEvent(this.target, TOUCH_END, Y.merge({
+                touches: emptyTouchList,
+                targetTouches: emptyTouchList,
+                changedTouches: touches
+            }, coord));
+        };
+
+        for (i=0; i < times; i++) {
+            eventQueue.add({
+                fn: touchStart,
+                context: this,
+                timeout: (i === 0)? 0 : delay
+            });
+
+            eventQueue.add({
+                fn: touchEnd,
+                context: this,
+                timeout: hold
+            });
+        }
+
+        if(times > 1 && !SUPPORTS_TOUCH) {
+            eventQueue.add({
+                fn: function() {
+                    this._simulateEvent(this.target, MOUSE_DBLCLICK, coord);
+                },
+                context: this
+            });
+        }
+
+        if(cb && Y.Lang.isFunction(cb)) {
+            eventQueue.add({
+                fn: cb,
+
+                // by default, the callback runs the node context where
+                // simulateGesture method is called.
+                context: this.node
+
+                //TODO: Use args to pass error object as 1st param if there is an error.
+                //args:
+            });
+        }
+
+        eventQueue.run();
+    },
+
+    /**
+     * The "flick" gesture is a specialized "move" that has some velocity
+     * and the movement always runs either x or y axis. The velocity is calculated
+     * with "distance" and "duration" arguments. If the calculated velocity is
+     * below than the minimum velocity, the given duration will be ignored and
+     * new duration will be created to make a valid flick gesture.
+     *
+     * @method flick
+     * @param {Function} cb The callback to execute when the gesture simulation
+     *      is completed.
+     * @param {Array} point A point(relative to the top left corner of the
+     *      target node element) where the flick gesture should start. The default
+     *      is the center of the taget node.
+     * @param {String} axis Either "x" or "y".
+     * @param {Number} distance A distance in pixels to flick.
+     * @param {Number} duration A duration of the gesture in millisecond.
+     *
+     */
+    flick: function(cb, point, axis, distance, duration) {
+        var path;
+
+        point = this._calculateDefaultPoint(point);
+
+        if(!Y.Lang.isString(axis)) {
+            axis = X_AXIS;
+        } else {
+            axis = axis.toLowerCase();
+            if(axis !== X_AXIS && axis !== Y_AXIS) {
+                Y.error(NAME+'(flick): Only x or y axis allowed');
+            }
+        }
+
+        if(!Y.Lang.isNumber(distance)) {
+            distance = DEFAULTS.DISTANCE_FLICK;
+        }
+
+        if(!Y.Lang.isNumber(duration)){
+            duration = DEFAULTS.DURATION_FLICK; // ms
+        } else {
+            if(duration > DEFAULTS.MAX_DURATION_FLICK) {
+                duration = DEFAULTS.MAX_DURATION_FLICK;
+            }
+        }
+
+        /*
+         * Check if too slow for a flick.
+         * Adjust duration if the calculated velocity is less than
+         * the minimum velcocity to be claimed as a flick.
+         */
+        if(Math.abs(distance)/duration < DEFAULTS.MIN_VELOCITY_FLICK) {
+            duration = Math.abs(distance)/DEFAULTS.MIN_VELOCITY_FLICK;
+        }
+
+        path = {
+            start: Y.clone(point),
+            end: [
+                (axis === X_AXIS) ? point[0]+distance : point[0],
+                (axis === Y_AXIS) ? point[1]+distance : point[1]
+            ]
+        };
+
+        this._move(cb, path, duration);
+    },
+
+    /**
+     * The "move" gesture simulate the movement of any direction between
+     * the straight line of start and end point for the given duration.
+     * The path argument is an object with "point", "xdist" and "ydist" properties.
+     * The "point" property is an array with x and y coordinations(relative to the
+     * top left corner of the target node element) while "xdist" and "ydist"
+     * properties are used for the distance along the x and y axis. A negative
+     * distance number can be used to drag either left or up direction.
+     *
+     * If no arguments are given, it will simulate the default move, which
+     * is moving 200 pixels from the center of the element to the positive X-axis
+     * direction for 1 sec.
+     *
+     * @method move
+     * @param {Function} cb The callback to execute when the gesture simulation
+     *      is completed.
+     * @param {Object} path An object with "point", "xdist" and "ydist".
+     * @param {Number} duration A duration of the gesture in millisecond.
+     */
+    move: function(cb, path, duration) {
+        var convertedPath;
+
+        if(!Y.Lang.isObject(path)) {
+            path = {
+                point: this._calculateDefaultPoint([]),
+                xdist: DEFAULTS.DISTANCE_MOVE,
+                ydist: 0
+            };
+        } else {
+            // convert to the page coordination
+            if(!Y.Lang.isArray(path.point)) {
+                path.point = this._calculateDefaultPoint([]);
+            } else {
+                path.point = this._calculateDefaultPoint(path.point);
+            }
+
+            if(!Y.Lang.isNumber(path.xdist)) {
+                path.xdist = DEFAULTS.DISTANCE_MOVE;
+            }
+
+            if(!Y.Lang.isNumber(path.ydist)) {
+                path.ydist = 0;
+            }
+        }
+
+        if(!Y.Lang.isNumber(duration)){
+            duration = DEFAULTS.DURATION_MOVE; // ms
+        } else {
+            if(duration > DEFAULTS.MAX_DURATION_MOVE) {
+                duration = DEFAULTS.MAX_DURATION_MOVE;
+            }
+        }
+
+        convertedPath = {
+            start: Y.clone(path.point),
+            end: [path.point[0]+path.xdist, path.point[1]+path.ydist]
+        };
+
+        this._move(cb, convertedPath, duration);
+    },
+
+    /**
+     * A base method on top of "move" and "flick" methods. The method takes
+     * the path with start/end properties and duration to generate a set of
+     * touch events for the movement gesture.
+     *
+     * @method _move
+     * @private
+     * @param {Function} cb The callback to execute when the gesture simulation
+     *      is completed.
+     * @param {Object} path An object with "start" and "end" properties. Each
+     *      property should be an array with x and y coordination (e.g. start: [100, 50])
+     * @param {Number} duration A duration of the gesture in millisecond.
+     */
+    _move: function(cb, path, duration) {
+        var eventQueue,
+            i,
+            interval = EVENT_INTERVAL,
+            steps, stepX, stepY,
+            id = 0,
+            touchMove;
+
+        if(!Y.Lang.isNumber(duration)){
+            duration = DEFAULTS.DURATION_MOVE; // ms
+        } else {
+            if(duration > DEFAULTS.MAX_DURATION_MOVE) {
+                duration = DEFAULTS.MAX_DURATION_MOVE;
+            }
+        }
+
+        if(!Y.Lang.isObject(path)) {
+            path = {
+                start: [
+                    START_PAGEX,
+                    START_PAGEY
+                ],
+                end: [
+                    START_PAGEX + DEFAULTS.DISTANCE_MOVE,
+                    START_PAGEY
+                ]
+            };
+        } else {
+            if(!Y.Lang.isArray(path.start)) {
+                path.start = [
+                    START_PAGEX,
+                    START_PAGEY
+                ];
+            }
+            if(!Y.Lang.isArray(path.end)) {
+                path.end = [
+                    START_PAGEX + DEFAULTS.DISTANCE_MOVE,
+                    START_PAGEY
+                ];
+            }
+        }
+
+        Y.AsyncQueue.defaults.timeout = interval;
+        eventQueue = new Y.AsyncQueue();
+
+        // start
+        eventQueue.add({
+            fn: function() {
+                var coord = {
+                        pageX: path.start[0],
+                        pageY: path.start[1],
+                        clientX: path.start[0],
+                        clientY: path.start[1]
+                    },
+                    touches = this._createTouchList([
+                        Y.merge({identifier: (id++)}, coord)
+                    ]);
+
+                this._simulateEvent(this.target, TOUCH_START, Y.merge({
+                    touches: touches,
+                    targetTouches: touches,
+                    changedTouches: touches
+                }, coord));
+            },
+            timeout: 0,
+            context: this
+        });
+
+        // move
+        steps = Math.floor(duration/interval);
+        stepX = (path.end[0] - path.start[0])/steps;
+        stepY = (path.end[1] - path.start[1])/steps;
+
+        touchMove = function(step) {
+            var px = path.start[0]+(stepX * step),
+                py = path.start[1]+(stepY * step),
+                coord = {
+                    pageX: px,
+                    pageY: py,
+                    clientX: px,
+                    clientY: py
+                },
+                touches = this._createTouchList([
+                    Y.merge({identifier: (id++)}, coord)
+                ]);
+
+            this._simulateEvent(this.target, TOUCH_MOVE, Y.merge({
+                touches: touches,
+                targetTouches: touches,
+                changedTouches: touches
+            }, coord));
+        };
+
+        for (i=0; i < steps; i++) {
+            eventQueue.add({
+                fn: touchMove,
+                args: [i],
+                context: this
+            });
+        }
+
+        // last move
+        eventQueue.add({
+            fn: function() {
+                var coord = {
+                        pageX: path.end[0],
+                        pageY: path.end[1],
+                        clientX: path.end[0],
+                        clientY: path.end[1]
+                    },
+                    touches = this._createTouchList([
+                        Y.merge({identifier: id}, coord)
+                    ]);
+
+                this._simulateEvent(this.target, TOUCH_MOVE, Y.merge({
+                    touches: touches,
+                    targetTouches: touches,
+                    changedTouches: touches
+                }, coord));
+            },
+            timeout: 0,
+            context: this
+        });
+
+        // end
+        eventQueue.add({
+            fn: function() {
+                var coord = {
+                    pageX: path.end[0],
+                    pageY: path.end[1],
+                    clientX: path.end[0],
+                    clientY: path.end[1]
+                },
+                emptyTouchList = this._getEmptyTouchList(),
+                touches = this._createTouchList([
+                    Y.merge({identifier: id}, coord)
+                ]);
+
+                this._simulateEvent(this.target, TOUCH_END, Y.merge({
+                    touches: emptyTouchList,
+                    targetTouches: emptyTouchList,
+                    changedTouches: touches
+                }, coord));
+            },
+            context: this
+        });
+
+        if(cb && Y.Lang.isFunction(cb)) {
+            eventQueue.add({
+                fn: cb,
+
+                // by default, the callback runs the node context where
+                // simulateGesture method is called.
+                context: this.node
+
+                //TODO: Use args to pass error object as 1st param if there is an error.
+                //args:
+            });
+        }
+
+        eventQueue.run();
+    },
+
+    /**
+     * Helper method to return a singleton instance of empty touch list.
+     *
+     * @method _getEmptyTouchList
+     * @private
+     * @return {TouchList | Array} An empty touch list object.
+     */
+    _getEmptyTouchList: function() {
+        if(!emptyTouchList) {
+            emptyTouchList = this._createTouchList([]);
+        }
+
+        return emptyTouchList;
+    },
+
+    /**
+     * Helper method to convert an array with touch points to TouchList object as
+     * defined in http://www.w3.org/TR/touch-events/
+     *
+     * @method _createTouchList
+     * @private
+     * @param {Array} touchPoints
+     * @return {TouchList | Array} If underlaying platform support creating touch list
+     *      a TouchList object will be returned otherwise a fake Array object
+     *      will be returned.
+     */
+    _createTouchList: function(touchPoints) {
+        /*
+        * Android 4.0.3 emulator:
+        * Native touch api supported starting in version 4.0 (Ice Cream Sandwich).
+        * However the support seems limited. In Android 4.0.3 emulator, I got
+        * "TouchList is not defined".
+        */
+        var touches = [],
+            touchList,
+            self = this;
+
+        if(!!touchPoints && Y.Lang.isArray(touchPoints)) {
+            if(Y.UA.android && Y.UA.android >= 4.0 || Y.UA.ios && Y.UA.ios >= 2.0) {
+                Y.each(touchPoints, function(point) {
+                    if(!point.identifier) {point.identifier = 0;}
+                    if(!point.pageX) {point.pageX = 0;}
+                    if(!point.pageY) {point.pageY = 0;}
+                    if(!point.screenX) {point.screenX = 0;}
+                    if(!point.screenY) {point.screenY = 0;}
+
+                    touches.push(document.createTouch(Y.config.win,
+                        self.target,
+                        point.identifier,
+                        point.pageX, point.pageY,
+                        point.screenX, point.screenY));
+                });
+
+                touchList = document.createTouchList.apply(document, touches);
+            } else if(Y.UA.ios && Y.UA.ios < 2.0) {
+                Y.error(NAME+': No touch event simulation framework present.');
+            } else {
+                // this will inclide android(Y.UA.android && Y.UA.android < 4.0)
+                // and desktops among all others.
+
+                /*
+                 * Touch APIs are broken in androids older than 4.0. We will use
+                 * simulated touch apis for these versions.
+                 */
+                touchList = [];
+                Y.each(touchPoints, function(point) {
+                    if(!point.identifier) {point.identifier = 0;}
+                    if(!point.clientX)  {point.clientX = 0;}
+                    if(!point.clientY)  {point.clientY = 0;}
+                    if(!point.pageX)    {point.pageX = 0;}
+                    if(!point.pageY)    {point.pageY = 0;}
+                    if(!point.screenX)  {point.screenX = 0;}
+                    if(!point.screenY)  {point.screenY = 0;}
+
+                    touchList.push({
+                        target: self.target,
+                        identifier: point.identifier,
+                        clientX: point.clientX,
+                        clientY: point.clientY,
+                        pageX: point.pageX,
+                        pageY: point.pageY,
+                        screenX: point.screenX,
+                        screenY: point.screenY
+                    });
+                });
+
+                touchList.item = function(i) {
+                    return touchList[i];
+                };
+            }
+        } else {
+            Y.error(NAME+': Invalid touchPoints passed');
+        }
+
+        return touchList;
+    },
+
+    /**
+     * @method _simulateEvent
+     * @private
+     * @param {HTMLElement} target The DOM element that's the target of the event.
+     * @param {String} type The type of event or name of the supported gesture to simulate
+     *      (i.e., "click", "doubletap", "flick").
+     * @param {Object} options (Optional) Extra options to copy onto the event object.
+     *      For gestures, options are used to refine the gesture behavior.
+     */
+    _simulateEvent: function(target, type, options) {
+        var touches;
+
+        if (touchEvents[type]) {
+            if(SUPPORTS_TOUCH) {
+                Y.Event.simulate(target, type, options);
+            } else {
+                // simulate using mouse events if touch is not applicable on this platform.
+                // but only single touch event can be simulated.
+                if(this._isSingleTouch(options.touches, options.targetTouches, options.changedTouches)) {
+                    type = {
+                        touchstart: MOUSE_DOWN,
+                        touchmove: MOUSE_MOVE,
+                        touchend: MOUSE_UP
+                    }[type];
+
+                    options.button = 0;
+                    options.relatedTarget = null; // since we are not using mouseover event.
+
+                    // touchend has none in options.touches.
+                    touches = (type === MOUSE_UP)? options.changedTouches : options.touches;
+
+                    options = Y.mix(options, {
+                        screenX: touches.item(0).screenX,
+                        screenY: touches.item(0).screenY,
+                        clientX: touches.item(0).clientX,
+                        clientY: touches.item(0).clientY
+                    }, true);
+
+                    Y.Event.simulate(target, type, options);
+
+                    if(type == MOUSE_UP) {
+                        Y.Event.simulate(target, MOUSE_CLICK, options);
+                    }
+                } else {
+                    Y.error("_simulateEvent(): Event '" + type + "' has multi touch objects that can't be simulated in your platform.");
+                }
+            }
+        } else {
+            // pass thru for all non touch events
+            Y.Event.simulate(target, type, options);
+        }
+    },
+
+    /**
+     * Helper method to check the single touch.
+     * @method _isSingleTouch
+     * @private
+     * @param {TouchList} touches
+     * @param {TouchList} targetTouches
+     * @param {TouchList} changedTouches
+     */
+    _isSingleTouch: function(touches, targetTouches, changedTouches) {
+        return (touches && (touches.length <= 1)) &&
+            (targetTouches && (targetTouches.length <= 1)) &&
+            (changedTouches && (changedTouches.length <= 1));
+    }
+};
+
+/*
+ * A gesture simulation class.
+ */
+Y.GestureSimulation = Simulations;
+
+/*
+ * Various simulation default behavior properties. If user override
+ * Y.GestureSimulation.defaults, overriden values will be used and this
+ * should be done before the gesture simulation.
+ */
+Y.GestureSimulation.defaults = DEFAULTS;
+
+/*
+ * The high level gesture names that YUI knows how to simulate.
+ */
+Y.GestureSimulation.GESTURES = gestureNames;
+
+/**
+ * Simulates the higher user level gesture of the given name on a target.
+ * This method generates a set of low level touch events(Apple specific gesture
+ * events as well for the iOS platforms) asynchronously. Note that gesture
+ * simulation is relying on `Y.Event.simulate()` method to generate
+ * the touch events under the hood. The `Y.Event.simulate()` method
+ * itself is a synchronous method.
+ *
+ * Users are suggested to use `Node.simulateGesture()` method which
+ * basically calls this method internally. Supported gestures are `tap`,
+ * `doubletap`, `press`, `move`, `flick`, `pinch` and `rotate`.
+ *
+ * The `pinch` gesture is used to simulate the pinching and spreading of two
+ * fingers. During a pinch simulation, rotation is also possible. Essentially
+ * `pinch` and `rotate` simulations share the same base implementation to allow
+ * both pinching and rotation at the same time. The only difference is `pinch`
+ * requires `start` and `end` option properties while `rotate` requires `rotation`
+ * option property.
+ *
+ * The `pinch` and `rotate` gestures can be described as placing 2 fingers along a
+ * circle. Pinching and spreading can be described by start and end circles while
+ * rotation occurs on a single circle. If the radius of the start circle is greater
+ * than the end circle, the gesture becomes a pinch, otherwise it is a spread spread.
+ *
+ * @example
+ *
+ *     var node = Y.one("#target");
+ *
+ *     // double tap example
+ *     node.simulateGesture("doubletap", function() {
+ *         // my callback function
+ *     });
+ *
+ *     // flick example from the center of the node, move 50 pixels down for 50ms)
+ *     node.simulateGesture("flick", {
+ *         axis: y,
+ *         distance: -100
+ *         duration: 50
+ *     }, function() {
+ *         // my callback function
+ *     });
+ *
+ *     // simulate rotating a node 75 degrees counter-clockwise
+ *     node.simulateGesture("rotate", {
+ *         rotation: -75
+ *     });
+ *
+ *     // simulate a pinch and a rotation at the same time.
+ *     // fingers start on a circle of radius 100 px, placed at top/bottom
+ *     // fingers end on a circle of radius 50px, placed at right/left
+ *     node.simulateGesture("pinch", {
+ *         r1: 100,
+ *         r2: 50,
+ *         start: 0
+ *         rotation: 90
+ *     });
+ *
+ * @method simulateGesture
+ * @param {HTMLElement|Node} node The YUI node or HTML element that's the target
+ *      of the event.
+ * @param {String} name The name of the supported gesture to simulate. The
+ *      supported gesture name is one of "tap", "doubletap", "press", "move",
+ *      "flick", "pinch" and "rotate".
+ * @param {Object} [options] Extra options used to define the gesture behavior:
+ *
+ *      Valid options properties for the `tap` gesture:
+ *
+ *      @param {Array} [options.point] (Optional) Indicates the [x,y] coordinates
+ *        where the tap should be simulated. Default is the center of the node
+ *        element.
+ *      @param {Number} [options.hold=10] (Optional) The hold time in milliseconds.
+ *        This is the time between `touchstart` and `touchend` event generation.
+ *      @param {Number} [options.times=1] (Optional) Indicates the number of taps.
+ *      @param {Number} [options.delay=10] (Optional) The number of milliseconds
+ *        before the next tap simulation happens. This is valid only when `times`
+ *        is more than 1.
+ *
+ *      Valid options properties for the `doubletap` gesture:
+ *
+ *      @param {Array} [options.point] (Optional) Indicates the [x,y] coordinates
+ *        where the doubletap should be simulated. Default is the center of the
+ *        node element.
+ *
+ *      Valid options properties for the `press` gesture:
+ *
+ *      @param {Array} [options.point] (Optional) Indicates the [x,y] coordinates
+ *        where the press should be simulated. Default is the center of the node
+ *        element.
+ *      @param {Number} [options.hold=3000] (Optional) The hold time in milliseconds.
+ *        This is the time between `touchstart` and `touchend` event generation.
+ *        Default is 3000ms (3 seconds).
+ *
+ *      Valid options properties for the `move` gesture:
+ *
+ *      @param {Object} [options.path] (Optional) Indicates the path of the finger
+ *        movement. It's an object with three optional properties: `point`,
+ *        `xdist` and  `ydist`.
+ *        @param {Array} [options.path.point] A starting point of the gesture.
+ *          Default is the center of the node element.
+ *        @param {Number} [options.path.xdist=200] A distance to move in pixels
+ *          along the X axis. A negative distance value indicates moving left.
+ *        @param {Number} [options.path.ydist=0] A distance to move in pixels
+ *          along the Y axis. A negative distance value indicates moving up.
+ *      @param {Number} [options.duration=1000] (Optional) The duration of the
+ *        gesture in milliseconds.
+ *
+ *      Valid options properties for the `flick` gesture:
+ *
+ *      @param {Array} [options.point] (Optional) Indicates the [x, y] coordinates
+ *        where the flick should be simulated. Default is the center of the
+ *        node element.
+ *      @param {String} [options.axis='x'] (Optional) Valid values are either
+ *        "x" or "y". Indicates axis to move along. The flick can move to one of
+ *        4 directions(left, right, up and down).
+ *      @param {Number} [options.distance=200] (Optional) Distance to move in pixels
+ *      @param {Number} [options.duration=1000] (Optional) The duration of the
+ *        gesture in milliseconds. User given value could be automatically
+ *        adjusted by the framework if it is below the minimum velocity to be
+ *        a flick gesture.
+ *
+ *      Valid options properties for the `pinch` gesture:
+ *
+ *      @param {Array} [options.center] (Optional) The center of the circle where
+ *        two fingers are placed. Default is the center of the node element.
+ *      @param {Number} [options.r1] (Required) Pixel radius of the start circle
+ *        where 2 fingers will be on when the gesture starts. The circles are
+ *        centered at the center of the element.
+ *      @param {Number} [options.r2] (Required) Pixel radius of the end circle
+ *        when this gesture ends.
+ *      @param {Number} [options.duration=1000] (Optional) The duration of the
+ *        gesture in milliseconds.
+ *      @param {Number} [options.start=0] (Optional) Starting degree of the first
+ *        finger. The value is relative to the path of the north. Default is 0
+ *        (i.e., 12:00 on a clock).
+ *      @param {Number} [options.rotation=0] (Optional) Degrees to rotate from
+ *        the starting degree. A negative value means rotation to the
+ *        counter-clockwise direction.
+ *
+ *      Valid options properties for the `rotate` gesture:
+ *
+ *      @param {Array} [options.center] (Optional) The center of the circle where
+ *        two fingers are placed. Default is the center of the node element.
+ *      @param {Number} [options.r1] (Optional) Pixel radius of the start circle
+ *        where 2 fingers will be on when the gesture starts. The circles are
+ *        centered at the center of the element. Default is a fourth of the node
+ *        element width or height, whichever is smaller.
+ *      @param {Number} [options.r2] (Optional) Pixel radius of the end circle
+ *        when this gesture ends. Default is a fourth of the node element width or
+ *        height, whichever is smaller.
+ *      @param {Number} [options.duration=1000] (Optional) The duration of the
+ *        gesture in milliseconds.
+ *      @param {Number} [options.start=0] (Optional) Starting degree of the first
+ *        finger. The value is relative to the path of the north. Default is 0
+ *        (i.e., 12:00 on a clock).
+ *      @param {Number} [options.rotation] (Required) Degrees to rotate from
+ *        the starting degree. A negative value means rotation to the
+ *        counter-clockwise direction.
+ *
+ * @param {Function} [cb] The callback to execute when the asynchronouse gesture
+ *      simulation is completed.
+ *      @param {Error} cb.err An error object if the simulation is failed.
+ * @for Event
+ * @static
+ */
+Y.Event.simulateGesture = function(node, name, options, cb) {
+
+    node = Y.one(node);
+
+    var sim = new Y.GestureSimulation(node);
+    name = name.toLowerCase();
+
+    if(!cb && Y.Lang.isFunction(options)) {
+        cb = options;
+        options = {};
+    }
+
+    options = options || {};
+
+    if (gestureNames[name]) {
+        switch(name) {
+            // single-touch: point gestures
+            case 'tap':
+                sim.tap(cb, options.point, options.times, options.hold, options.delay);
+                break;
+            case 'doubletap':
+                sim.tap(cb, options.point, 2);
+                break;
+            case 'press':
+                if(!Y.Lang.isNumber(options.hold)) {
+                    options.hold = DEFAULTS.HOLD_PRESS;
+                } else if(options.hold < DEFAULTS.MIN_HOLD_PRESS) {
+                    options.hold = DEFAULTS.MIN_HOLD_PRESS;
+                } else if(options.hold > DEFAULTS.MAX_HOLD_PRESS) {
+                    options.hold = DEFAULTS.MAX_HOLD_PRESS;
+                }
+                sim.tap(cb, options.point, 1, options.hold);
+                break;
+
+            // single-touch: move gestures
+            case 'move':
+                sim.move(cb, options.path, options.duration);
+                break;
+            case 'flick':
+                sim.flick(cb, options.point, options.axis, options.distance,
+                    options.duration);
+                break;
+
+            // multi-touch: pinch/rotation gestures
+            case 'pinch':
+                sim.pinch(cb, options.center, options.r1, options.r2,
+                    options.duration, options.start, options.rotation);
+                break;
+            case 'rotate':
+                sim.rotate(cb, options.center, options.r1, options.r2,
+                    options.duration, options.start, options.rotation);
+                break;
+        }
+    } else {
+        Y.error(NAME+': Not a supported gesture simulation: '+name);
+    }
+};
+
+
+}, '3.17.2', {"requires": ["async-queue", "event-simulate", "node-screen"]});

Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/node-base/node-base-min.js
URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/node-base/node-base-min.js?rev=1609737&view=auto
==============================================================================
--- roller/trunk/app/src/main/webapp/roller-ui/yui3/node-base/node-base-min.js (added)
+++ roller/trunk/app/src/main/webapp/roller-ui/yui3/node-base/node-base-min.js Fri Jul 11 16:23:25 2014
@@ -0,0 +1,8 @@
+/*
+YUI 3.17.2 (build 9c3c78e)
+Copyright 2014 Yahoo! Inc. All rights reserved.
+Licensed under the BSD License.
+http://yuilibrary.com/license/
+*/
+
+YUI.add("node-base",function(e,t){var n=["hasClass","addClass","removeClass","replaceClass","toggleClass"];e.Node.importMethod(e.DOM,n),e.NodeList.importMethod(e.Node.prototype,n);var r=e.Node,i=e.DOM;r.create=function(t,n){return n&&n._node&&(n=n._node),e.one(i.create(t,n))},e.mix(r.prototype,{create:r.create,insert:function(e,t){return this._insert(e,t),this},_insert:function(e,t){var n=this._node,r=null;return typeof t=="number"?t=this._node.childNodes[t]:t&&t._node&&(t=t._node),e&&typeof e!="string"&&(e=e._node||e._nodes||e),r=i.addHTML(n,e,t),r},prepend:function(e){return this.insert(e,0)},append:function(e){return this.insert(e,null)},appendChild:function(e){return r.scrubVal(this._insert(e))},insertBefore:function(t,n){return e.Node.scrubVal(this._insert(t,n))},appendTo:function(t){return e.one(t).append(this),this},setContent:function(e){return this._insert(e,"replace"),this},getContent:function(){var e=this;return e._node.nodeType===11&&(e=e.create("<div/>").append(e.cloneN
 ode(!0))),e.get("innerHTML")}}),e.Node.prototype.setHTML=e.Node.prototype.setContent,e.Node.prototype.getHTML=e.Node.prototype.getContent,e.NodeList.importMethod(e.Node.prototype,["append","insert","appendChild","insertBefore","prepend","setContent","getContent","setHTML","getHTML"]);var r=e.Node,i=e.DOM;r.ATTRS={text:{getter:function(){return i.getText(this._node)},setter:function(e){return i.setText(this._node,e),e}},"for":{getter:function(){return i.getAttribute(this._node,"for")},setter:function(e){return i.setAttribute(this._node,"for",e),e}},options:{getter:function(){return this._node.getElementsByTagName("option")}},children:{getter:function(){var t=this._node,n=t.children,r,i,s;if(!n){r=t.childNodes,n=[];for(i=0,s=r.length;i<s;++i)r[i].tagName&&(n[n.length]=r[i])}return e.all(n)}},value:{getter:function(){return i.getValue(this._node)},setter:function(e){return i.setValue(this._node,e),e}}},e.Node.importMethod(e.DOM,["setAttribute","getAttribute"]);var r=e.Node,s=e.NodeList
 ;r.DOM_EVENTS={abort:1,beforeunload:1,blur:1,change:1,click:1,close:1,command:1,contextmenu:1,copy:1,cut:1,dblclick:1,DOMMouseScroll:1,drag:1,dragstart:1,dragenter:1,dragover:1,dragleave:1,dragend:1,drop:1,error:1,focus:1,key:1,keydown:1,keypress:1,keyup:1,load:1,message:1,mousedown:1,mouseenter:1,mouseleave:1,mousemove:1,mousemultiwheel:1,mouseout:1,mouseover:1,mouseup:1,mousewheel:1,orientationchange:1,paste:1,reset:1,resize:1,select:1,selectstart:1,submit:1,scroll:1,textInput:1,unload:1,invalid:1},e.mix(r.DOM_EVENTS,e.Env.evt.plugins),e.augment(r,e.EventTarget),e.mix(r.prototype,{purge:function(t,n){return e.Event.purgeElement(this._node,t,n),this}}),e.mix(e.NodeList.prototype,{_prepEvtArgs:function(t,n,r){var i=e.Array(arguments,0,!0);return i.length<2?i[2]=this._nodes:i.splice(2,0,this._nodes),i[3]=r||this,i},on:function(t,n,r){return e.on.apply(e,this._prepEvtArgs.apply(this,arguments))},once:function(t,n,r){return e.once.apply(e,this._prepEvtArgs.apply(this,arguments))},after
 :function(t,n,r){return e.after.apply(e,this._prepEvtArgs.apply(this,arguments))},onceAfter:function(t,n,r){return e.onceAfter.apply(e,this._prepEvtArgs.apply(this,arguments))}}),s.importMethod(e.Node.prototype,["detach","detachAll"]),e.mix(e.Node.ATTRS,{offsetHeight:{setter:function(t){return e.DOM.setHeight(this._node,t),t},getter:function(){return this._node.offsetHeight}},offsetWidth:{setter:function(t){return e.DOM.setWidth(this._node,t),t},getter:function(){return this._node.offsetWidth}}}),e.mix(e.Node.prototype,{sizeTo:function(t,n){var r;arguments.length<2&&(r=e.one(t),t=r.get("offsetWidth"),n=r.get("offsetHeight")),this.setAttrs({offsetWidth:t,offsetHeight:n})}}),e.config.doc.documentElement.hasAttribute||(e.Node.prototype.hasAttribute=function(e){return e==="value"&&this.get("value")!==""?!0:!!this._node.attributes[e]&&!!this._node.attributes[e].specified}),e.Node.prototype.focus=function(){try{this._node.focus()}catch(e){}return this},e.Node.ATTRS.type={setter:function(e
 ){if(e==="hidden")try{this._node.type="hidden"}catch(t){this._node.style.display="none",this._inputType="hidden"}else try{this._node.type=e}catch(t){}return e},getter:function(){return this._inputType||this._node.type},_bypassProxy:!0},e.config.doc.createElement("form").elements.nodeType&&(e.Node.ATTRS.elements={getter:function(){return this.all("input, textarea, button, select")}}),e.mix(e.Node.prototype,{_initData:function(){"_data"in this||(this._data={})},getData:function(t){this._initData();var n=this._data,r=n;return arguments.length?t in n?r=n[t]:r=this._getDataAttribute(t):typeof n=="object"&&n!==null&&(r={},e.Object.each(n,function(e,t){r[t]=e}),r=this._getDataAttributes(r)),r},_getDataAttributes:function(e){e=e||{};var t=0,n=this._node.attributes,r=n.length,i=this.DATA_PREFIX,s=i.length,o;while(t<r)o=n[t].name,o.indexOf(i)===0&&(o=o.substr(s),o in e||(e[o]=this._getDataAttribute(o))),t+=1;return e},_getDataAttribute:function(e){e=this.DATA_PREFIX+e;var t=this._node,n=t.att
 ributes,r=n&&n[e]&&n[e].value;return r},setData:function(e,t){return this._initData(),arguments.length>1?this._data[e]=t:this._data=e,this},clearData:function(e){return"_data"in this&&(typeof e!="undefined"?delete this._data[e]:delete this._data),this}}),e.mix(e.NodeList.prototype,{getData:function(e){var t=arguments.length?[e]:[];return this._invoke("getData",t,!0)},setData:function(e,t){var n=arguments.length>1?[e,t]:[e];return this._invoke("setData",n)},clearData:function(e){var t=arguments.length?[e]:[];return this._invoke("clearData",[e])}})},"3.17.2",{requires:["event-base","node-core","dom-base","dom-style"]});