Daniel Werner has uploaded a new change for review.
https://gerrit.wikimedia.org/r/79148
Change subject: Moves the jQuery.NativeEventHandler from Wikibase\Lib into
ValueView extension
......................................................................
Moves the jQuery.NativeEventHandler from Wikibase\Lib into ValueView extension
Introduces a few minor changes while moving this:
- Gets rid of all Wikibase/MediaWiki dependencies in tests.
- Some cleanup done in test files, moved basic test definition in separate file.
- Some coding style changes, most notably multi-var statements replacing
single-var.
- Cleanup in comments and documentation.
Change-Id: Ia207fdea460a64142cef3dc427d364db353183d3
---
M ValueView/ValueView.resources.mw.php
M ValueView/ValueView.tests.qunit.php
M ValueView/resources/jquery.ui/jquery.ui.inputextender.js
A ValueView/resources/jquery/jquery.nativeEventHandler.js
A ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.test.js
A
ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.test.testDefinition.js
A
ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.testsOnObject.js
A
ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.testsOnWidget.js
8 files changed, 746 insertions(+), 45 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/DataValues
refs/changes/48/79148/1
diff --git a/ValueView/ValueView.resources.mw.php
b/ValueView/ValueView.resources.mw.php
index 0286208..1a556f2 100644
--- a/ValueView/ValueView.resources.mw.php
+++ b/ValueView/ValueView.resources.mw.php
@@ -71,6 +71,12 @@
),
),
+ 'jquery.nativeEventHandler' => $moduleTemplate + array(
+ 'scripts' => array(
+ 'jquery/jquery.nativeEventHandler.js',
+ )
+ ),
+
'jquery.eachchange' => $moduleTemplate + array(
'scripts' => array(
'jquery/jquery.eachchange.js'
diff --git a/ValueView/ValueView.tests.qunit.php
b/ValueView/ValueView.tests.qunit.php
index e909c30..82692ac 100644
--- a/ValueView/ValueView.tests.qunit.php
+++ b/ValueView/ValueView.tests.qunit.php
@@ -54,6 +54,18 @@
),
),
+ 'jquery.nativeEventHandler.tests' => array(
+ 'scripts' => array(
+
"$bp/jquery.NativeEventHandler/NativeEventHandler.test.js",
+
"$bp/jquery.NativeEventHandler/NativeEventHandler.test.testDefinition.js",
+
"$bp/jquery.NativeEventHandler/NativeEventHandler.testsOnObject.js",
+
"$bp/jquery.NativeEventHandler/NativeEventHandler.testsOnWidget.js",
+ ),
+ 'dependencies' => array(
+ 'jquery.nativeEventHandler',
+ ),
+ ),
+
'jquery.eachchange.tests' => array(
'scripts' => array(
"$bp/jquery/jquery.eachchange.tests.js",
diff --git a/ValueView/resources/jquery.ui/jquery.ui.inputextender.js
b/ValueView/resources/jquery.ui/jquery.ui.inputextender.js
index e897667..1df5bc2 100644
--- a/ValueView/resources/jquery.ui/jquery.ui.inputextender.js
+++ b/ValueView/resources/jquery.ui/jquery.ui.inputextender.js
@@ -20,19 +20,13 @@
* hidden when the associated input element is empty.
* Default value: true
*
- * @option {string} [contentAnimationEvents] One or more events (separated
with spaces) which imply
- * that the input extenders extension's content is about to be
animated. Those events should
- * give a jQuery.AnimationEvent object as their event object. If this
is the case and the
- * event bubbles up to the input extender's extension node, then this
will trigger the
- * "contentanimation" event on the widget node.
- *
- * @event animation: Triggered at the beginning of an animation of the input's
extension.
- * (1) {jQuery.AnimationEvent} animationEvent
- *
- * @event contentanimation: Triggered at the beginning of an animation of the
extender's
- * extension content. Depends on the "contentAnimationEvents" option.
- * (1) {jQuery.AnimationEvent} animationEvent The animation event gets
passed on from the
- * event within the input extender's extension causing the
"contentanimation" event.
+ * @event animationstep: While the input extender's extension is being
animated, this event is
+ * triggered on each animation step. The event forwards the parameters
received from the
+ * animation's "step" callback. However, when the animation is
finished, the event is
+ * triggered without the second and third parameter.
+ * (1) {jQuery.Event}
+ * (2) {number|undefined} [now]
+ * (3) {jQuery.Tween|undefined} [tween]
*
* @dependency jQuery.Widget
* @dependency jQuery.eachchange
@@ -83,7 +77,6 @@
*/
options: {
content: [],
- contentAnimationEvents: '',
initCallback: null,
hideWhenInputEmpty: true,
position: {
@@ -225,7 +218,7 @@
/**
* Shows the extension.
*
- * @param {Function} [callback] Invoked as soon as the
extension's show animation is done.
+ * @param {Function} [callback] Invoked as soon as the contents
are visible.
*/
showExtension: function( callback ) {
if( !this._isExtended ) {
@@ -237,7 +230,7 @@
/**
* Hides the extension.
*
- * @param {Function} [callback] Invoked as soon as the
extension's hide animation is done.
+ * @param {Function} [callback] Invoked as soon as the contents
are hidden.
*/
hideExtension: function( callback ) {
if( this._isExtended ) {
@@ -280,6 +273,12 @@
/**
* Draws the widget.
+ *
+ * @param {Function} [callback] For private usage only.
+ * TODO: Get rid of "callback", introduce some sort of
"animationstart" event instead,
+ * offering an object allowing to register callback that will
be given into the animation's
+ * options. show/hideExtension can then do a .one() event
registration for that one and
+ * register their callback there.
*/
draw: function( /* private: */ callback ) {
this.element[ this._isExtended ? 'addClass' :
'removeClass' ](
@@ -301,6 +300,7 @@
this.$extension = $extension =
this._buildExtension();
$extension.appendTo( $( 'body' ) );
+ // TODO
if( $.isFunction( this.options.initCallback ) )
{
$extension.show();
this.options.initCallback.call( this,
$extension );
@@ -337,43 +337,37 @@
this.$extension.css( 'opacity', '1' );
}
- this.$extension.stop( true ).animateWithEvent(
- 'extensionexpansion',
- 'fadeIn',
- {
- duration: 150,
- complete: function() {
- if( $.isFunction( callback ) ) {
- callback();
- }
- }
+ this.$extension.stop( true ).fadeIn( {
+ duration: 150,
+ step: function( now, tween ) {
+ self._trigger( 'animationstep', null, [
now, tween ] );
},
- function( animationEvent ) {
- self._trigger( 'animation',
animationEvent );
+ complete: function() {
+ if( $.isFunction( callback ) ) {
+ callback();
+ }
+ self._trigger( 'animationstep' );
}
- );
+ } );
inputExtendersWithVisibleExtension.add( this );
},
_drawExtensionRemoval: function( callback ) {
var self = this;
- this.$extension.stop( true ).animateWithEvent(
- 'extensionremoval',
- 'fadeOut',
- {
- duration: 150,
- complete: function() {
-
inputExtendersWithVisibleExtension.remove( self );
- if( $.isFunction( callback ) ) {
- callback();
- }
- }
+ this.$extension.stop( true ).fadeOut( {
+ duration: 150,
+ step: function( now, tween ) {
+ self._trigger( 'animationstep', null, [
now, tween ] );
},
- function( animationEvent ) {
- self._trigger( 'animation',
animationEvent );
+ complete: function() {
+
inputExtendersWithVisibleExtension.remove( this );
+ if( $.isFunction( callback ) ) {
+ callback();
+ }
+ self._trigger( 'animationstep' );
}
- );
+ } );
},
/**
@@ -416,8 +410,10 @@
self.showExtension();
}
} )
- .on( this.options.contentAnimationEvents, function(
animationEvent ) {
- self._trigger( 'contentanimation',
animationEvent );
+ // TODO: move this out of here, toggler is not even
used/known to this widget:
+ .on( 'toggleranimationstep.' + this.widgetName,
function( event, now, tween ) {
+ self._reposition();
+ self._trigger( 'animationstep', null, [ now,
tween ] );
} )
.on( 'keydown.' + this.widgetName, function( event ) {
// Take care of tabbing out of the extension
again:
diff --git a/ValueView/resources/jquery/jquery.nativeEventHandler.js
b/ValueView/resources/jquery/jquery.nativeEventHandler.js
new file mode 100644
index 0000000..0cca3e5
--- /dev/null
+++ b/ValueView/resources/jquery/jquery.nativeEventHandler.js
@@ -0,0 +1,224 @@
+/**
+ * @file
+ *
+ * @licence GNU GPL v2+
+ * @author Daniel Werner < [email protected] >
+ *
+ * Returns a function (outer function) which executes some given logic and
does additional event
+ * handling for a given event. The event handling is separated in up to three
steps and handles
+ * advanced features offered by jQuery. The following steps (handlers) in
detail:
+ *
+ * - initial handler: Executes some initial logic which allows to cancel the
whole process. All
+ * parameters given to the outer function are available as well as the
related jQuery.Event
+ * object. The jQuery.Event object can be
+ * used to cancel all further event handlers (jQuery.Event.cancel()) or to
prevent only the
+ * custom handlers to be
+ * executed (jQuery.Event.stopImmediatePropagation() or prevent only the
native handler to be
+ * executed (jQuery.Event.preventDefault()). jQuery.Event.handlerArgs can be
set to an array
+ * to define all arguments propagated to all handlers if not defined
otherwise by one of the
+ * other ...HandlerArgs fields. jQuery.Event.customHandlerArgs can be set to
an array to
+ * define all arguments propagated to custom handlers, the jQuery.Event
object itself will
+ * always be given to the custom handlers. jQuery.Event.nativeHandlerArgs
can be set to an
+ * array which acts as equivalent for the native handler.
+ *
+ * - custom handlers: These are all the handlers registered to the object with
jQuery.fn.on().
+ * If not prevented by the initial handler, they will be executed right
after the initial
+ * handler. By default this will get the same arguments as the initial
handler, except if the
+ * initial handler has explicitly set jQuery.Event.customHandlerArgs.
+ *
+ * - native handler: Is the handler which executes the actual logic of the
outer function which
+ * should also be what the defined event is all about.
+ *
+ * The native handler return value will be taken as return value for the outer
function. If the
+ * native handler never gets called, the return value of the outer function
can either be the
+ * last return value given by any custom handler (as long as the return value
was not undefined)
+ * or - if the custom handlers aren't called, if there are no custom handlers
registered, if
+ * 'allowCustomResult' is set to false or if returning of custom values is not
supported by the
+ * responsible event handler (which is the case when used within widgets) -
the initial
+ * handler's return value.
+ *
+ * The context the handlers are called in is usually the one of the outer
function. The only
+ * exception is for custom handlers while the system is used within jQuery
widgets. In those
+ * custom handlers, the context will be the widget's subject DOM node.
+ *
+ * NOTE: The native handler is available as 'nativeHandler' property of the
returned function.
+ * The initial handler is available as 'initialHandler' property (just
an empty function
+ * if not provided)
+ *
+ * @version 0.1
+ *
+ * @param eventName String
+ * @param fn Function|Object if this is a function, then it will be taken as
native handler and
+ * will be executed after custom event handlers are executed.
+ * If this is an object, this can hold properties defining the native
as well as the
+ * initial handler as well as additional options for changing the event
handling
+ * behavior. The following properties can be given (see full
description about the
+ * different handlers above):
+ * - initially: should be a function representing the initial handler
+ * - natively: the actual native handler, 'function which makes the
event happen'
+ * - allowCustomResult: if set to true, custom handlers result values
will be returned
+ * by the outer function if the native handler won't be called
(because of
+ * jQuery.preventDefault)
+ *
+ * @return Function
+ *
+ * @example
+ * <code>
+ * // Will focus the element and return true if focus has been set, false if
the process failed.
+ * // Will trigger 'focus' event if focus isn't set already.
+ * SomeConstructor.prototype.focus = $.NativeEventHandler( 'focus', {
+ * // event: jQuery.Event which will be triggered after this if
event.stopPropagation() not called
+ * // The other arguments are those who were given to the public, outer
focus() function
+ * initially: function( event, highlight, someInternal ) {
+ * if( this.hasFocus() ) {
+ * event.cancel(); // focus is set already, stop everything...
+ * return true; // ... and let the outer focus() function return
true
+ * }
+ * event.customHandlerArgs = [ highlight ]; // don't give the
someInternal arg to custom event handlers
+ * return false; // will be returned by outer focus() if custom
handlers call event.preventDefault()
+ * },
+ * natively: function( event, highlight, somethingInternal ) {
+ * // this will only be called after 'focus' event was called and
default wasn't prevented
+ * doSomething();
+ * return true; // final return value for outer focus()
+ * }
+ * } )
+ * </code>
+ */
+jQuery.NativeEventHandler = ( function( $ ) {
+ 'use strict';
+
+ var NEH_OPTIONS = [
+ 'natively',
+ 'nativeHandler',
+ 'initially',
+ 'initialHandler',
+ 'allowCustomResult'
+ ];
+
+ return function( eventName, fn ) {
+ var initialFn = function() {},
+ allowCustomResult = false;
+
+ if( !$.isFunction( fn ) ) { // not just a native handler but
additional callbacks/options
+ // check for spelling errors in definition object
+ $.each( fn, function( key, elem ) {
+ if( $.inArray( key, NEH_OPTIONS ) === -1 ) {
+ throw new Error( 'Unknown native event
handler option "' + key + '"' );
+ }
+ } );
+
+ // get options
+ allowCustomResult = fn.allowCustomResult !== undefined
+ ? fn.allowCustomResult
+ : allowCustomResult;
+
+ // get handlers
+ initialFn = fn.initially || fn.initialHandler ||
initialFn;
+ fn = fn.natively || fn.nativeHandler;
+
+ // make sure we have a native handler or fail
+ if( !$.isFunction( fn ) ) {
+ throw new Error( 'No native handler function
provided' );
+ }
+ }
+
+ /**
+ * The returned function handling all the stages of handlers.
+ * 1. initial, 2. custom, 3. native
+ *
+ * @return {*}
+ */
+ var handler = function() {
+ var event = $.Event( eventName, {
+ handlerArgs: false,
+ customHandlerArgs: false,
+ nativeHandlerArgs: false,
+ cancel: function() {
+ event.stopImmediatePropagation();
+ event.preventDefault();
+ }
+ } );
+ var args = $( arguments ).toArray();
+
+ // Does all the preparation and can cancel the whole
thing:
+ var ret = handler.initialHandler.apply( this, [ event
].concat( args ) );
+
+ var defaultPreventedByWidget = false;
+
+ // Store this so custom callbacks can't interfere with
internal default prevention:
+ var defaultPreventedEarly = event.isDefaultPrevented();
+
+ // Allow for different arguments for custom/native
event handlers:
+ var handlerArgs = event.handlerArgs || args;
+ var customHandlerArgs = event.customHandlerArgs ||
handlerArgs;
+ var nativeHandlerArgs = event.nativeHandlerArgs ||
handlerArgs;
+
+ // Don't reveal this to custom handlers!
+ event.handlerArgs = event.customHandlerArgs =
event.nativeHandlerArgs = event.cancel
+ = undefined;
+
+ // Trigger all registered events (custom handlers).
+ // This might be prevented by the initial handler for
some reason.
+ if( !event.isImmediatePropagationStopped() ) {
+ if( $.Widget && ( this instanceof $.Widget ) ) {
+ // Use the $.Widget's native trigger
mechanisms.
+ // $.Widget._trigger will use its own
event but return false if prevented.
+ // Also, context of custom handlers
will be the DOM node rather than the widget.
+ defaultPreventedByWidget =
!this._trigger( event.type, null, customHandlerArgs );
+ // TODO: attach our own event as some
field of the widget's event
+ } else {
+ // Don't use trigger(); it might end up
in an endless loop since it would try to
+ // execute a function named after the
event in the object.
+ $( this ).triggerHandler( event,
customHandlerArgs );
+ }
+
+ // If desired for this event, let custom
handlers last return value overwrite
+ // initial handlers one.
+ if( allowCustomResult && event.result !==
undefined ) {
+ ret = event.result;
+ }
+ }
+
+ // Initial handler and custom handlers can prevent
native event from being executed.
+ if( !defaultPreventedEarly
+ && ( !defaultPreventedByWidget &&
!event.isDefaultPrevented() )
+ ) {
+ // Call native handler for the event.
+ // Give event as first argument just like
jQuery does for custom handlers!
+ var nativeRet = handler.nativeHandler.apply(
this, [ event ].concat( nativeHandlerArgs ) );
+
+ // If native handler returns undefined, return
previously gathered return value.
+ ret = nativeRet !== undefined ? nativeRet :
ret; // might be the same value
+ }
+
+ return ret; // whatever the initial or custom
handler(s) returned last (ignoring undefined)
+ };
+
+ /**
+ * @type Function
+ * @since 0.1
+ *
+ * @param event {jQuery.Event} the event which is about to be
triggered
+ * @param args {Array} arguments which will be applied to the
native handler as well as to
+ * the custom callbacks (except if the return value is
an array in which case these
+ * values will be used for custom callbacks).
+ * @return {undefined|Boolean|Array} if undefined or true the
native handler as well as all
+ * custom callbacks will be executed. If false, the
whole event will be cancelled.
+ * If an array is returned, its contents will be
applied to the custom callbacks as
+ * parameters, the native handler will still receive
the arguments of the args array.
+ */
+ handler.initialHandler = initialFn;
+
+ /**
+ * Holds the pure functionality of the native event handler.
+ *
+ * @type Function
+ * @since 0.1
+ */
+ handler.nativeHandler = fn; // for outside world and inheritance
+
+ return handler;
+ };
+
+}( jQuery ) );
diff --git
a/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.test.js
b/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.test.js
new file mode 100644
index 0000000..f9b35b7
--- /dev/null
+++ b/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.test.js
@@ -0,0 +1,304 @@
+/**
+ * @file
+ * @licence GNU GPL v2+
+ * @author Daniel Werner < [email protected] >
+ */
+jQuery.NativeEventHandler.test = ( function ( $, QUnit ) {
+ 'use strict';
+
+/**
+ * Will execute NativeEventHandler tests based on a given test definition.
+ * @see jQuery.NativeEventHandler.test.testDefinition
+ *
+ * @since 0.1
+ *
+ * @param {Object} testDefinition
+ */
+return function( testDefinition ) {
+ QUnit.module( 'jQuery.NativeEventHandler using ' +
testDefinition.eventSystem );
+
+ // TEST HELPERS:
+
+ var NEH_STAGE = {
+ INITIAL: 1,
+ CUSTOM: 2,
+ NATIVE: 4
+ };
+ var testResult = 0;
+ function initialHandler() {
+ testResult |= NEH_STAGE.INITIAL;
+ }
+ function customHandler() {
+ testResult |= NEH_STAGE.CUSTOM;
+ }
+ function nativeHandler() {
+ testResult |= NEH_STAGE.NATIVE;
+ }
+ function testNEH( exceptedFlag, comment ) {
+ QUnit.assert.equal(
+ testResult,
+ exceptedFlag,
+ comment
+ );
+ testResult = 0;
+ }
+ var newTestBody = testDefinition.newTestBody;
+ var supportsCustomResults = testDefinition.supportsCustomResults;
+
+ // ACTUAL TESTS:
+
+ QUnit.test( 'Simple native event', function( assert ) {
+ var TEST_EVENT = 'run';
+ var testBody = newTestBody(); // 'Class' which we define our
test function in
+ var ret;
+
+ testBody[ TEST_EVENT ] = $.NativeEventHandler( TEST_EVENT,
nativeHandler );
+
+ assert.ok(
+ $.isFunction( testBody[ TEST_EVENT ] ),
+ 'Returns a function'
+ );
+
+ assert.ok(
+ $.isFunction( testBody[ TEST_EVENT ].nativeHandler ),
+ 'Reference to inner native handler function stored'
+ );
+
+ // register some custom event
+ testBody.one( TEST_EVENT, customHandler );
+ testBody[ TEST_EVENT ](); // CALL!
+ testNEH(
+ NEH_STAGE.NATIVE + NEH_STAGE.CUSTOM,
+ 'custom and native events were called after registering
event with jQuery.one()'
+ );
+
+ testBody[ TEST_EVENT ](); // CALL!
+ testNEH(
+ NEH_STAGE.NATIVE,
+ 'only native handler was called because no events are
registered'
+ );
+
+ testBody.one( TEST_EVENT, function( event ) {
+ customHandler();
+ event.preventDefault(); // should prevent from calling
native handler
+ return 'foo';
+ } );
+ ret = testBody[ TEST_EVENT ](); // CALL!
+ testNEH(
+ NEH_STAGE.CUSTOM,
+ 'only custom handlers are called after one of them
requests jQuery.Event.preventDefault()'
+ );
+ assert.notEqual(
+ ret,
+ 'foo', // shouldn't work because allowCustomResult not
set to true!
+ 'calling event function has not returned value returned
by native handler'
+ );
+
+ testBody.one( TEST_EVENT, function( event ) {
+ event.stopImmediatePropagation();
+ } );
+ testBody.one( TEST_EVENT, customHandler );
+ testBody[ TEST_EVENT ](); // CALL!
+ testNEH(
+ NEH_STAGE.NATIVE,
+ 'no further custom handlers were called after
jQuery.Event.stopImmediatePropagation()'
+ );
+ } );
+
+
+ QUnit.test( 'Simple native event with initial handler, also allowing
custom results', function( assert ) {
+ var TEST_EVENT = 'run';
+ var testBody = newTestBody();
+ var ret;
+
+ testBody[ TEST_EVENT ] = $.NativeEventHandler( TEST_EVENT, {
+ allowCustomResult: true,
+ initially: function( event, cancel ) {
+ initialHandler();
+ if( cancel ) { // for cancel test
+ event.cancel();
+ }
+ return NEH_STAGE.INITIAL;
+ },
+ natively: function( event ) {
+ nativeHandler();
+ return NEH_STAGE.NATIVE;
+ }
+ } );
+
+ assert.ok(
+ $.isFunction( testBody[ TEST_EVENT ].initialHandler ),
+ 'Reference to inner initial handler function stored'
+ );
+
+ ret = testBody[ TEST_EVENT ](); // CALL!
+ assert.equal(
+ ret,
+ NEH_STAGE.NATIVE,
+ 'calling event function returns value returned by
native handler'
+ );
+ testNEH(
+ NEH_STAGE.INITIAL + NEH_STAGE.NATIVE,
+ 'initial and native handlers were called (no event
registered)'
+ );
+
+ // register some custom event
+ testBody.one( TEST_EVENT, customHandler );
+ testBody[ TEST_EVENT ](); // CALL!
+ testNEH(
+ NEH_STAGE.INITIAL + NEH_STAGE.NATIVE + NEH_STAGE.CUSTOM,
+ 'initial, custom and native handlers were called'
+ );
+
+ ret = testBody[ TEST_EVENT ]( true ); // CALL!, argument
triggers $.Event.cancel() test
+ assert.equal(
+ ret,
+ NEH_STAGE.INITIAL,
+ 'calling event function returns value returned by
initial handler because of condition in initial handler'
+ );
+ testNEH(
+ NEH_STAGE.INITIAL,
+ 'only initial handler was called, which then decided to
cancel the whole event'
+ );
+
+ testBody.one( TEST_EVENT, function( event ) {
+ customHandler();
+ event.preventDefault();
+ return NEH_STAGE.CUSTOM; // should be returned by event
function because native handler suppressed above^^
+ } );
+ ret = testBody[ TEST_EVENT ](); // CALL!
+
+ if( supportsCustomResults ) {
+ assert.equal(
+ ret,
+ NEH_STAGE.CUSTOM,
+ 'calling event function returns value returned
by last custom handler because ' +
+ 'default was prevented and custom
results are supported by the event handler'
+ );
+ } else {
+ assert.equal(
+ ret,
+ NEH_STAGE.INITIAL,
+ 'calling event function returns value returned
by initial handler even though ' +
+ 'custom handler did prevent default and
returned a custom value while default ' +
+ 'has been prevented. The final output
will be the native handler\'s return value'
+ );
+ }
+ testNEH(
+ NEH_STAGE.INITIAL + NEH_STAGE.CUSTOM,
+ 'only custom handlers are called after one of them
requests jQuery.Event.preventDefault()'
+ );
+
+ testBody.one( TEST_EVENT, function( event ) {
+ customHandler();
+ return NEH_STAGE.CUSTOM; // should be returned by event
function because native handler suppressed next!
+ } );
+ testBody.one( TEST_EVENT, function( event ) {
+ return false;
+ } );
+ ret = testBody[ TEST_EVENT ](); // CALL!
+
+ assert.equal(
+ ret,
+ supportsCustomResults
+ ? false // false returned by custom handler,
also implies preventDefault!
+ : NEH_STAGE.INITIAL, // false causes
preventDefault() but outer function will have native handler's return value
+ supportsCustomResults
+ ? 'calling event function returns value
returned by first custom handler even' +
+ 'though it is false'
+ : 'calling event function returns native
handlers result instead of false even ' +
+ 'though false was returned by custom
handler. This is because custom results ' +
+ 'are not supported by the event handler
in use.'
+ );
+ testNEH(
+ NEH_STAGE.INITIAL + NEH_STAGE.CUSTOM,
+ 'only custom handlers are called after second custom
handler returned false'
+ );
+ } );
+
+
+ QUnit.test(
+ 'Additional jQuery.Event members used for communicating between
initial handler and outer function',
+ 12, // make sure all tests are executed since we execute some
tests from within event handlers!
+ function( assert ) {
+
+ var TEST_EVENT = 'run';
+ var testBody = newTestBody();
+ var newBasicHandlerTest = function( handlerType,
numberOfAdditionalArgs ) {
+ return function( event ) {
+ assert.equal(
+ this,
+ testBody[ handlerType +
'HandlerContext' ],
+ handlerType + ' handler was
called in the right context'
+ );
+ assert.ok(
+ event instanceof $.Event,
+ handlerType + ' handler
callback gets jQuery.Event as first parameter'
+ );
+ assert.ok(
+ arguments.length ===
numberOfAdditionalArgs + 1, // + 1 for event arg
+ 'all ' + numberOfAdditionalArgs
+ ' arguments plus one for event object get passed on'
+ );
+ switch( handlerType ) { // will only
set a flag that the handler was called
+ case 'initial':
initialHandler(); break;
+ case 'native': nativeHandler();
break;
+ case 'custom': customHandler();
break;
+ }
+ };
+ };
+
+ testBody[ TEST_EVENT ] = $.NativeEventHandler( TEST_EVENT, {
+ initially: function( event ) {
+ newBasicHandlerTest( 'initial', 2 ).apply(
this, arguments );
+
+ assert.ok(
+ event.customHandlerArgs === false,
+ 'jQuery.Event.customHandlerArgs is set
to false'
+ );
+
+ assert.ok(
+ event.nativeHandlerArgs === false,
+ 'jQuery.Event.customHandlerArgs is set
to false'
+ );
+
+ event.customHandlerArgs = [ 1, 2, 3 ];
+ event.nativeHandlerArgs = [ 1, 2, 3, 4, 5 ];
+ },
+ natively: newBasicHandlerTest( 'native', 5 )
+ } );
+
+ // register some custom event, execute newBasicHandlerTest
tests there as well
+ testBody.one( TEST_EVENT, newBasicHandlerTest( 'custom', 3 ) );
+ testBody[ TEST_EVENT ]( 1, 2 ); // CALL!, give two parameters
for test
+ testNEH(
+ NEH_STAGE.INITIAL + NEH_STAGE.NATIVE + NEH_STAGE.CUSTOM,
+ 'initial, custom and native handlers were called'
+ );
+ } );
+
+
+ QUnit.test( 'Excepted errors', function( assert ) {
+ assert.throws(
+ function() {
+ $.NativeEventHandler( 'foo' );
+ },
+ 'Can\'t create handler without function'
+ );
+
+ assert.throws(
+ function() {
+ $.NativeEventHandler( 'foo', {} );
+ },
+ 'Can\'t create handler without function although 2nd
parameter is set'
+ );
+
+ assert.throws(
+ function() {
+ $.NativeEventHandler( 'foo', { natively:
$.noop, 'foo': 'test' } );
+ },
+ 'Can\'t create handler with unknown key in 2nd
parameter'
+ );
+ } );
+};
+
+}( jQuery, QUnit ) );
diff --git
a/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.test.testDefinition.js
b/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.test.testDefinition.js
new file mode 100644
index 0000000..5af1d3d
--- /dev/null
+++
b/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.test.testDefinition.js
@@ -0,0 +1,50 @@
+/**
+ * @file
+ * @licence GNU GPL v2+
+ * @author Daniel Werner < [email protected] >
+ */
+jQuery.NativeEventHandler.test.testDefinition = ( function ( $, QUnit ) {
+ 'use strict';
+
+ /**
+ * Test definition for running wb.tests.nativeEventHandlerTest with.
+ *
+ * @since 0.1
+ *
+ * @constructor
+ * @abstract
+ */
+ return {
+ /**
+ * Descriptive name of the event handler system which is used
together with the
+ * NativeEventHandler in this test definition.
+ * @type {String}
+ */
+ eventSystem: '',
+
+ /**
+ * Whether custom results are supported by the event handler
system in use. E.g. $.Widget's
+ * _trigger() does not allow for custom results while
$.trigger() does.
+ * @type Boolean
+ */
+ supportsCustomResults: false,
+
+ /**
+ * Returns an Object which test functions factored by the
NativeEventHandler can be attached
+ * to. The returned object also has a 'one' function which is
equivalent to jQuery.one() and
+ * allows for listening to events which should be triggered by
any NativeEventHandler
+ * defined on the test body Object returned by this.
+ *
+ * @return {Object} Will have the following fields:
+ * - 'one' function to register custom event handler,
will be removed after called once.
+ * - 'initialHandlerContext' The object which should be
the context for initial handler.
+ * - 'customHandlerContext' The object which should be
the context for custom handlers.
+ * - 'nativeHandlerContext' The object which should be
the context for native handler.
+ */
+ newWidgetTestBody: function() {
+ throw new Error( '"newWidgetTestBody" has to be
overwritten in specific test '
+ + 'implementation' );
+ }
+ };
+
+}( jQuery, QUnit ) );
diff --git
a/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.testsOnObject.js
b/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.testsOnObject.js
new file mode 100644
index 0000000..1f7c877
--- /dev/null
+++
b/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.testsOnObject.js
@@ -0,0 +1,50 @@
+/**
+ * @file
+ * @licence GNU GPL v2+
+ * @author Daniel Werner < [email protected] >
+ */
+( function ( $, QUnit, runTest, testDefinitionBase ) {
+ 'use strict';
+
+ /**
+ * Test definition for running NativeEventHandler tests within a plain
Object's environment.
+ * For triggering events on the object, $( obj ).trigger() will be used.
+ *
+ * @type Object
+ */
+ var testDefinition = $.extend( {}, testDefinitionBase, {
+ /**
+ * @see
jQuery.NativeEventHandler.test.testDefinition.eventSystem
+ */
+ eventSystem: 'jQuery.fn.trigger',
+
+ /**
+ * @see
jQuery.NativeEventHandler.test.testDefinition.supportsCustomResults
+ */
+ supportsCustomResults: true,
+
+ /**
+ * @see
jQuery.NativeEventHandler.test.testDefinition.newWidgetTestBody
+ */
+ newTestBody: function() {
+ var testBody = {
+ one: function( eventType, fn ) {
+ $( this ).one( eventType, fn );
+ }
+ };
+ testBody.initialHandlerContext
+ = testBody.customHandlerContext
+ = testBody.nativeHandlerContext
+ = testBody;
+
+ return testBody;
+ }
+ } );
+
+ runTest( testDefinition );
+}(
+ jQuery,
+ QUnit,
+ jQuery.NativeEventHandler.test,
+ jQuery.NativeEventHandler.test.testDefinition
+) );
diff --git
a/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.testsOnWidget.js
b/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.testsOnWidget.js
new file mode 100644
index 0000000..e7af534
--- /dev/null
+++
b/ValueView/tests/qunit/jquery.NativeEventHandler/NativeEventHandler.testsOnWidget.js
@@ -0,0 +1,59 @@
+/**
+ * @file
+ * @licence GNU GPL v2+
+ * @author Daniel Werner < [email protected] >
+ */
+( function ( $, QUnit, runTest, testDefinitionBase ) {
+ 'use strict';
+
+ /**
+ * Test definition for running NativeEventHandler tests within jQuery
Widget environment,
+ * meaning, the jQuery.Widget's _trigger() function will be used to
trigger events.
+ *
+ * @type Object
+ */
+ var testDefinition = $.extend( {}, testDefinitionBase, {
+ /**
+ * @see wb.tests.NativeEventHandlerTestDefinition.eventSystem
+ */
+ eventSystem: 'jQuery.Widget.prototype._trigger',
+
+ /**
+ * @see
wb.tests.NativeEventHandlerTestDefinition.supportsCustomResults
+ */
+ supportsCustomResults: false,
+
+ /**
+ * @see
wb.tests.NativeEventHandlerTestDefinition.newWidgetTestBody
+ */
+ newTestBody: function() {
+ var TestWidget = function() {
+ $.Widget.apply( this, arguments );
+ };
+ TestWidget.prototype = $.extend( new $.Widget(), {
+ constructor: TestWidget,
+ widgetName: 'neh_test_widget',
+ widgetEventPrefix: 'neh_test_widget_'
+ } );
+
+ var testBody = new TestWidget( {}, $( '<div/>' ) );
+
+ testBody.one = function( eventType, fn ) {
+ // In widgets, event will have a prefix!
+ testBody.element.one(
testBody.widgetEventPrefix + eventType, fn );
+ };
+ testBody.initialHandlerContext = testBody;
+ testBody.customHandlerContext = testBody.element[0];
+ testBody.nativeHandlerContext = testBody;
+
+ return testBody;
+ }
+ } );
+
+ runTest( testDefinition );
+}(
+ jQuery,
+ QUnit,
+ jQuery.NativeEventHandler.test,
+ jQuery.NativeEventHandler.test.testDefinition
+) );
--
To view, visit https://gerrit.wikimedia.org/r/79148
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia207fdea460a64142cef3dc427d364db353183d3
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/DataValues
Gerrit-Branch: master
Gerrit-Owner: Daniel Werner <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits