Henning Snater has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/74116


Change subject: Split off adaptLetterCase and autocompleteString from suggester
......................................................................

Split off adaptLetterCase and autocompleteString from suggester

Change-Id: I83d751ca22f2b0579d21849233da011417b92e5d
---
M ValueView/ValueView.resources.mw.php
M ValueView/ValueView.tests.qunit.php
M ValueView/resources/jquery.ui/jquery.ui.suggester.js
A ValueView/resources/jquery.util/jquery.util.adaptlettercase.js
A ValueView/resources/jquery/jquery.autocompletestring.js
M ValueView/tests/qunit/jquery.ui/jquery.ui.suggester.tests.js
A ValueView/tests/qunit/jquery.util/jquery.util.adaptlettercase.tests.js
A ValueView/tests/qunit/jquery/jquery.autocompletestring.tests.js
8 files changed, 306 insertions(+), 158 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/DataValues 
refs/changes/16/74116/1

diff --git a/ValueView/ValueView.resources.mw.php 
b/ValueView/ValueView.resources.mw.php
index d135403..d29a412 100644
--- a/ValueView/ValueView.resources.mw.php
+++ b/ValueView/ValueView.resources.mw.php
@@ -86,7 +86,10 @@
                                'jquery.ui/jquery.ui.suggester.css'
                        ),
                        'dependencies' => array(
-                               'jquery.ui.autocomplete'
+                               'jquery.autocompletestring',
+                               'jquery.ui.autocomplete',
+                               'jquery.ui.widget',
+                               'jquery.util.adaptlettercase',
                        )
                ),
 
@@ -127,7 +130,6 @@
                        ),
                ),
 
-
                'jquery.ui.listrotator' => $moduleTemplate + array(
                        'scripts' => array(
                                'jquery.ui/jquery.ui.listrotator.js',
@@ -144,6 +146,22 @@
                                'valueview-listrotator-auto',
                        ),
                ),
+
+               'jquery.autocompletestring' => $moduleTemplate + array(
+                       'scripts' => array(
+                               'jquery/jquery.autocompletestring.js',
+                       ),
+                       'dependencies' => array(
+                               'jquery.util.adaptlettercase',
+                       ),
+               ),
+
+               'jquery.util.adaptlettercase' => $moduleTemplate + array(
+                       'scripts' => array(
+                               'jquery.util/jquery.util.adaptlettercase.js',
+                       ),
+               ),
+
        );
 
        // return jQuery.valueview's native resources plus those required by 
the MW extension:
diff --git a/ValueView/ValueView.tests.qunit.php 
b/ValueView/ValueView.tests.qunit.php
index 3b4dac0..010fa47 100644
--- a/ValueView/ValueView.tests.qunit.php
+++ b/ValueView/ValueView.tests.qunit.php
@@ -174,6 +174,25 @@
                                'jquery.valueview.experts.timeinput',
                        ),
                ),
+
+               'jquery.autocompletestring.tests' => array(
+                       'scripts' => array(
+                               "$bp/jquery/jquery.autocompletestring.tests.js",
+                       ),
+                       'dependencies' => array(
+                               'jquery.autocompletestring',
+                       ),
+               ),
+
+               'jquery.util.adaptlettercase.tests' => array(
+                       'scripts' => array(
+                               
"$bp/jquery.util/jquery.util.adaptlettercase.tests.js",
+                       ),
+                       'dependencies' => array(
+                               'jquery.util.adaptlettercase',
+                       ),
+               ),
+
        );
 
 } );
diff --git a/ValueView/resources/jquery.ui/jquery.ui.suggester.js 
b/ValueView/resources/jquery.ui/jquery.ui.suggester.js
index db1ca3e..d52e9a7 100644
--- a/ValueView/resources/jquery.ui/jquery.ui.suggester.js
+++ b/ValueView/resources/jquery.ui/jquery.ui.suggester.js
@@ -78,7 +78,10 @@
  *        (2) {String} Error text status.
  *        (3) {Object} Detailed error information.
  *
+ * @dependency jquery.autocompletestring
+ * @dependency jquery.eachchange
  * @dependency jquery.ui.autocomplete
+ * @dependency jquery.util.adaptlettercase
  */
 ( function( $ ) {
        'use strict';
@@ -230,7 +233,10 @@
                        var resultSet = $.ui.autocomplete.filter( 
this.options.source, request.term );
 
                        if ( resultSet.length && this.options.adaptLetterCase ) 
{
-                               this.term = this._adaptLetterCase( this.term, 
resultSet[0] );
+                               this.term = $.util.adaptLetterCase( this.term,
+                                       resultSet[0],
+                                       this.options.adaptLetterCase
+                               );
                                this.element.val( this.term );
                        }
 
@@ -289,10 +295,18 @@
                                // auto-complete input box text (because of the 
API call lag, this is
                                // avoided when hitting backspace, since the 
value would be reset too slow)
                                if ( this._lastKeyDown !== 8 && 
response[1].length > 0 ) {
-                                       this.autocompleteString(
-                                               response[0],
-                                               response[1][0]
-                                       );
+                                       var incomplete = response[0],
+                                               complete = response[1][0];
+
+                                       if ( this.options.adaptLetterCase ) {
+                                               this.term = incomplete = 
$.util.adaptLetterCase(
+                                                       incomplete,
+                                                       complete,
+                                                       
this.options.adaptLetterCase
+                                               );
+                                       }
+
+                                       this.element.autocompletestring( 
incomplete, complete );
                                }
 
                                suggest( response[1] ); // pass array of 
returned values to callback
@@ -519,24 +533,6 @@
                },
 
                /**
-                * Adjusts the letter case of a source string to the letter 
case in a destination string
-                * according to the adaptLetterCase option.
-                *
-                * @param {String} source
-                * @param {String} destination
-                * @return {String} Altered source string
-                */
-               _adaptLetterCase: function( source, destination ) {
-                       if ( this.options.adaptLetterCase === 'all' ) {
-                               return destination.substr( 0, source.length );
-                       } else if ( this.options.adaptLetterCase === 'first' ) {
-                               return destination.substr( 0, 1 ) + 
source.substr( 1 );
-                       } else {
-                               return source;
-                       }
-               },
-
-               /**
                 * Sets/gets the plain input box value.
                 *
                 * @param {String} [value] Value to be set
@@ -556,65 +552,6 @@
                        this.menu.element.position( $.extend( {
                                of: this.element
                        }, this.options.position ) );
-               },
-
-               /**
-                * Completes the input box with the remaining characters of a 
given string. The characters
-                * of the remaining part are text-highlighted, so the will be 
overwritten if typing
-                * characters is continue. Tabbing or clicking outside of the 
input box will leave the
-                * completed string in the input box.
-                *
-                * @param incomplete {String}
-                * @param complete {String}
-                * @return {Number} number of characters added (and 
highlighted) at the end of the
-                *         incomplete string
-                */
-               autocompleteString: function( incomplete, complete ) {
-                       if(
-                               // if nothing to complete, just return and 
don't move the cursor
-                               // (can be annoying in this situation)
-                               incomplete === complete
-                               // The following statement is a work-around for 
a technically unexpected search
-                               // behaviour: e.g. in English Wikipedia 
opensearch for "Allegro [...]" returns
-                               // "Allegro" as first result instead of 
"Allegro (music)", so auto-completion should
-                               // probably be prevented here since it would 
always reset the input box's value to
-                               // "Allegro"
-                               || complete.toLowerCase().indexOf( 
this.element.val().toLowerCase() ) === -1
-                       ) {
-                               return 0;
-                       }
-
-                       // set value to complete value...
-                       if ( this.options.adaptLetterCase ) {
-                               this.term = this._adaptLetterCase( incomplete, 
complete );
-                               if ( complete.indexOf( this.term ) === 0 ) {
-                                       this.element.val( complete );
-                               }
-                       } else if ( incomplete === complete.substr( 0, 
incomplete.length ) ) {
-                               this.element.val( incomplete + complete.substr( 
incomplete.length ) );
-                       }
-
-                       // ... and select the suggested, not manually typed 
part of the value
-                       var start = incomplete.length,
-                               end = complete.length,
-                               node = this.element[0];
-
-                       // highlighting takes some browser specific 
implementation
-                       if( node.createTextRange ) { // opera < 10.5 and IE
-                               var selRange = node.createTextRange();
-                               selRange.collapse( true );
-                               selRange.moveStart( 'character', start);
-                               selRange.moveEnd( 'character', end);
-                               selRange.select();
-                       } else if( node.setSelectionRange ) { // major modern 
browsers
-                               // make a 'backward' selection so pressing 
arrow left won't put the cursor near the
-                               // selections end but rather at the typing 
position
-                               node.setSelectionRange( start, end, 'backward' 
);
-                       } else if( node.selectionStart ) {
-                               node.selectionStart = start;
-                               node.selectionEnd = end;
-                       }
-                       return ( end - start );
                }
 
        } );
diff --git a/ValueView/resources/jquery.util/jquery.util.adaptlettercase.js 
b/ValueView/resources/jquery.util/jquery.util.adaptlettercase.js
new file mode 100644
index 0000000..0215dee
--- /dev/null
+++ b/ValueView/resources/jquery.util/jquery.util.adaptlettercase.js
@@ -0,0 +1,46 @@
+/**
+ * adaptlettercase helper function
+ *
+ * @licence GNU GPL v2+
+ * @author H. Snater < mediaw...@snater.com >
+ *
+ * @dependency jQuery
+ */
+jQuery.util = jQuery.util || {};
+
+jQuery.util.adaptlettercase = ( function( $ ) {
+       'use strict';
+
+       /**
+        * Adapts the letter case of a source string to a destination string. 
The destination string is
+        * supposed to consist our of the source string's first letter(s).
+        *
+        * @param {string} source
+        * @param {string} destination
+        * @param {string|undefined} method "all" will adapt source's letter 
case for all destination
+        *        characters, "first" will adapt the first letter only. By 
default, no adaption is
+        *        taking place.
+        * @return {string}
+        *
+        * @throws {Error} if source and/or destination string is not specified.
+        * @throws {Error} if source string does not start with destination 
string.
+        */
+       return function( source, destination, method ) {
+               if( !source || !destination ) {
+                       throw new Error( 'Source and destination need to be 
specified.' );
+               }
+
+               if( source.toLowerCase().indexOf( destination.toLowerCase() ) 
=== -1 ) {
+                       throw new Error( source + ' does not start with ' + 
destination + '.' );
+               }
+
+               if ( method === 'all' ) {
+                       return destination.substr( 0, source.length );
+               } else if ( method === 'first' ) {
+                       return destination.substr( 0, 1 ) + source.substr( 1 );
+               } else {
+                       return source;
+               }
+       };
+
+} )( jQuery );
diff --git a/ValueView/resources/jquery/jquery.autocompletestring.js 
b/ValueView/resources/jquery/jquery.autocompletestring.js
new file mode 100644
index 0000000..6408add
--- /dev/null
+++ b/ValueView/resources/jquery/jquery.autocompletestring.js
@@ -0,0 +1,79 @@
+/**
+ * autocompletestring jQuery plugin
+ *
+ * @licence GNU GPL v2+
+ * @author H. Snater < mediaw...@snater.com >
+ *
+ * @dependency jQuery
+ */
+jQuery.fn.autocompletestring = ( function( $ ) {
+       'use strict';
+
+       /**
+        * Applied to an input or textarea element, 
jQuery.fn.autocompletestring is fed with a
+        * "complete" string and an "incomplete" - latter is supposed to 
consist out of the first
+        * letter(s) of the "complete" string. The form element is filled with 
the "complete" string
+        * while a text selection is applied to the characters missing in the 
"incomplete" string.
+        *
+        * @param {string} incomplete
+        * @param {string} complete
+        * @return {jQuery}
+        */
+       var autocompletestring = function( incomplete, complete ) {
+               if(
+                       !incomplete || !complete
+                       || complete.toLowerCase().indexOf( 
incomplete.toLowerCase() ) !== 0
+               ) {
+                       return this;
+               }
+
+               return this.each( function() {
+                       var $this = $( this );
+
+                       // Only auto-complete when incomplete string actually 
is a part of the complete string:
+                       if( incomplete === complete.substr( 0, 
incomplete.length ) ) {
+                               $this.val( incomplete + complete.substr( 
incomplete.length ) );
+                       }
+
+                       $.fn.autocompletestring.selectText( this, 
incomplete.length, complete.length );
+               } );
+       };
+
+       /**
+        * Creates a text selection.
+        *
+        * @param {object} node
+        * @param {number} start
+        * @param {number} end
+        * @return {number} Text selection length.
+        */
+       autocompletestring.selectText = function( node, start, end ) {
+               if( end > node.value.length ) {
+                       end = node.value.length;
+               }
+
+               if( start > end ) {
+                       return 0;
+               }
+
+               if( node.createTextRange ) { // Opera < 10.5 and IE
+                       var selRange = node.createTextRange();
+                       selRange.collapse( true );
+                       selRange.moveStart( 'character', start );
+                       selRange.moveEnd( 'character', end );
+                       selRange.select();
+               } else if( node.setSelectionRange ) { // major modern browsers
+                       // Make a 'backward' selection so pressing arrow left 
won't put the cursor near the
+                       // selections end but rather at the typing position:
+                       node.setSelectionRange( start, end, 'backward' );
+               } else if( node.selectionStart ) {
+                       node.selectionStart = start;
+                       node.selectionEnd = end;
+               }
+
+               return ( end - start );
+       };
+
+       return autocompletestring;
+
+} )( jQuery );
diff --git a/ValueView/tests/qunit/jquery.ui/jquery.ui.suggester.tests.js 
b/ValueView/tests/qunit/jquery.ui/jquery.ui.suggester.tests.js
index 2885696..b5e88a8 100644
--- a/ValueView/tests/qunit/jquery.ui/jquery.ui.suggester.tests.js
+++ b/ValueView/tests/qunit/jquery.ui/jquery.ui.suggester.tests.js
@@ -103,83 +103,9 @@
                        'Detected scrollbar width.'
                );
 
-               // Firefox will throw an error when the input element is not 
part of the DOM while trying to
-               // set the selection range which is part of the following 
assertion
-               $( 'body' ).append( $input );
-               assert.equal(
-                       suggester.autocompleteString( $input.val(), 'ab' ),
-                       1,
-                       'Auto-completed text.'
-               );
-
                suggester.destroy();
                $input.remove();
 
-       } );
-
-       QUnit.test( 'Adapt letter case', function( assert ) {
-               var $input = newTestSuggester();
-               var suggester = $input.data( 'suggester' );
-
-               assert.equal(
-                       suggester._adaptLetterCase( 'abc', 'AbC' ),
-                       'abc',
-                       "adaptLetterCase: Did not adapt any letter case."
-               );
-
-               $input.val( 'ef' );
-               suggester.search( 'EF' ); // simulate case-insensitive search
-
-               assert.equal(
-                       $input.val(),
-                       'ef',
-                       "Did not adjusted input value's letter case according 
to suggestion list's first result set."
-               );
-
-               suggester.destroy();
-               $input.remove();
-
-               $input = newTestSuggester( { adaptLetterCase: 'all' } );
-               suggester = $input.data( 'suggester' );
-
-               assert.equal(
-                       suggester._adaptLetterCase( 'abc', 'AbC' ),
-                       'AbC',
-                       "adjustLetterCase: Adapted the case of all letters."
-               );
-
-               $input.val( 'ef' );
-               suggester.search( 'EF' );
-
-               assert.equal(
-                       $input.val(),
-                       'EF',
-                       "Adjusted input value's letter case according to 
suggestion list's first result set."
-               );
-
-               suggester.destroy();
-               $input.remove();
-
-               $input = newTestSuggester( { adaptLetterCase: 'first' } );
-               suggester = $input.data( 'suggester' );
-
-               assert.equal(
-                       suggester._adaptLetterCase( 'abc', 'AbC' ),
-                       'Abc',
-                       "adaptLetterCase: Adapted the case of the first letter."
-               );
-
-               $input.val( 'ef' );
-               suggester.search( 'EF' );
-
-               assert.equal(
-                       $input.val(),
-                       'Ef',
-                       "Capitalized input value's letters according to 
suggestion list's first result set."
-               );
-
-               suggester.destroy();
-               $input.remove();
        } );
 
        QUnit.test( 'automatic height adjustment', function( assert ) {
diff --git 
a/ValueView/tests/qunit/jquery.util/jquery.util.adaptlettercase.tests.js 
b/ValueView/tests/qunit/jquery.util/jquery.util.adaptlettercase.tests.js
new file mode 100644
index 0000000..932238a
--- /dev/null
+++ b/ValueView/tests/qunit/jquery.util/jquery.util.adaptlettercase.tests.js
@@ -0,0 +1,53 @@
+/**
+ * @licence GNU GPL v2+
+ * @author H. Snater < mediaw...@snater.com >
+ */
+
+( function( $, QUnit ) {
+       'use strict';
+
+       QUnit.module( 'jquery.util.adaptlettercase' );
+
+       QUnit.test( 'Basic tests', function( assert ) {
+
+               assert.equal(
+                       $.util.adaptlettercase( 'abc', 'AbC' ),
+                       'abc',
+                       'Not adapting any letter-case when omitting \'method\' 
parameter.'
+               );
+
+               assert.equal(
+                       $.util.adaptlettercase( 'abc', 'AbC', 'all' ),
+                       'AbC',
+                       'Adapting the case of all letters when specifying 
\'all\' as method.'
+               );
+
+               assert.equal(
+                       $.util.adaptlettercase( 'ABC', 'abc', 'first' ),
+                       'aBC',
+                       'Adapting the first letter\'s case when specifying 
\'first\' as method.'
+               );
+
+               assert.equal(
+                       $.util.adaptlettercase( 'AB', 'ab', 'first' ),
+                       'aB',
+                       'Adapting the first letter\'s case when specifying 
\'first\' as method with ' +
+                               'destination being a a part of source.'
+               );
+
+               assert.equal(
+                       $.util.adaptlettercase( '123', '123', 'all' ),
+                       '123',
+                       'No replacement taking place when not passing letters.'
+               );
+
+               assert.throws(
+                       function() {
+                               $.util.adaptlettercase( 'abc', '123', 'all' );
+                       },
+                       'Error thrown when destination does not match source.'
+               );
+
+       } );
+
+}( jQuery, QUnit ) );
\ No newline at end of file
diff --git a/ValueView/tests/qunit/jquery/jquery.autocompletestring.tests.js 
b/ValueView/tests/qunit/jquery/jquery.autocompletestring.tests.js
new file mode 100644
index 0000000..6be97af
--- /dev/null
+++ b/ValueView/tests/qunit/jquery/jquery.autocompletestring.tests.js
@@ -0,0 +1,70 @@
+/**
+ * @licence GNU GPL v2+
+ * @author H. Snater < mediaw...@snater.com >
+ */
+
+( function( $, QUnit ) {
+       'use strict';
+
+       /**
+        * Creates an input element suitable for testing.
+        * @return {jQuery}
+        */
+       function createTestInput() {
+               return $( '<input/>' ).addClass( 'test-autocompletestring' 
).appendTo( 'body' );
+       }
+
+       QUnit.module( 'jquery.autocompletestring', {
+               teardown: function() {
+                       $( '.test-autocompletestring' ).remove();
+               }
+       } );
+
+       QUnit.test( 'Adapt letter case', function( assert ) {
+               var $input = createTestInput();
+
+               assert.equal(
+                       $input.autocompletestring( 'a', 'abc' ).val(),
+                       'abc',
+                       'Auto-completed \'a\' to \'abc\'.'
+               );
+
+               assert.equal(
+                       $input.autocompletestring( '12', '123' ).val(),
+                       '123',
+                       'Auto-completed \'12\' to \'123\'.'
+               );
+
+               assert.equal(
+                       $input.autocompletestring( 'abc', 'abc' ).val(),
+                       'abc',
+                       'Value remains the same when \'incomplete\' and 
\'complete\' string match.'
+               );
+
+               assert.equal(
+                       $input.autocompletestring( 'a', 'ABC' ).val(),
+                       'abc',
+                       'No auto-completion is performed when \'incomplete\' is 
not part of \'complete\' '
+                               + 'string. Input value remains unchanged.'
+               );
+       } );
+
+       QUnit.test( 'selectText()', function( assert ) {
+               var $input = createTestInput().val( '0123456789' );
+
+               assert.equal(
+                       $.fn.autocompletestring.selectText( $input[0], 0, 1 ),
+                       1,
+                       'Applied text selection with length of 1.'
+               );
+
+               assert.equal(
+                       $.fn.autocompletestring.selectText( $input[0], 0, 20 ),
+                       10,
+                       'Applied a text selection with the input value\'s 
character length since it is shorter '
+                               + 'than the selection length trying to apply.'
+               );
+
+       } );
+
+}( jQuery, QUnit ) );

-- 
To view, visit https://gerrit.wikimedia.org/r/74116
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I83d751ca22f2b0579d21849233da011417b92e5d
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/DataValues
Gerrit-Branch: master
Gerrit-Owner: Henning Snater <henning.sna...@wikimedia.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to