Return-Path: X-Original-To: apmail-roller-commits-archive@www.apache.org Delivered-To: apmail-roller-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id AC67C11978 for ; Fri, 11 Jul 2014 16:24:27 +0000 (UTC) Received: (qmail 42442 invoked by uid 500); 11 Jul 2014 16:24:27 -0000 Delivered-To: apmail-roller-commits-archive@roller.apache.org Received: (qmail 42361 invoked by uid 500); 11 Jul 2014 16:24:27 -0000 Mailing-List: contact commits-help@roller.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@roller.apache.org Delivered-To: mailing list commits@roller.apache.org Received: (qmail 42346 invoked by uid 99); 11 Jul 2014 16:24:27 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 11 Jul 2014 16:24:27 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 11 Jul 2014 16:24:19 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id EDFAD2388BEC; Fri, 11 Jul 2014 16:23:35 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1609737 [8/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/ roll... Date: Fri, 11 Jul 2014 16:23:29 -0000 To: commits@roller.apache.org From: gmazza@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140711162335.EDFAD2388BEC@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/event-custom-complex/event-custom-complex.js URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/event-custom-complex/event-custom-complex.js?rev=1609737&view=auto ============================================================================== --- roller/trunk/app/src/main/webapp/roller-ui/yui3/event-custom-complex/event-custom-complex.js (added) +++ roller/trunk/app/src/main/webapp/roller-ui/yui3/event-custom-complex/event-custom-complex.js Fri Jul 11 16:23:25 2014 @@ -0,0 +1,677 @@ +/* +YUI 3.17.2 (build 9c3c78e) +Copyright 2014 Yahoo! Inc. All rights reserved. +Licensed under the BSD License. +http://yuilibrary.com/license/ +*/ + +YUI.add('event-custom-complex', function (Y, NAME) { + + +/** + * Adds event facades, preventable default behavior, and bubbling. + * events. + * @module event-custom + * @submodule event-custom-complex + */ + +var FACADE, + FACADE_KEYS, + YObject = Y.Object, + key, + EMPTY = {}, + CEProto = Y.CustomEvent.prototype, + ETProto = Y.EventTarget.prototype, + + mixFacadeProps = function(facade, payload) { + var p; + + for (p in payload) { + if (!(FACADE_KEYS.hasOwnProperty(p))) { + facade[p] = payload[p]; + } + } + }; + +/** + * Wraps and protects a custom event for use when emitFacade is set to true. + * Requires the event-custom-complex module + * @class EventFacade + * @param e {Event} the custom event + * @param currentTarget {HTMLElement} the element the listener was attached to + */ + +Y.EventFacade = function(e, currentTarget) { + + if (!e) { + e = EMPTY; + } + + this._event = e; + + /** + * The arguments passed to fire + * @property details + * @type Array + */ + this.details = e.details; + + /** + * The event type, this can be overridden by the fire() payload + * @property type + * @type string + */ + this.type = e.type; + + /** + * The real event type + * @property _type + * @type string + * @private + */ + this._type = e.type; + + ////////////////////////////////////////////////////// + + /** + * Node reference for the targeted eventtarget + * @property target + * @type Node + */ + this.target = e.target; + + /** + * Node reference for the element that the listener was attached to. + * @property currentTarget + * @type Node + */ + this.currentTarget = currentTarget; + + /** + * Node reference to the relatedTarget + * @property relatedTarget + * @type Node + */ + this.relatedTarget = e.relatedTarget; + +}; + +Y.mix(Y.EventFacade.prototype, { + + /** + * Stops the propagation to the next bubble target + * @method stopPropagation + */ + stopPropagation: function() { + this._event.stopPropagation(); + this.stopped = 1; + }, + + /** + * Stops the propagation to the next bubble target and + * prevents any additional listeners from being exectued + * on the current target. + * @method stopImmediatePropagation + */ + stopImmediatePropagation: function() { + this._event.stopImmediatePropagation(); + this.stopped = 2; + }, + + /** + * Prevents the event's default behavior + * @method preventDefault + */ + preventDefault: function() { + this._event.preventDefault(); + this.prevented = 1; + }, + + /** + * Stops the event propagation and prevents the default + * event behavior. + * @method halt + * @param immediate {boolean} if true additional listeners + * on the current target will not be executed + */ + halt: function(immediate) { + this._event.halt(immediate); + this.prevented = 1; + this.stopped = (immediate) ? 2 : 1; + } + +}); + +CEProto.fireComplex = function(args) { + + var es, + ef, + q, + queue, + ce, + ret = true, + events, + subs, + ons, + afters, + afterQueue, + postponed, + prevented, + preventedFn, + defaultFn, + self = this, + host = self.host || self, + next, + oldbubble, + stack = self.stack, + yuievt = host._yuievt, + hasPotentialSubscribers; + + if (stack) { + + // queue this event if the current item in the queue bubbles + if (self.queuable && self.type !== stack.next.type) { + + if (!stack.queue) { + stack.queue = []; + } + stack.queue.push([self, args]); + + return true; + } + } + + hasPotentialSubscribers = self.hasSubs() || yuievt.hasTargets || self.broadcast; + + self.target = self.target || host; + self.currentTarget = host; + + self.details = args.concat(); + + if (hasPotentialSubscribers) { + + es = stack || { + + id: self.id, // id of the first event in the stack + next: self, + silent: self.silent, + stopped: 0, + prevented: 0, + bubbling: null, + type: self.type, + // defaultFnQueue: new Y.Queue(), + defaultTargetOnly: self.defaultTargetOnly + + }; + + subs = self.getSubs(); + ons = subs[0]; + afters = subs[1]; + + self.stopped = (self.type !== es.type) ? 0 : es.stopped; + self.prevented = (self.type !== es.type) ? 0 : es.prevented; + + if (self.stoppedFn) { + // PERF TODO: Can we replace with callback, like preventedFn. Look into history + events = new Y.EventTarget({ + fireOnce: true, + context: host + }); + self.events = events; + events.on('stopped', self.stoppedFn); + } + + + self._facade = null; // kill facade to eliminate stale properties + + ef = self._createFacade(args); + + if (ons) { + self._procSubs(ons, args, ef); + } + + // bubble if this is hosted in an event target and propagation has not been stopped + if (self.bubbles && host.bubble && !self.stopped) { + oldbubble = es.bubbling; + + es.bubbling = self.type; + + if (es.type !== self.type) { + es.stopped = 0; + es.prevented = 0; + } + + ret = host.bubble(self, args, null, es); + + self.stopped = Math.max(self.stopped, es.stopped); + self.prevented = Math.max(self.prevented, es.prevented); + + es.bubbling = oldbubble; + } + + prevented = self.prevented; + + if (prevented) { + preventedFn = self.preventedFn; + if (preventedFn) { + preventedFn.apply(host, args); + } + } else { + defaultFn = self.defaultFn; + + if (defaultFn && ((!self.defaultTargetOnly && !es.defaultTargetOnly) || host === ef.target)) { + defaultFn.apply(host, args); + } + } + + // broadcast listeners are fired as discreet events on the + // YUI instance and potentially the YUI global. + if (self.broadcast) { + self._broadcast(args); + } + + if (afters && !self.prevented && self.stopped < 2) { + + // Queue the after + afterQueue = es.afterQueue; + + if (es.id === self.id || self.type !== yuievt.bubbling) { + + self._procSubs(afters, args, ef); + + if (afterQueue) { + while ((next = afterQueue.last())) { + next(); + } + } + } else { + postponed = afters; + + if (es.execDefaultCnt) { + postponed = Y.merge(postponed); + + Y.each(postponed, function(s) { + s.postponed = true; + }); + } + + if (!afterQueue) { + es.afterQueue = new Y.Queue(); + } + + es.afterQueue.add(function() { + self._procSubs(postponed, args, ef); + }); + } + + } + + self.target = null; + + if (es.id === self.id) { + + queue = es.queue; + + if (queue) { + while (queue.length) { + q = queue.pop(); + ce = q[0]; + // set up stack to allow the next item to be processed + es.next = ce; + ce._fire(q[1]); + } + } + + self.stack = null; + } + + ret = !(self.stopped); + + if (self.type !== yuievt.bubbling) { + es.stopped = 0; + es.prevented = 0; + self.stopped = 0; + self.prevented = 0; + } + + } else { + defaultFn = self.defaultFn; + + if(defaultFn) { + ef = self._createFacade(args); + + if ((!self.defaultTargetOnly) || (host === ef.target)) { + defaultFn.apply(host, args); + } + } + } + + // Kill the cached facade to free up memory. + // Otherwise we have the facade from the last fire, sitting around forever. + self._facade = null; + + return ret; +}; + +/** + * @method _hasPotentialSubscribers + * @for CustomEvent + * @private + * @return {boolean} Whether the event has potential subscribers or not + */ +CEProto._hasPotentialSubscribers = function() { + return this.hasSubs() || this.host._yuievt.hasTargets || this.broadcast; +}; + +/** + * Internal utility method to create a new facade instance and + * insert it into the fire argument list, accounting for any payload + * merging which needs to happen. + * + * This used to be called `_getFacade`, but the name seemed inappropriate + * when it was used without a need for the return value. + * + * @method _createFacade + * @private + * @param fireArgs {Array} The arguments passed to "fire", which need to be + * shifted (and potentially merged) when the facade is added. + * @return {EventFacade} The event facade created. + */ + +// TODO: Remove (private) _getFacade alias, once synthetic.js is updated. +CEProto._createFacade = CEProto._getFacade = function(fireArgs) { + + var userArgs = this.details, + firstArg = userArgs && userArgs[0], + firstArgIsObj = (firstArg && (typeof firstArg === "object")), + ef = this._facade; + + if (!ef) { + ef = new Y.EventFacade(this, this.currentTarget); + } + + if (firstArgIsObj) { + // protect the event facade properties + mixFacadeProps(ef, firstArg); + + // Allow the event type to be faked http://yuilibrary.com/projects/yui3/ticket/2528376 + if (firstArg.type) { + ef.type = firstArg.type; + } + + if (fireArgs) { + fireArgs[0] = ef; + } + } else { + if (fireArgs) { + fireArgs.unshift(ef); + } + } + + // update the details field with the arguments + ef.details = this.details; + + // use the original target when the event bubbled to this target + ef.target = this.originalTarget || this.target; + + ef.currentTarget = this.currentTarget; + ef.stopped = 0; + ef.prevented = 0; + + this._facade = ef; + + return this._facade; +}; + +/** + * Utility method to manipulate the args array passed in, to add the event facade, + * if it's not already the first arg. + * + * @method _addFacadeToArgs + * @private + * @param {Array} The arguments to manipulate + */ +CEProto._addFacadeToArgs = function(args) { + var e = args[0]; + + // Trying not to use instanceof, just to avoid potential cross Y edge case issues. + if (!(e && e.halt && e.stopImmediatePropagation && e.stopPropagation && e._event)) { + this._createFacade(args); + } +}; + +/** + * Stop propagation to bubble targets + * @for CustomEvent + * @method stopPropagation + */ +CEProto.stopPropagation = function() { + this.stopped = 1; + if (this.stack) { + this.stack.stopped = 1; + } + if (this.events) { + this.events.fire('stopped', this); + } +}; + +/** + * Stops propagation to bubble targets, and prevents any remaining + * subscribers on the current target from executing. + * @method stopImmediatePropagation + */ +CEProto.stopImmediatePropagation = function() { + this.stopped = 2; + if (this.stack) { + this.stack.stopped = 2; + } + if (this.events) { + this.events.fire('stopped', this); + } +}; + +/** + * Prevents the execution of this event's defaultFn + * @method preventDefault + */ +CEProto.preventDefault = function() { + if (this.preventable) { + this.prevented = 1; + if (this.stack) { + this.stack.prevented = 1; + } + } +}; + +/** + * Stops the event propagation and prevents the default + * event behavior. + * @method halt + * @param immediate {boolean} if true additional listeners + * on the current target will not be executed + */ +CEProto.halt = function(immediate) { + if (immediate) { + this.stopImmediatePropagation(); + } else { + this.stopPropagation(); + } + this.preventDefault(); +}; + +/** + * Registers another EventTarget as a bubble target. Bubble order + * is determined by the order registered. Multiple targets can + * be specified. + * + * Events can only bubble if emitFacade is true. + * + * Included in the event-custom-complex submodule. + * + * @method addTarget + * @chainable + * @param o {EventTarget} the target to add + * @for EventTarget + */ +ETProto.addTarget = function(o) { + var etState = this._yuievt; + + if (!etState.targets) { + etState.targets = {}; + } + + etState.targets[Y.stamp(o)] = o; + etState.hasTargets = true; + + return this; +}; + +/** + * Returns an array of bubble targets for this object. + * @method getTargets + * @return EventTarget[] + */ +ETProto.getTargets = function() { + var targets = this._yuievt.targets; + return targets ? YObject.values(targets) : []; +}; + +/** + * Removes a bubble target + * @method removeTarget + * @chainable + * @param o {EventTarget} the target to remove + * @for EventTarget + */ +ETProto.removeTarget = function(o) { + var targets = this._yuievt.targets; + + if (targets) { + delete targets[Y.stamp(o, true)]; + + if (YObject.size(targets) === 0) { + this._yuievt.hasTargets = false; + } + } + + return this; +}; + +/** + * Propagate an event. Requires the event-custom-complex module. + * @method bubble + * @param evt {CustomEvent} the custom event to propagate + * @return {boolean} the aggregated return value from Event.Custom.fire + * @for EventTarget + */ +ETProto.bubble = function(evt, args, target, es) { + + var targs = this._yuievt.targets, + ret = true, + t, + ce, + i, + bc, + ce2, + type = evt && evt.type, + originalTarget = target || (evt && evt.target) || this, + oldbubble; + + if (!evt || ((!evt.stopped) && targs)) { + + for (i in targs) { + if (targs.hasOwnProperty(i)) { + + t = targs[i]; + + ce = t._yuievt.events[type]; + + if (t._hasSiblings) { + ce2 = t.getSibling(type, ce); + } + + if (ce2 && !ce) { + ce = t.publish(type); + } + + oldbubble = t._yuievt.bubbling; + t._yuievt.bubbling = type; + + // if this event was not published on the bubble target, + // continue propagating the event. + if (!ce) { + if (t._yuievt.hasTargets) { + t.bubble(evt, args, originalTarget, es); + } + } else { + + if (ce2) { + ce.sibling = ce2; + } + + // set the original target to that the target payload on the facade is correct. + ce.target = originalTarget; + ce.originalTarget = originalTarget; + ce.currentTarget = t; + bc = ce.broadcast; + ce.broadcast = false; + + // default publish may not have emitFacade true -- that + // shouldn't be what the implementer meant to do + ce.emitFacade = true; + + ce.stack = es; + + // TODO: See what's getting in the way of changing this to use + // the more performant ce._fire(args || evt.details || []). + + // Something in Widget Parent/Child tests is not happy if we + // change it - maybe evt.details related? + ret = ret && ce.fire.apply(ce, args || evt.details || []); + + ce.broadcast = bc; + ce.originalTarget = null; + + // stopPropagation() was called + if (ce.stopped) { + break; + } + } + + t._yuievt.bubbling = oldbubble; + } + } + } + + return ret; +}; + +/** + * @method _hasPotentialSubscribers + * @for EventTarget + * @private + * @param {String} fullType The fully prefixed type name + * @return {boolean} Whether the event has potential subscribers or not + */ +ETProto._hasPotentialSubscribers = function(fullType) { + + var etState = this._yuievt, + e = etState.events[fullType]; + + if (e) { + return e.hasSubs() || etState.hasTargets || e.broadcast; + } else { + return false; + } +}; + +FACADE = new Y.EventFacade(); +FACADE_KEYS = {}; + +// Flatten whitelist +for (key in FACADE) { + FACADE_KEYS[key] = true; +} + + +}, '3.17.2', {"requires": ["event-custom-base"]}); Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/event-delegate/event-delegate-min.js URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/event-delegate/event-delegate-min.js?rev=1609737&view=auto ============================================================================== --- roller/trunk/app/src/main/webapp/roller-ui/yui3/event-delegate/event-delegate-min.js (added) +++ roller/trunk/app/src/main/webapp/roller-ui/yui3/event-delegate/event-delegate-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("event-delegate",function(e,t){function f(t,r,u,l){var c=n(arguments,0,!0),h=i(u)?u:null,p,d,v,m,g,y,b,w,E;if(s(t)){w=[];if(o(t))for(y=0,b=t.length;y1&&(g=p.shift(),c[0]=t=p.shift()),d=e.Node.DOM_EVENTS[t],s(d)&&d.delegate&&(E=d.delegate.apply(d,arguments));if(!E){if(!t||!r||!u||!l)return;v=h?e.Selector.query(h,null,!0):u,!v&&i(u)&&(E=e.on("available",function(){e.mix(E,e.delegate.apply(e,c),!0)},u)),!E&&v&&(c.splice(2,2,v),E=e.Event._attach(c,{facade:!1}),E.sub.filter=l,E.sub._notify=f.notifySub)}return E&&g&&(m=a[g]||(a[g]={}),m=m[t]||(m[t]=[]),m.push(E)),E}var n=e.Array,r=e.Lang,i=r.isString,s=r.isObject,o=r.isArray,u=e.Selector.test,a=e.Env.evt.handles;f.notifySub=function(t,r,i){r=r.slice(),this.args&&r.push.apply(r,this.args);var s=f._applyFilter(this.filter,r,i),o,u,a,l ;if(s){s=n(s),o=r[0]=new e.DOMEventFacade(r[0],i.el,i),o.container=e.one(i.el);for(u=0,a=s.length;uSets up event delegation on a container element. The delegated event + * will use a supplied selector or filtering function to test if the event + * references at least one node that should trigger the subscription + * callback.

+ * + *

Selector string filters will trigger the callback if the event originated + * from a node that matches it or is contained in a node that matches it. + * Function filters are called for each Node up the parent axis to the + * subscribing container node, and receive at each level the Node and the event + * object. The function should return true (or a truthy value) if that Node + * should trigger the subscription callback. Note, it is possible for filters + * to match multiple Nodes for a single event. In this case, the delegate + * callback will be executed for each matching Node.

+ * + *

For each matching Node, the callback will be executed with its 'this' + * object set to the Node matched by the filter (unless a specific context was + * provided during subscription), and the provided event's + * currentTarget will also be set to the matching Node. The + * containing Node from which the subscription was originally made can be + * referenced as e.container. + * + * @method delegate + * @param type {String} the event type to delegate + * @param fn {Function} the callback function to execute. This function + * will be provided the event object for the delegated event. + * @param el {String|node} the element that is the delegation container + * @param filter {string|Function} a selector that must match the target of the + * event or a function to test target and its parents for a match + * @param context optional argument that specifies what 'this' refers to. + * @param args* 0..n additional arguments to pass on to the callback function. + * These arguments will be added after the event object. + * @return {EventHandle} the detach handle + * @static + * @for Event + */ +function delegate(type, fn, el, filter) { + var args = toArray(arguments, 0, true), + query = isString(el) ? el : null, + typeBits, synth, container, categories, cat, i, len, handles, handle; + + // Support Y.delegate({ click: fnA, key: fnB }, el, filter, ...); + // and Y.delegate(['click', 'key'], fn, el, filter, ...); + if (isObject(type)) { + handles = []; + + if (isArray(type)) { + for (i = 0, len = type.length; i < len; ++i) { + args[0] = type[i]; + handles.push(Y.delegate.apply(Y, args)); + } + } else { + // Y.delegate({'click', fn}, el, filter) => + // Y.delegate('click', fn, el, filter) + args.unshift(null); // one arg becomes two; need to make space + + for (i in type) { + if (type.hasOwnProperty(i)) { + args[0] = i; + args[1] = type[i]; + handles.push(Y.delegate.apply(Y, args)); + } + } + } + + return new Y.EventHandle(handles); + } + + typeBits = type.split(/\|/); + + if (typeBits.length > 1) { + cat = typeBits.shift(); + args[0] = type = typeBits.shift(); + } + + synth = Y.Node.DOM_EVENTS[type]; + + if (isObject(synth) && synth.delegate) { + handle = synth.delegate.apply(synth, arguments); + } + + if (!handle) { + if (!type || !fn || !el || !filter) { + return; + } + + container = (query) ? Y.Selector.query(query, null, true) : el; + + if (!container && isString(el)) { + handle = Y.on('available', function () { + Y.mix(handle, Y.delegate.apply(Y, args), true); + }, el); + } + + if (!handle && container) { + args.splice(2, 2, container); // remove the filter + + handle = Y.Event._attach(args, { facade: false }); + handle.sub.filter = filter; + handle.sub._notify = delegate.notifySub; + } + } + + if (handle && cat) { + categories = detachCategories[cat] || (detachCategories[cat] = {}); + categories = categories[type] || (categories[type] = []); + categories.push(handle); + } + + return handle; +} + +/** +Overrides the _notify method on the normal DOM subscription to +inject the filtering logic and only proceed in the case of a match. + +This method is hosted as a private property of the `delegate` method +(e.g. `Y.delegate.notifySub`) + +@method notifySub +@param thisObj {Object} default 'this' object for the callback +@param args {Array} arguments passed to the event's fire() +@param ce {CustomEvent} the custom event managing the DOM subscriptions for + the subscribed event on the subscribing node. +@return {Boolean} false if the event was stopped +@private +@static +@since 3.2.0 +**/ +delegate.notifySub = function (thisObj, args, ce) { + // Preserve args for other subscribers + args = args.slice(); + if (this.args) { + args.push.apply(args, this.args); + } + + // Only notify subs if the event occurred on a targeted element + var currentTarget = delegate._applyFilter(this.filter, args, ce), + //container = e.currentTarget, + e, i, len, ret; + + if (currentTarget) { + // Support multiple matches up the the container subtree + currentTarget = toArray(currentTarget); + + // The second arg is the currentTarget, but we'll be reusing this + // facade, replacing the currentTarget for each use, so it doesn't + // matter what element we seed it with. + e = args[0] = new Y.DOMEventFacade(args[0], ce.el, ce); + + e.container = Y.one(ce.el); + + for (i = 0, len = currentTarget.length; i < len && !e.stopped; ++i) { + e.currentTarget = Y.one(currentTarget[i]); + + ret = this.fn.apply(this.context || e.currentTarget, args); + + if (ret === false) { // stop further notifications + break; + } + } + + return ret; + } +}; + +/** +Compiles a selector string into a filter function to identify whether +Nodes along the parent axis of an event's target should trigger event +notification. + +This function is memoized, so previously compiled filter functions are +returned if the same selector string is provided. + +This function may be useful when defining synthetic events for delegate +handling. + +Hosted as a property of the `delegate` method (e.g. `Y.delegate.compileFilter`). + +@method compileFilter +@param selector {String} the selector string to base the filtration on +@return {Function} +@since 3.2.0 +@static +**/ +delegate.compileFilter = Y.cached(function (selector) { + return function (target, e) { + return selectorTest(target._node, selector, + (e.currentTarget === e.target) ? null : e.currentTarget._node); + }; +}); + +/** +Regex to test for disabled elements during filtering. This is only relevant to +IE to normalize behavior with other browsers, which swallow events that occur +to disabled elements. IE fires the event from the parent element instead of the +original target, though it does preserve `event.srcElement` as the disabled +element. IE also supports disabled on ``, but the event still bubbles, so it +acts more like `e.preventDefault()` plus styling. That issue is not handled here +because other browsers fire the event on the ``, so delegate is supported in +both cases. + +@property _disabledRE +@type {RegExp} +@protected +@since 3.8.1 +**/ +delegate._disabledRE = /^(?:button|input|select|textarea)$/i; + +/** +Walks up the parent axis of an event's target, and tests each element +against a supplied filter function. If any Nodes, including the container, +satisfy the filter, the delegated callback will be triggered for each. + +Hosted as a protected property of the `delegate` method (e.g. +`Y.delegate._applyFilter`). + +@method _applyFilter +@param filter {Function} boolean function to test for inclusion in event + notification +@param args {Array} the arguments that would be passed to subscribers +@param ce {CustomEvent} the DOM event wrapper +@return {Node|Node[]|undefined} The Node or Nodes that satisfy the filter +@protected +**/ +delegate._applyFilter = function (filter, args, ce) { + var e = args[0], + container = ce.el, // facadeless events in IE, have no e.currentTarget + target = e.target || e.srcElement, + match = [], + isContainer = false; + + // Resolve text nodes to their containing element + if (target.nodeType === 3) { + target = target.parentNode; + } + + // For IE. IE propagates events from the parent element of disabled + // elements, where other browsers swallow the event entirely. To normalize + // this in IE, filtering for matching elements should abort if the target + // is a disabled form control. + if (target.disabled && delegate._disabledRE.test(target.nodeName)) { + return match; + } + + // passing target as the first arg rather than leaving well enough alone + // making 'this' in the filter function refer to the target. This is to + // support bound filter functions. + args.unshift(target); + + if (isString(filter)) { + while (target) { + isContainer = (target === container); + if (selectorTest(target, filter, (isContainer ? null: container))) { + match.push(target); + } + + if (isContainer) { + break; + } + + target = target.parentNode; + } + } else { + // filter functions are implementer code and should receive wrappers + args[0] = Y.one(target); + args[1] = new Y.DOMEventFacade(e, container, ce); + + while (target) { + // filter(target, e, extra args...) - this === target + if (filter.apply(args[0], args)) { + match.push(target); + } + + if (target === container) { + break; + } + + target = target.parentNode; + args[0] = Y.one(target); + } + args[1] = e; // restore the raw DOM event + } + + if (match.length <= 1) { + match = match[0]; // single match or undefined + } + + // remove the target + args.shift(); + + return match; +}; + +/** + * Sets up event delegation on a container element. The delegated event + * will use a supplied filter to test if the callback should be executed. + * This filter can be either a selector string or a function that returns + * a Node to use as the currentTarget for the event. + * + * The event object for the delegated event is supplied to the callback + * function. It is modified slightly in order to support all properties + * that may be needed for event delegation. 'currentTarget' is set to + * the element that matched the selector string filter or the Node returned + * from the filter function. 'container' is set to the element that the + * listener is delegated from (this normally would be the 'currentTarget'). + * + * Filter functions will be called with the arguments that would be passed to + * the callback function, including the event object as the first parameter. + * The function should return false (or a falsey value) if the success criteria + * aren't met, and the Node to use as the event's currentTarget and 'this' + * object if they are. + * + * @method delegate + * @param type {string} the event type to delegate + * @param fn {function} the callback function to execute. This function + * will be provided the event object for the delegated event. + * @param el {string|node} the element that is the delegation container + * @param filter {string|function} a selector that must match the target of the + * event or a function that returns a Node or false. + * @param context optional argument that specifies what 'this' refers to. + * @param args* 0..n additional arguments to pass on to the callback function. + * These arguments will be added after the event object. + * @return {EventHandle} the detach handle + * @for YUI + */ +Y.delegate = Y.Event.delegate = delegate; + + +}, '3.17.2', {"requires": ["node-base"]}); Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/event-flick/event-flick-min.js URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/event-flick/event-flick-min.js?rev=1609737&view=auto ============================================================================== --- roller/trunk/app/src/main/webapp/roller-ui/yui3/event-flick/event-flick-min.js (added) +++ roller/trunk/app/src/main/webapp/roller-ui/yui3/event-flick/event-flick-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("event-flick",function(e,t){var n=e.Event._GESTURE_MAP,r={start:n.start,end:n.end,move:n.move},i="start",s="end",o="move",u="ownerDocument",a="minVelocity",f="minDistance",l="preventDefault",c="_fs",h="_fsh",p="_feh",d="_fmh",v="nodeType";e.Event.define("flick",{on:function(e,t,n){var s=e.on(r[i],this._onStart,this,e,t,n);t[h]=s},detach:function(e,t,n){var r=t[h],i=t[p];r&&(r.detach(),t[h]=null),i&&(i.detach(),t[p]=null)},processArgs:function(t){var n=t.length>3?e.merge(t.splice(3,1)[0]):{};return a in n||(n[a]=this.MIN_VELOCITY),f in n||(n[f]=this.MIN_DISTANCE),l in n||(n[l]=this.PREVENT_DEFAULT),n},_onStart:function(t,n,i,a){var f=!0,l,h,m,g=i._extra.preventDefault,y=t;t.touches&&(f=t.touches.length===1,t=t.touches[0]),f&&(g&&(!g.call||g(t))&&y.preventDefault(),t.flick={time:(new Date).getTime()},i[c]=t,l=i[p],m=n.get(v)===9?n:n.get(u),l||(l=m.on(r[s],e.bind(this._onEnd,this),null,n,i,a),i[p]=l),i[d]=m.once(r[o],e.bind(this._onMove,this),null,n,i,a))},_onMove:function(e,t, n,r){var i=n[c];i&&i.flick&&(i.flick.time=(new Date).getTime())},_onEnd:function(e,t,n,r){var i=(new Date).getTime(),s=n[c],o=!!s,u=e,h,p,v,m,g,y,b,w,E=n[d];E&&(E.detach(),delete n[d]),o&&(e.changedTouches&&(e.changedTouches.length===1&&e.touches.length===0?u=e.changedTouches[0]:o=!1),o&&(m=n._extra,v=m[l],v&&(!v.call||v(e))&&e.preventDefault(),h=s.flick.time,i=(new Date).getTime(),p=i-h,g=[u.pageX-s.pageX,u.pageY-s.pageY],m.axis?w=m.axis:w=Math.abs(g[0])>=Math.abs(g[1])?"x":"y",y=g[w==="x"?0:1],b=p!==0?y/p:0,isFinite(b)&&Math.abs(y)>=m[f]&&Math.abs(b)>=m[a]&&(e.type="flick",e.flick={time:p,distance:y,velocity:b,axis:w,start:s},r.fire(e)),n[c]=null))},MIN_VELOCITY:0,MIN_DISTANCE:0,PREVENT_DEFAULT:!1})},"3.17.2",{requires:["node-base","event-touch","event-synthetic"]}); Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/event-flick/event-flick.js URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/event-flick/event-flick.js?rev=1609737&view=auto ============================================================================== --- roller/trunk/app/src/main/webapp/roller-ui/yui3/event-flick/event-flick.js (added) +++ roller/trunk/app/src/main/webapp/roller-ui/yui3/event-flick/event-flick.js Fri Jul 11 16:23:25 2014 @@ -0,0 +1,278 @@ +/* +YUI 3.17.2 (build 9c3c78e) +Copyright 2014 Yahoo! Inc. All rights reserved. +Licensed under the BSD License. +http://yuilibrary.com/license/ +*/ + +YUI.add('event-flick', function (Y, NAME) { + +/** + * The gestures module provides gesture events such as "flick", which normalize user interactions + * across touch and mouse or pointer based input devices. This layer can be used by application developers + * to build input device agnostic components which behave the same in response to either touch or mouse based + * interaction. + * + *

Documentation for events added by this module can be found in the event document for the YUI global.

+ * + * + @example + + YUI().use('event-flick', function (Y) { + Y.one('#myNode').on('flick', function (e) { + }); + }); + + * + * @module event-gestures + */ + +/** + * Adds support for a "flick" event, which is fired at the end of a touch or mouse based flick gesture, and provides + * velocity of the flick, along with distance and time information. + * + *

Documentation for the flick event can be found on the YUI global, + * along with the other supported events.

+ * + * @module event-gestures + * @submodule event-flick + */ +var GESTURE_MAP = Y.Event._GESTURE_MAP, + EVENT = { + start: GESTURE_MAP.start, + end: GESTURE_MAP.end, + move: GESTURE_MAP.move + }, + START = "start", + END = "end", + MOVE = "move", + + OWNER_DOCUMENT = "ownerDocument", + MIN_VELOCITY = "minVelocity", + MIN_DISTANCE = "minDistance", + PREVENT_DEFAULT = "preventDefault", + + _FLICK_START = "_fs", + _FLICK_START_HANDLE = "_fsh", + _FLICK_END_HANDLE = "_feh", + _FLICK_MOVE_HANDLE = "_fmh", + + NODE_TYPE = "nodeType"; + +/** + * Sets up a "flick" event, that is fired whenever the user initiates a flick gesture on the node + * where the listener is attached. The subscriber can specify a minimum distance or velocity for + * which the event is to be fired. The subscriber can also specify if there is a particular axis which + * they are interested in - "x" or "y". If no axis is specified, the axis along which there was most distance + * covered is used. + * + *

It is recommended that you use Y.bind to set up context and additional arguments for your event handler, + * however if you want to pass the context and arguments as additional signature arguments to "on", + * you need to provide a null value for the configuration object, e.g: node.on("flick", fn, null, context, arg1, arg2, arg3)

+ * + * @event flick + * @for YUI + * @param type {string} "flick" + * @param fn {function} The method the event invokes. It receives an event facade with an e.flick object containing the flick related properties: e.flick.time, e.flick.distance, e.flick.velocity and e.flick.axis, e.flick.start. + * @param cfg {Object} Optional. An object which specifies any of the following: + *
+ *
minDistance (in pixels, defaults to 10)
+ *
The minimum distance between start and end points, which would qualify the gesture as a flick.
+ *
minVelocity (in pixels/ms, defaults to 0)
+ *
The minimum velocity which would qualify the gesture as a flick.
+ *
preventDefault (defaults to false)
+ *
Can be set to true/false to prevent default behavior as soon as the touchstart/touchend or mousedown/mouseup is received so that things like scrolling or text selection can be + * prevented. This property can also be set to a function, which returns true or false, based on the event facade passed to it.
+ *
axis (no default)
+ *
Can be set to "x" or "y" if you want to constrain the flick velocity and distance to a single axis. If not + * defined, the axis along which the maximum distance was covered is used.
+ *
+ * @return {EventHandle} the detach handle + */ + +Y.Event.define('flick', { + + on: function (node, subscriber, ce) { + + var startHandle = node.on(EVENT[START], + this._onStart, + this, + node, + subscriber, + ce); + + subscriber[_FLICK_START_HANDLE] = startHandle; + }, + + detach: function (node, subscriber, ce) { + + var startHandle = subscriber[_FLICK_START_HANDLE], + endHandle = subscriber[_FLICK_END_HANDLE]; + + if (startHandle) { + startHandle.detach(); + subscriber[_FLICK_START_HANDLE] = null; + } + + if (endHandle) { + endHandle.detach(); + subscriber[_FLICK_END_HANDLE] = null; + } + }, + + processArgs: function(args) { + var params = (args.length > 3) ? Y.merge(args.splice(3, 1)[0]) : {}; + + if (!(MIN_VELOCITY in params)) { + params[MIN_VELOCITY] = this.MIN_VELOCITY; + } + + if (!(MIN_DISTANCE in params)) { + params[MIN_DISTANCE] = this.MIN_DISTANCE; + } + + if (!(PREVENT_DEFAULT in params)) { + params[PREVENT_DEFAULT] = this.PREVENT_DEFAULT; + } + + return params; + }, + + _onStart: function(e, node, subscriber, ce) { + + var start = true, // always true for mouse + endHandle, + moveHandle, + doc, + preventDefault = subscriber._extra.preventDefault, + origE = e; + + if (e.touches) { + start = (e.touches.length === 1); + e = e.touches[0]; + } + + if (start) { + + if (preventDefault) { + // preventDefault is a boolean or function + if (!preventDefault.call || preventDefault(e)) { + origE.preventDefault(); + } + } + + e.flick = { + time : new Date().getTime() + }; + + subscriber[_FLICK_START] = e; + + endHandle = subscriber[_FLICK_END_HANDLE]; + + doc = (node.get(NODE_TYPE) === 9) ? node : node.get(OWNER_DOCUMENT); + if (!endHandle) { + endHandle = doc.on(EVENT[END], Y.bind(this._onEnd, this), null, node, subscriber, ce); + subscriber[_FLICK_END_HANDLE] = endHandle; + } + + subscriber[_FLICK_MOVE_HANDLE] = doc.once(EVENT[MOVE], Y.bind(this._onMove, this), null, node, subscriber, ce); + } + }, + + _onMove: function(e, node, subscriber, ce) { + var start = subscriber[_FLICK_START]; + + // Start timing from first move. + if (start && start.flick) { + start.flick.time = new Date().getTime(); + } + }, + + _onEnd: function(e, node, subscriber, ce) { + + var endTime = new Date().getTime(), + start = subscriber[_FLICK_START], + valid = !!start, + endEvent = e, + startTime, + time, + preventDefault, + params, + xyDistance, + distance, + velocity, + axis, + moveHandle = subscriber[_FLICK_MOVE_HANDLE]; + + if (moveHandle) { + moveHandle.detach(); + delete subscriber[_FLICK_MOVE_HANDLE]; + } + + if (valid) { + + if (e.changedTouches) { + if (e.changedTouches.length === 1 && e.touches.length === 0) { + endEvent = e.changedTouches[0]; + } else { + valid = false; + } + } + + if (valid) { + + params = subscriber._extra; + preventDefault = params[PREVENT_DEFAULT]; + + if (preventDefault) { + // preventDefault is a boolean or function + if (!preventDefault.call || preventDefault(e)) { + e.preventDefault(); + } + } + + startTime = start.flick.time; + endTime = new Date().getTime(); + time = endTime - startTime; + + xyDistance = [ + endEvent.pageX - start.pageX, + endEvent.pageY - start.pageY + ]; + + if (params.axis) { + axis = params.axis; + } else { + axis = (Math.abs(xyDistance[0]) >= Math.abs(xyDistance[1])) ? 'x' : 'y'; + } + + distance = xyDistance[(axis === 'x') ? 0 : 1]; + velocity = (time !== 0) ? distance/time : 0; + + if (isFinite(velocity) && (Math.abs(distance) >= params[MIN_DISTANCE]) && (Math.abs(velocity) >= params[MIN_VELOCITY])) { + + e.type = "flick"; + e.flick = { + time:time, + distance: distance, + velocity:velocity, + axis: axis, + start : start + }; + + ce.fire(e); + + } + + subscriber[_FLICK_START] = null; + } + } + }, + + MIN_VELOCITY : 0, + MIN_DISTANCE : 0, + PREVENT_DEFAULT : false +}); + + +}, '3.17.2', {"requires": ["node-base", "event-touch", "event-synthetic"]}); Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/event-focus/event-focus-min.js URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/event-focus/event-focus-min.js?rev=1609737&view=auto ============================================================================== --- roller/trunk/app/src/main/webapp/roller-ui/yui3/event-focus/event-focus-min.js (added) +++ roller/trunk/app/src/main/webapp/roller-ui/yui3/event-focus/event-focus-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("event-focus",function(e,t){function u(t,r,u){var a="_"+t+"Notifiers";e.Event.define(t,{_useActivate:o,_attach:function(i,s,o){return e.DOM.isWindow(i)?n._attach([t,function(e){s.fire(e)},i]):n._attach([r,this._proxy,i,this,s,o],{capture:!0})},_proxy:function(t,r,i){var s=t.target,f=t.currentTarget,l=s.getData(a),c=e.stamp(f._node),h=o||s!==f,p;r.currentTarget=i?s:f,r.container=i?f:null,l?h=!0:(l={},s.setData(a,l),h&&(p=n._attach([u,this._notify,s._node]).sub,p.once=!0)),l[c]||(l[c]=[]),l[c].push(r),h||this._notify(t)},_notify:function(t,n){var r=t.currentTarget,i=r.getData(a),o=r.ancestors(),u=r.get("ownerDocument"),f=[],l=i?e.Object.keys(i).length:0,c,h,p,d,v,m,g,y,b,w;r.clearData(a),o.push(r),u&&o.unshift(u),o._nodes.reverse(),l&&(m=l,o.some(function(t){var n=e.stamp(t),r=i[n],s,o;if(r){l--;for(s=0,o=r.length;sdiv#b>input #a.on(focus..) #b.on(focus..), + // use one focus or blur subscription that fires notifiers from + // #b then #a to emulate bubble sequence. + if (!notifiers) { + notifiers = {}; + target.setData(nodeDataKey, notifiers); + + // only subscribe to the element's focus if the target is + // not the current target ( + if (defer) { + directSub = Event._attach( + [directEvent, this._notify, target._node]).sub; + directSub.once = true; + } + } else { + // In old IE, defer is always true. In capture-phase browsers, + // The delegate subscriptions will be encountered first, which + // will establish the notifiers data and direct subscription + // on the node. If there is also a direct subscription to the + // node's focus/blur, it should not call _notify because the + // direct subscription from the delegate sub(s) exists, which + // will call _notify. So this avoids _notify being called + // twice, unnecessarily. + defer = true; + } + + if (!notifiers[yuid]) { + notifiers[yuid] = []; + } + + notifiers[yuid].push(notifier); + + if (!defer) { + this._notify(e); + } + }, + + _notify: function (e, container) { + var currentTarget = e.currentTarget, + notifierData = currentTarget.getData(nodeDataKey), + axisNodes = currentTarget.ancestors(), + doc = currentTarget.get('ownerDocument'), + delegates = [], + // Used to escape loops when there are no more + // notifiers to consider + count = notifierData ? + Y.Object.keys(notifierData).length : + 0, + target, notifiers, notifier, yuid, match, tmp, i, len, sub, ret; + + // clear the notifications list (mainly for delegation) + currentTarget.clearData(nodeDataKey); + + // Order the delegate subs by their placement in the parent axis + axisNodes.push(currentTarget); + // document.get('ownerDocument') returns null + // which we'll use to prevent having duplicate Nodes in the list + if (doc) { + axisNodes.unshift(doc); + } + + // ancestors() returns the Nodes from top to bottom + axisNodes._nodes.reverse(); + + if (count) { + // Store the count for step 2 + tmp = count; + axisNodes.some(function (node) { + var yuid = Y.stamp(node), + notifiers = notifierData[yuid], + i, len; + + if (notifiers) { + count--; + for (i = 0, len = notifiers.length; i < len; ++i) { + if (notifiers[i].handle.sub.filter) { + delegates.push(notifiers[i]); + } + } + } + + return !count; + }); + count = tmp; + } + + // Walk up the parent axis, notifying direct subscriptions and + // testing delegate filters. + while (count && (target = axisNodes.shift())) { + yuid = Y.stamp(target); + + notifiers = notifierData[yuid]; + + if (notifiers) { + for (i = 0, len = notifiers.length; i < len; ++i) { + notifier = notifiers[i]; + sub = notifier.handle.sub; + match = true; + + e.currentTarget = target; + + if (sub.filter) { + match = sub.filter.apply(target, + [target, e].concat(sub.args || [])); + + // No longer necessary to test against this + // delegate subscription for the nodes along + // the parent axis. + delegates.splice( + arrayIndex(delegates, notifier), 1); + } + + if (match) { + // undefined for direct subs + e.container = notifier.container; + ret = notifier.fire(e); + } + + if (ret === false || e.stopped === 2) { + break; + } + } + + delete notifiers[yuid]; + count--; + } + + if (e.stopped !== 2) { + // delegates come after subs targeting this specific node + // because they would not normally report until they'd + // bubbled to the container node. + for (i = 0, len = delegates.length; i < len; ++i) { + notifier = delegates[i]; + sub = notifier.handle.sub; + + if (sub.filter.apply(target, + [target, e].concat(sub.args || []))) { + + e.container = notifier.container; + e.currentTarget = target; + ret = notifier.fire(e); + } + + if (ret === false || e.stopped === 2 || + // If e.stopPropagation() is called, notify any + // delegate subs from the same container, but break + // once the container changes. This emulates + // delegate() behavior for events like 'click' which + // won't notify delegates higher up the parent axis. + (e.stopped && delegates[i+1] && + delegates[i+1].container !== notifier.container)) { + break; + } + } + } + + if (e.stopped) { + break; + } + } + }, + + on: function (node, sub, notifier) { + sub.handle = this._attach(node._node, notifier); + }, + + detach: function (node, sub) { + sub.handle.detach(); + }, + + delegate: function (node, sub, notifier, filter) { + if (isString(filter)) { + sub.filter = function (target) { + return Y.Selector.test(target._node, filter, + node === target ? null : node._node); + }; + } + + sub.handle = this._attach(node._node, notifier, true); + }, + + detachDelegate: function (node, sub) { + sub.handle.detach(); + } + }, true); +} + +// For IE, we need to defer to focusin rather than focus because +// `el.focus(); doSomething();` executes el.onbeforeactivate, el.onactivate, +// el.onfocusin, doSomething, then el.onfocus. All others support capture +// phase focus, which executes before doSomething. To guarantee consistent +// behavior for this use case, IE's direct subscriptions are made against +// focusin so subscribers will be notified before js following el.focus() is +// executed. +if (useActivate) { + // name capture phase direct subscription + define("focus", "beforeactivate", "focusin"); + define("blur", "beforedeactivate", "focusout"); +} else { + define("focus", "focus", "focus"); + define("blur", "blur", "blur"); +} + + +}, '3.17.2', {"requires": ["event-synthetic"]}); Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/event-key/event-key-min.js URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/event-key/event-key-min.js?rev=1609737&view=auto ============================================================================== --- roller/trunk/app/src/main/webapp/roller-ui/yui3/event-key/event-key-min.js (added) +++ roller/trunk/app/src/main/webapp/roller-ui/yui3/event-key/event-key-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("event-key",function(e,t){var n="+alt",r="+ctrl",i="+meta",s="+shift",o=e.Lang.trim,u={KEY_MAP:{enter:13,space:32,esc:27,backspace:8,tab:9,pageup:33,pagedown:34},_typeRE:/^(up|down|press):/,_keysRE:/^(?:up|down|press):|\+(alt|ctrl|meta|shift)/g,processArgs:function(t){var n=t.splice(3,1)[0],r=e.Array.hash(n.match(/\+(?:alt|ctrl|meta|shift)\b/g)||[]),i={type:this._typeRE.test(n)?RegExp.$1:null,mods:r,keys:null},s=n.replace(this._keysRE,""),u,a,f,l;if(s){s=s.split(","),i.keys={};for(l=s.length-1;l>=0;--l){u=o(s[l]);if(!u)continue;+u==u?i.keys[u]=r:(f=u.toLowerCase(),this.KEY_MAP[f]?(i.keys[this.KEY_MAP[f]]=r,i.type||(i.type="down")):(u=u.charAt(0),a=u.toUpperCase(),r["+shift"]&&(u=a),i.keys[u.charCodeAt(0)]=u===a?e.merge(r,{"+shift":!0}):r))}}return i.type||(i.type="press"),i},on:function(e,t,o,u){var a=t._extra,f="key"+a.type,l=a.keys,c=u?"delegate":"on";t._detach=e[c](f,function(e){var t=l?l[e.which]:a.mods;t&&(!t[n]||t[n]&&e.altKey)&&(!t[r]||t[r]&&e.ctrlKey)&&(!t[i]||t[i]&& e.metaKey)&&(!t[s]||t[s]&&e.shiftKey)&&o.fire(e)},u)},detach:function(e,t,n){t._detach.detach()}};u.delegate=u.on,u.detachDelegate=u.detach,e.Event.define("key",u,!0)},"3.17.2",{requires:["event-synthetic"]}); Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/event-key/event-key.js URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/event-key/event-key.js?rev=1609737&view=auto ============================================================================== --- roller/trunk/app/src/main/webapp/roller-ui/yui3/event-key/event-key.js (added) +++ roller/trunk/app/src/main/webapp/roller-ui/yui3/event-key/event-key.js Fri Jul 11 16:23:25 2014 @@ -0,0 +1,179 @@ +/* +YUI 3.17.2 (build 9c3c78e) +Copyright 2014 Yahoo! Inc. All rights reserved. +Licensed under the BSD License. +http://yuilibrary.com/license/ +*/ + +YUI.add('event-key', function (Y, NAME) { + +/** + * Functionality to listen for one or more specific key combinations. + * @module event + * @submodule event-key + */ + +var ALT = "+alt", + CTRL = "+ctrl", + META = "+meta", + SHIFT = "+shift", + + trim = Y.Lang.trim, + + eventDef = { + KEY_MAP: { + enter : 13, + space : 32, + esc : 27, + backspace: 8, + tab : 9, + pageup : 33, + pagedown : 34 + }, + + _typeRE: /^(up|down|press):/, + _keysRE: /^(?:up|down|press):|\+(alt|ctrl|meta|shift)/g, + + processArgs: function (args) { + var spec = args.splice(3,1)[0], + mods = Y.Array.hash(spec.match(/\+(?:alt|ctrl|meta|shift)\b/g) || []), + config = { + type: this._typeRE.test(spec) ? RegExp.$1 : null, + mods: mods, + keys: null + }, + // strip type and modifiers from spec, leaving only keyCodes + bits = spec.replace(this._keysRE, ''), + chr, uc, lc, i; + + if (bits) { + bits = bits.split(','); + + config.keys = {}; + + // FIXME: need to support '65,esc' => keypress, keydown + for (i = bits.length - 1; i >= 0; --i) { + chr = trim(bits[i]); + + // catch sloppy filters, trailing commas, etc 'a,,' + if (!chr) { + continue; + } + + // non-numerics are single characters or key names + if (+chr == chr) { + config.keys[chr] = mods; + } else { + lc = chr.toLowerCase(); + + if (this.KEY_MAP[lc]) { + config.keys[this.KEY_MAP[lc]] = mods; + // FIXME: '65,enter' defaults keydown for both + if (!config.type) { + config.type = "down"; // safest + } + } else { + // FIXME: Character mapping only works for keypress + // events. Otherwise, it uses String.fromCharCode() + // from the keyCode, which is wrong. + chr = chr.charAt(0); + uc = chr.toUpperCase(); + + if (mods["+shift"]) { + chr = uc; + } + + // FIXME: stupid assumption that + // the keycode of the lower case == the + // charCode of the upper case + // a (key:65,char:97), A (key:65,char:65) + config.keys[chr.charCodeAt(0)] = + (chr === uc) ? + // upper case chars get +shift free + Y.merge(mods, { "+shift": true }) : + mods; + } + } + } + } + + if (!config.type) { + config.type = "press"; + } + + return config; + }, + + on: function (node, sub, notifier, filter) { + var spec = sub._extra, + type = "key" + spec.type, + keys = spec.keys, + method = (filter) ? "delegate" : "on"; + + // Note: without specifying any keyCodes, this becomes a + // horribly inefficient alias for 'keydown' (et al), but I + // can't abort this subscription for a simple + // Y.on('keypress', ...); + // Please use keyCodes or just subscribe directly to keydown, + // keyup, or keypress + sub._detach = node[method](type, function (e) { + var key = keys ? keys[e.which] : spec.mods; + + if (key && + (!key[ALT] || (key[ALT] && e.altKey)) && + (!key[CTRL] || (key[CTRL] && e.ctrlKey)) && + (!key[META] || (key[META] && e.metaKey)) && + (!key[SHIFT] || (key[SHIFT] && e.shiftKey))) + { + notifier.fire(e); + } + }, filter); + }, + + detach: function (node, sub, notifier) { + sub._detach.detach(); + } + }; + +eventDef.delegate = eventDef.on; +eventDef.detachDelegate = eventDef.detach; + +/** + *

Add a key listener. The listener will only be notified if the + * keystroke detected meets the supplied specification. The + * specification is a string that is defined as:

+ * + *
+ *
spec
+ *
[{type}:]{code}[,{code}]*
+ *
type
+ *
"down", "up", or "press"
+ *
code
+ *
{keyCode|character|keyName}[+{modifier}]*
+ *
modifier
+ *
"shift", "ctrl", "alt", or "meta"
+ *
keyName
+ *
"enter", "space", "backspace", "esc", "tab", "pageup", or "pagedown"
+ *
+ * + *

Examples:

+ *
    + *
  • Y.on("key", callback, "press:12,65+shift+ctrl", "#my-input");
  • + *
  • Y.delegate("key", preventSubmit, "#forms", "enter", "input[type=text]");
  • + *
  • Y.one("doc").on("key", viNav, "j,k,l,;");
  • + *
+ * + * @event key + * @for YUI + * @param type {string} 'key' + * @param fn {function} the function to execute + * @param id {string|HTMLElement|collection} the element(s) to bind + * @param spec {string} the keyCode and modifier specification + * @param o optional context object + * @param args 0..n additional arguments to provide to the listener. + * @return {Event.Handle} the detach handle + */ +Y.Event.define('key', eventDef, true); + + +}, '3.17.2', {"requires": ["event-synthetic"]}); Added: roller/trunk/app/src/main/webapp/roller-ui/yui3/event-simulate/event-simulate-min.js URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/webapp/roller-ui/yui3/event-simulate/event-simulate-min.js?rev=1609737&view=auto ============================================================================== --- roller/trunk/app/src/main/webapp/roller-ui/yui3/event-simulate/event-simulate-min.js (added) +++ roller/trunk/app/src/main/webapp/roller-ui/yui3/event-simulate/event-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("event-simulate",function(e,t){(function(){function v(t,n,a,f,l,c,h,p,d,v,m){t||e.error("simulateKeyEvent(): Invalid target.");if(i(n)){n=n.toLowerCase();switch(n){case"textevent":n="keypress";break;case"keyup":case"keydown":case"keypress":break;default:e.error("simulateKeyEvent(): Event type '"+n+"' not supported.")}}else e.error("simulateKeyEvent(): Event type must be a string.");s(a)||(a=!0),s(f)||(f=!0),o(l)||(l=e.config.win),s(c)||(c=!1),s(h)||(h=!1),s(p)||(p=!1),s(d)||(d=!1),u(v)||(v=0),u(m)||(m=0);var g=null;if(r(e.config.doc.createEvent)){try{g=e.config.doc.createEvent("KeyEvents"),g.initKeyEvent(n,a,f,l,c,h,p,d,v,m)}catch(y){try{g=e.config.doc.createEvent("Events")}catch(b){g=e.config.doc.createEvent("UIEvents")}finally{g.initEvent(n,a,f),g.view=l,g.altKey=h,g.ctrlKey=c,g.shiftKey=p,g.metaKey=d,g.keyCode=v,g.charCode=m}}t.dispatchEvent(g)}else o(e.config.doc.createEventObject)?(g=e.config.doc.createEventObject(),g.bubbles=a,g.cancelable=f,g.view=l,g.ctrlKey=c,g.altK ey=h,g.shiftKey=p,g.metaKey=d,g.keyCode=m>0?m:v,t.fireEvent("on"+n,g)):e.error("simulateKeyEvent(): No event simulation framework present.")}function m(t,n,l,c,h,p,d,v,m,g,y,b,w,E,S,x){t||e.error("simulateMouseEvent(): Invalid target."),i(n)?!a[n.toLowerCase()]&&!f[n]&&e.error("simulateMouseEvent(): Event type '"+n+"' not supported."):e.error("simulateMouseEvent(): Event type must be a string."),s(l)||(l=!0),s(c)||(c=n!=="mousemove"),o(h)||(h=e.config.win),u(p)||(p=1),u(d)||(d=0),u(v)||(v=0),u(m)||(m=0),u(g)||(g=0),s(y)||(y=!1),s(b)||(b=!1),s(w)||(w=!1),s(E)||(E=!1),u(S)||(S=0),x=x||null;var T=null;if(r(e.config.doc.createEvent))T=e.config.doc.createEvent("MouseEvents"),T.initMouseEvent?T.initMouseEvent(n,l,c,h,p,d,v,m,g,y,b,w,E,S,x):(T=e.config.doc.createEvent("UIEvents"),T.initEvent(n,l,c),T.view=h,T.detail=p,T.screenX=d,T.screenY=v,T.clientX=m,T.clientY=g,T.ctrlKey=y,T.altKey=b,T.metaKey=E,T.shiftKey=w,T.button=S,T.relatedTarget=x),x&&!T.relatedTarget&&(n==="mouseout"?T.toElement =x:n==="mouseover"&&(T.fromElement=x)),t.dispatchEvent(T);else if(o(e.config.doc.createEventObject)){T=e.config.doc.createEventObject(),T.bubbles=l,T.cancelable=c,T.view=h,T.detail=p,T.screenX=d,T.screenY=v,T.clientX=m,T.clientY=g,T.ctrlKey=y,T.altKey=b,T.metaKey=E,T.shiftKey=w;switch(S){case 0:T.button=1;break;case 1:T.button=4;break;case 2:break;default:T.button=0}T.relatedTarget=x,t.fireEvent("on"+n,T)}else e.error("simulateMouseEvent(): No event simulation framework present.")}function g(t,n,a,f,l,p){t||e.error("simulateUIEvent(): Invalid target."),i(n)?(n=n.toLowerCase(),c[n]||e.error("simulateUIEvent(): Event type '"+n+"' not supported.")):e.error("simulateUIEvent(): Event type must be a string.");var d=null;s(a)||(a=n in h),s(f)||(f=n==="submit"),o(l)||(l=e.config.win),u(p)||(p=1),r(e.config.doc.createEvent)?(d=e.config.doc.createEvent("UIEvents"),d.initUIEvent(n,a,f,l,p),t.dispatchEvent(d)):o(e.config.doc.createEventObject)?(d=e.config.doc.createEventObject(),d.bubbles=a,d.c ancelable=f,d.view=l,d.detail=p,t.fireEvent("on"+n,d)):e.error("simulateUIEvent(): No event simulation framework present.")}function y(t,n,r,i,s,o,u,a,f,l,c,h,p,v,m,g){var y;(!e.UA.ios||e.UA.ios<2)&&e.error("simulateGestureEvent(): Native gesture DOM eventframe is not available in this platform."),t||e.error("simulateGestureEvent(): Invalid target."),e.Lang.isString(n)?(n=n.toLowerCase(),d[n]||e.error("simulateTouchEvent(): Event type '"+n+"' not supported.")):e.error("simulateGestureEvent(): Event type must be a string."),e.Lang.isBoolean(r)||(r=!0),e.Lang.isBoolean(i)||(i=!0),e.Lang.isObject(s)||(s=e.config.win),e.Lang.isNumber(o)||(o=2),e.Lang.isNumber(u)||(u=0),e.Lang.isNumber(a)||(a=0),e.Lang.isNumber(f)||(f=0),e.Lang.isNumber(l)||(l=0),e.Lang.isBoolean(c)||(c=!1),e.Lang.isBoolean(h)||(h=!1),e.Lang.isBoolean(p)||(p=!1),e.Lang.isBoolean(v)||(v=!1),e.Lang.isNumber(m)||(m=1),e.Lang.isNumber(g)||(g=0),y=e.config.doc.createEvent("GestureEvent"),y.initGestureEvent(n,r,i,s,o,u,a,f,l,c ,h,p,v,t,m,g),t.dispatchEvent(y)}function b(t,n,r,i,s,o,u,a,f,l,c,h,d,v,m,g,y,b,w){var E;t||e.error("simulateTouchEvent(): Invalid target."),e.Lang.isString(n)?(n=n.toLowerCase(),p[n]||e.error("simulateTouchEvent(): Event type '"+n+"' not supported.")):e.error("simulateTouchEvent(): Event type must be a string."),n==="touchstart"||n==="touchmove"?m.length===0&&e.error("simulateTouchEvent(): No touch object in touches"):n==="touchend"&&y.length===0&&e.error("simulateTouchEvent(): No touch object in changedTouches"),e.Lang.isBoolean(r)||(r=!0),e.Lang.isBoolean(i)||(i=n!=="touchcancel"),e.Lang.isObject(s)||(s=e.config.win),e.Lang.isNumber(o)||(o=1),e.Lang.isNumber(u)||(u=0),e.Lang.isNumber(a)||(a=0),e.Lang.isNumber(f)||(f=0),e.Lang.isNumber(l)||(l=0),e.Lang.isBoolean(c)||(c=!1),e.Lang.isBoolean(h)||(h=!1),e.Lang.isBoolean(d)||(d=!1),e.Lang.isBoolean(v)||(v=!1),e.Lang.isNumber(b)||(b=1),e.Lang.isNumber(w)||(w=0),e.Lang.isFunction(e.config.doc.createEvent)?(e.UA.android?e.UA.android<4?(E =e.config.doc.createEvent("MouseEvents"),E.initMouseEvent(n,r,i,s,o,u,a,f,l,c,h,d,v,0,t),E.touches=m,E.targetTouches=g,E.changedTouches=y):(E=e.config.doc.createEvent("TouchEvent"),E.initTouchEvent(m,g,y,n,s,u,a,f,l,c,h,d,v)):e.UA.ios?e.UA.ios>=2?(E=e.config.doc.createEvent("TouchEvent"),E.initTouchEvent(n,r,i,s,o,u,a,f,l,c,h,d,v,m,g,y,b,w)):e.error("simulateTouchEvent(): No touch event simulation framework present for iOS, "+e.UA.ios+"."):e.error("simulateTouchEvent(): Not supported agent yet, "+e.UA.userAgent),t.dispatchEvent(E)):e.error("simulateTouchEvent(): No event simulation framework present.")}var t=e.Lang,n=e.config.win,r=t.isFunction,i=t.isString,s=t.isBoolean,o=t.isObject,u=t.isNumber,a={click:1,dblclick:1,mouseover:1,mouseout:1,mousedown:1,mouseup:1,mousemove:1,contextmenu:1},f=n&&n.PointerEvent?{pointerover:1,pointerout:1,pointerdown:1,pointerup:1,pointermove:1}:{MSPointerOver:1,MSPointerOut:1,MSPointerDown:1,MSPointerUp:1,MSPointerMove:1},l={keydown:1,keyup:1,keypress :1},c={submit:1,blur +:1,change:1,focus:1,resize:1,scroll:1,select:1},h={scroll:1,resize:1,reset:1,submit:1,change:1,select:1,error:1,abort:1},p={touchstart:1,touchmove:1,touchend:1,touchcancel:1},d={gesturestart:1,gesturechange:1,gestureend:1};e.mix(h,a),e.mix(h,l),e.mix(h,p),e.Event.simulate=function(t,n,r){r=r||{},a[n]||f[n]?m(t,n,r.bubbles,r.cancelable,r.view,r.detail,r.screenX,r.screenY,r.clientX,r.clientY,r.ctrlKey,r.altKey,r.shiftKey,r.metaKey,r.button,r.relatedTarget):l[n]?v(t,n,r.bubbles,r.cancelable,r.view,r.ctrlKey,r.altKey,r.shiftKey,r.metaKey,r.keyCode,r.charCode):c[n]?g(t,n,r.bubbles,r.cancelable,r.view,r.detail):p[n]?e.config.win&&"ontouchstart"in e.config.win&&!e.UA.phantomjs&&!(e.UA.chrome&&e.UA.chrome<6)?b(t,n,r.bubbles,r.cancelable,r.view,r.detail,r.screenX,r.screenY,r.clientX,r.clientY,r.ctrlKey,r.altKey,r.shiftKey,r.metaKey,r.touches,r.targetTouches,r.changedTouches,r.scale,r.rotation):e.error("simulate(): Event '"+n+"' can't be simulated. Use gesture-simulate module instead."):e.UA. ios&&e.UA.ios>=2&&d[n]?y(t,n,r.bubbles,r.cancelable,r.view,r.detail,r.screenX,r.screenY,r.clientX,r.clientY,r.ctrlKey,r.altKey,r.shiftKey,r.metaKey,r.scale,r.rotation):e.error("simulate(): Event '"+n+"' can't be simulated.")}})()},"3.17.2",{requires:["event-base"]});