Amire80 has uploaded a new change for review.

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

Change subject: Update jquery.ime from upstream
......................................................................

Update jquery.ime from upstream

* Digit fix in Southern Kurdish.
* Or-Lekhani and OdiScript layouts.
* Major updates for VisualEditor integration by David Chan.

Change-Id: Ia7301bddb79c1fbce2af7190494bdd7bdd909862
---
M lib/jquery.ime/jquery.ime.js
M lib/jquery.ime/rules/or/or-lekhani.js
M lib/jquery.ime/rules/sdh/sdh-kbd.js
M lib/jquery.ime/rules/si/si-singlish.js
M lib/jquery.ime/rules/yo/yo-alt.js
5 files changed, 390 insertions(+), 370 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/UniversalLanguageSelector 
refs/changes/66/265766/1

diff --git a/lib/jquery.ime/jquery.ime.js b/lib/jquery.ime/jquery.ime.js
index 8bb2d4f..283c51c 100644
--- a/lib/jquery.ime/jquery.ime.js
+++ b/lib/jquery.ime/jquery.ime.js
@@ -3,18 +3,51 @@
 * Copyright (c) 2015 Santhosh Thottingal; Licensed GPL, MIT */
 ( function ( $ ) {
        'use strict';
+       var TextEntryFactory, TextEntry, FormWidgetEntry, ContentEditableEntry,
+               defaultInputMethod;
 
        // rangy is defined in the rangy library
        /*global rangy */
 
        /**
+        * Just initializes an empty static object.
+        * Similar to initClass in https://www.mediawiki.org/wiki/OOjs
+        *
+        * @param {Function} fn
+        */
+       function initClass( fn ) {
+               fn.static = fn.static || {};
+       }
+
+       /**
+        * Inheritance. Uses pattern similar to OOjs 
(https://www.mediawiki.org/wiki/OOjs).
+        * Extend prototype and static methods and properties of child 
constructor from
+        * a parent constructor.
+        *
+        * @param {Function} targetFn
+        * @param {Function} originFn
+        */
+       function inheritClass( targetFn, originFn ) {
+               targetFn.parent = originFn;
+               targetFn.prototype = $.extend( {}, originFn.prototype );
+               targetFn.prototype.constructor = originFn.constructor;
+               targetFn.static = $.extend( {}, originFn.static );
+       }
+
+       /**
         * IME Class
+        * @class
+        *
+        * @constructor
+        * @param {HTMLElement} element Element on which to listen for events
+        * @param {TextEntry} textEntry Text entry object to use to get/set text
         * @param {Function} [options.helpHandler] Called for each input method 
row in the selector
         * @param {Object} options.helpHandler.imeSelector
         * @param {String} options.helpHandler.ime Id of the input method
         */
-       function IME( element, options ) {
+       function IME( element, textEntry, options ) {
                this.$element = $( element );
+               this.textEntry = textEntry;
                // This needs to be delayed here since extending language list 
happens at DOM ready
                $.ime.defaults.languages = arrayKeys( $.ime.languages );
                this.options = $.extend( {}, $.ime.defaults, options );
@@ -127,7 +160,7 @@
                 */
                keypress: function ( e ) {
                        var altGr = false,
-                               c, startPos, pos, endPos, divergingPos, input, 
replacement;
+                               c, input, replacement;
 
                        if ( !this.active ) {
                                return true;
@@ -160,24 +193,10 @@
 
                        c = String.fromCharCode( e.which );
 
-                       // Get the current caret position. The user may have 
selected text to overwrite,
-                       // so get both the start and end position of the 
selection. If there is no selection,
-                       // startPos and endPos will be equal.
-                       pos = this.getCaretPosition( this.$element );
-                       startPos = pos[0];
-                       endPos = pos[1];
-
-                       // Get the last few characters before the one the user 
just typed,
+                       // Append the character being typed to the preceding 
few characters,
                        // to provide context for the transliteration regexes.
-                       // We need to append c because it hasn't been added to 
$this.val() yet
-                       input = this.lastNChars(
-                               this.$element.val() || this.$element.text(),
-                               startPos,
-                               this.inputmethod.maxKeyLength
-                       );
-                       input += c;
-
-                       replacement = this.transliterate( input, this.context, 
altGr );
+                       input = this.textEntry.getTextBeforeSelection( 
this.inputmethod.maxKeyLength );
+                       replacement = this.transliterate( input + c, 
this.context, altGr );
 
                        // Update the context
                        this.context += c;
@@ -198,11 +217,7 @@
                                return true;
                        }
 
-                       // Drop a common prefix, if any
-                       divergingPos = this.firstDivergence( input, 
replacement.output );
-                       input = input.substring( divergingPos );
-                       replacement.output = replacement.output.substring( 
divergingPos );
-                       replaceText( this.$element, replacement.output, 
startPos - input.length + 1, endPos );
+                       this.textEntry.replaceTextAtSelection( input.length, 
replacement.output );
 
                        e.stopPropagation();
 
@@ -332,121 +347,200 @@
 
                        return deferred.promise();
                },
+       };
 
-               /**
-                * Returns an array [start, end] of the beginning
-                * and the end of the current selection in $element
-                * @returns {Array}
-                */
-               getCaretPosition: function ( $element ) {
-                       return getCaretPosition( $element );
-               },
+       /**
+        * TextEntry factory
+        * @class
+        *
+        * @constructor
+        */
+       TextEntryFactory = function IMETextEntryFactory() {
+               this.TextEntryClasses = [];
+       };
 
-               /**
-                * Set the caret position in the div.
-                * @param {jQuery} $element The content editable div element
-                * @param {Object} position An object with start and end 
properties.
-                * @return {Array} If the cursor could not be placed at given 
position, how
-                * many characters had to go back to place the cursor
-                */
-               setCaretPosition: function ( $element, position ) {
-                       return setCaretPosition( $element, position );
-               },
+       /* Inheritance */
 
-               /**
-                * Find the point at which a and b diverge, i.e. the first 
position
-                * at which they don't have matching characters.
-                *
-                * @param a String
-                * @param b String
-                * @return Position at which a and b diverge, or -1 if a === b
-                */
-               firstDivergence: function ( a, b ) {
-                       return firstDivergence( a, b );
-               },
+       initClass( TextEntryFactory );
 
-               /**
-                * Get the n characters in str that immediately precede pos
-                * Example: lastNChars( 'foobarbaz', 5, 2 ) === 'ba'
-                *
-                * @param str String to search in
-                * @param pos Position in str
-                * @param n Number of characters to go back from pos
-                * @return Substring of str, at most n characters long, 
immediately preceding pos
-                */
-               lastNChars: function ( str, pos, n ) {
-                       return lastNChars( str, pos, n );
+       /* Methods */
+
+       /**
+        * Register a TextEntry class, with priority over previous registrations
+        *
+        * @param {TextEntry} Class to register
+        */
+       TextEntryFactory.prototype.register = function ( TextEntryClass ) {
+               this.TextEntryClasses.unshift( TextEntryClass );
+       };
+
+       /**
+        * Wrap an editable element with the appropriate TextEntry class
+        *
+        * @param {jQuery} $element The element to wrap
+        * @return {TextEntry|undefined} A TextEntry, or undefined if no match
+        */
+       TextEntryFactory.prototype.wrap = function ( $element ) {
+               var i, len, TextEntryClass;
+               for ( i = 0, len = this.TextEntryClasses.length; i < len; i++ ) 
{
+                       TextEntryClass = this.TextEntryClasses[ i ];
+                       if ( TextEntryClass.static.canWrap( $element ) ) {
+                               return new TextEntryClass( $element );
+                       }
+               }
+               return undefined;
+       };
+
+       /* Initialization */
+
+       TextEntryFactory.static.singleton = new TextEntryFactory();
+
+       /**
+        * Generic text entry
+        * @class
+        *
+        * @abstract
+        */
+       TextEntry = function IMETextEntry() {
+       };
+
+       /* Inheritance */
+
+       initClass( TextEntry );
+
+       /* Static methods */
+
+       /**
+        * Test whether can wrap this type of element
+        *
+        * @param {jQuery} $element The element to wrap
+        * @return {boolean} Whether the element can be wrapped
+        */
+       TextEntry.static.canWrap = function () {
+               return false;
+       };
+
+       /* Abstract methods */
+
+       /**
+        * Get text immediately before the current selection start.
+        *
+        * This SHOULD return the empty string for non-collapsed selections.
+        *
+        * @param {number} maxLength Maximum number of chars (code units) to 
return
+        * @return {String} Up to maxLength of text
+        */
+       TextEntry.prototype.getTextBeforeSelection = null;
+
+       /**
+        * Replace the currently selected text and/or text before the selection
+        *
+        * @param {number} precedingCharCount Number of chars before selection 
to replace
+        * @param {String} newText Replacement text
+        */
+       TextEntry.prototype.replaceTextAtSelection = null;
+
+       /**
+        * TextEntry class for input/textarea widgets
+        * @class
+        *
+        * @constructor
+        * @param {jQuery} $element The element to wrap
+        */
+       FormWidgetEntry = function IMEFormWidgetEntry( $element ) {
+               this.$element = $element;
+       };
+
+       /* Inheritance */
+
+       inheritClass( FormWidgetEntry, TextEntry );
+
+       /* Static methods */
+
+       /**
+        * @inheritdoc TextEntry
+        */
+       FormWidgetEntry.static.canWrap = function ( $element ) {
+               return $element.is( 'input:not([type]), input[type=text], 
input[type=search], textarea' ) &&
+                       !$element.prop( 'readonly' ) &&
+                       !$element.prop( 'disabled' ) &&
+                       !$element.hasClass( 'noime' );
+       };
+
+       /* Instance methods */
+
+       /**
+        * @inheritdoc TextEntry
+        */
+       FormWidgetEntry.prototype.getTextBeforeSelection = function ( maxLength 
) {
+               var pos = this.getCaretPosition();
+               return this.$element.val().substring(
+                       Math.max( 0, pos.start - maxLength ),
+                       pos.start
+               );
+       };
+
+       /**
+        * @inheritdoc TextEntry
+        */
+       FormWidgetEntry.prototype.replaceTextAtSelection = function ( 
precedingCharCount, newText ) {
+               var selection,
+                       length,
+                       newLines,
+                       start,
+                       scrollTop,
+                       pos,
+                       element = this.$element.get( 0 );
+
+               if ( typeof element.selectionStart === 'number' && typeof 
element.selectionEnd === 'number' ) {
+                       // IE9+ and all other browsers
+                       start = element.selectionStart;
+                       scrollTop = element.scrollTop;
+
+                       // Replace the whole text of the text area:
+                       // text before + newText + text after.
+                       // This could be made better if range selection worked 
on browsers.
+                       // But for complex scripts, browsers place cursor in 
unexpected places
+                       // and it's not possible to fix cursor programmatically.
+                       // Ref Bug https://bugs.webkit.org/show_bug.cgi?id=66630
+                       element.value = element.value.substring( 0, start - 
precedingCharCount ) +
+                               newText +
+                               element.value.substring( element.selectionEnd, 
element.value.length );
+
+                       // restore scroll
+                       element.scrollTop = scrollTop;
+                       // set selection
+                       element.selectionStart = element.selectionEnd = start - 
precedingCharCount + newText.length;
+               } else {
+                       // IE8 and lower
+                       pos = this.getCaretPosition();
+                       selection = element.createTextRange();
+                       length = element.value.length;
+                       // IE doesn't count \n when computing the offset, so we 
won't either
+                       newLines = element.value.match( /\n/g );
+
+                       if ( newLines ) {
+                               length = length - newLines.length;
+                       }
+
+                       selection.moveStart( 'character', pos.start - 
precedingCharCount );
+                       selection.moveEnd( 'character', pos.end - length );
+
+                       selection.text = newText;
+                       selection.collapse( false );
+                       selection.select();
                }
        };
 
        /**
-        * jQuery plugin ime
-        * @param {Object} option
+        * Get the current selection offsets inside the widget
+        *
+        * @return {Object} Offsets in chars (0 means first offset *or* no 
selection in widget)
+        * @return.start {number} Selection start
+        * @return.end {number} Selection end
         */
-       $.fn.ime = function ( option ) {
-               return this.each( function () {
-                       var data,
-                               $this = $( this ),
-                               options = typeof option === 'object' && option;
-
-                       // Some exclusions: IME shouldn't be applied to 
textareas with
-                       // these properties.
-                       if ( $this.prop( 'readonly' ) ||
-                               $this.prop( 'disabled' ) ||
-                               $this.hasClass( 'noime' ) ) {
-                               return;
-                       }
-
-                       data = $this.data( 'ime' );
-
-                       if ( !data ) {
-                               data = new IME( this, options );
-                               $this.data( 'ime', data );
-                       }
-
-                       if ( typeof option === 'string' ) {
-                               data[option]();
-                       }
-               } );
-       };
-
-       $.ime = {};
-       $.ime.inputmethods = {};
-       $.ime.sources = {};
-       $.ime.preferences = {};
-       $.ime.languages = {};
-
-       var defaultInputMethod = {
-               contextLength: 0,
-               maxKeyLength: 1
-       };
-
-       $.ime.register = function ( inputMethod ) {
-               $.ime.inputmethods[inputMethod.id] = $.extend( {}, 
defaultInputMethod, inputMethod );
-       };
-
-       // default options
-       $.ime.defaults = {
-               imePath: '../', // Relative/Absolute path for the rules folder 
of jquery.ime
-               languages: [], // Languages to be used- by default all languages
-               helpHandler: null // Called for each ime option in the menu
-       };
-
-       /**
-        * private function for debugging
-        */
-       function debug( $obj ) {
-               if ( window.console && window.console.log ) {
-                       window.console.log( $obj );
-               }
-       }
-
-       /**
-        * Returns an array [start, end] of the beginning
-        * and the end of the current selection in $element
-        */
-       function getCaretPosition( $element ) {
-               var el = $element.get( 0 ),
+       FormWidgetEntry.prototype.getCaretPosition = function () {
+               var el = this.$element.get( 0 ),
                        start = 0,
                        end = 0,
                        normalizedValue,
@@ -455,10 +549,6 @@
                        len,
                        newLines,
                        endRange;
-
-               if ( $element.is( '[contenteditable]' ) ) {
-                       return getDivCaretPosition( el );
-               }
 
                if ( typeof el.selectionStart === 'number' && typeof 
el.selectionEnd === 'number' ) {
                        start = el.selectionStart;
@@ -499,264 +589,189 @@
                                }
                        }
                }
+               return { start: start, end: end };
+       };
 
-               return [start, end];
-       }
+       TextEntryFactory.static.singleton.register( FormWidgetEntry );
 
        /**
-        * Helper function to get an IE TextRange object for an element
+        * TextEntry class for ContentEditable
+        * @class
+        *
+        * @constructor
+        * @param {jQuery} $element The element to wrap
         */
-       function rangeForElementIE( element ) {
-               var selection;
+       ContentEditableEntry = function IMEContentEditableEntry( $element ) {
+               this.$element = $element;
+       };
 
-               if ( element.nodeName.toLowerCase() === 'input' ) {
-                       selection = element.createTextRange();
-               } else {
-                       selection = document.body.createTextRange();
-                       selection.moveToElementText( element );
+       /* Inheritance */
+
+       inheritClass( ContentEditableEntry, TextEntry );
+
+       /* Static methods */
+
+       /**
+        * @inheritdoc TextEntry
+        */
+       ContentEditableEntry.static.canWrap = function ( $element ) {
+               return $element.is( '[contenteditable]' ) && 
!$element.hasClass( 'noime' );
+       };
+
+       /* Instance methods */
+
+       /**
+        * @inheritdoc TextEntry
+        */
+       ContentEditableEntry.prototype.getTextBeforeSelection = function ( 
maxLength ) {
+               var range = this.getSelectedRange();
+               if ( !range || !range.collapsed || 
range.startContainer.nodeType !== Node.TEXT_NODE ) {
+                       return '';
                }
+               return range.startContainer.nodeValue.substring(
+                       Math.max( 0, range.startOffset - maxLength ),
+                       range.startOffset
+               );
+       };
 
-               return selection;
-       }
+       /**
+        * @inheritdoc SelectionWrapper
+        */
+       ContentEditableEntry.prototype.replaceTextAtSelection = function ( 
precedingCharCount, newText ) {
+               var range, textNode, textOffset, newOffset, newRange;
 
-       function replaceText( $element, replacement, start, end ) {
-               var selection,
-                       length,
-                       newLines,
-                       scrollTop,
-                       range,
-                       correction,
-                       textNode,
-                       element = $element.get( 0 );
-
-               if ( $element.is( '[contenteditable]' ) ) {
-                       correction = setCaretPosition( $element, {
-                               start: start,
-                               end: end
-                       } );
-
-                       rangy.init();
-                       selection = rangy.getSelection();
-                       range = selection.getRangeAt( 0 );
-
-                       if ( correction[0] > 0 ) {
-                               replacement = selection.toString().substring( 
0, correction[0] ) + replacement;
-                       }
-
-                       textNode = document.createTextNode( replacement );
-                       range.deleteContents();
-                       range.insertNode( textNode );
-                       range.commonAncestorContainer.normalize();
-                       start = end = start + replacement.length - 
correction[0];
-                       setCaretPosition( $element, {
-                               start: start,
-                               end: end
-                       } );
-
+               if ( !this.getSelectedRange() ) {
                        return;
                }
 
-               if ( typeof element.selectionStart === 'number' && typeof 
element.selectionEnd === 'number' ) {
-                       // IE9+ and all other browsers
-                       scrollTop = element.scrollTop;
+               // Trigger any externally registered jQuery compositionstart 
event listeners.
+               // TODO: Try node.dispatchEvent( new CompositionEvent(...) ) so 
listeners not
+               // registered using jQuery will also get triggered, then 
fallback gracefully for
+               // browsers that do not support it.
+               this.$element.trigger( 'compositionstart' );
 
-                       // Replace the whole text of the text area:
-                       // text before + replacement + text after.
-                       // This could be made better if range selection worked 
on browsers.
-                       // But for complex scripts, browsers place cursor in 
unexpected places
-                       // and it's not possible to fix cursor programmatically.
-                       // Ref Bug https://bugs.webkit.org/show_bug.cgi?id=66630
-                       element.value = element.value.substring( 0, start ) +
-                               replacement +
-                               element.value.substring( end, 
element.value.length );
+               range = this.getSelectedRange();
 
-                       // restore scroll
-                       element.scrollTop = scrollTop;
-                       // set selection
-                       element.selectionStart = element.selectionEnd = start + 
replacement.length;
-               } else {
-                       // IE8 and lower
-                       selection = rangeForElementIE(element);
-                       length = element.value.length;
-                       // IE doesn't count \n when computing the offset, so we 
won't either
-                       newLines = element.value.match( /\n/g );
-
-                       if ( newLines ) {
-                               length = length - newLines.length;
-                       }
-
-                       selection.moveStart( 'character', start );
-                       selection.moveEnd( 'character', end - length );
-
-                       selection.text = replacement;
-                       selection.collapse( false );
-                       selection.select();
+               if ( !range.collapsed ) {
+                       range.deleteContents();
                }
-       }
 
-       function getDivCaretPosition( element ) {
-               var charIndex = 0,
-                       start = 0,
-                       end = 0,
-                       foundStart = false,
-                       foundEnd = false,
-                       sel;
+               if ( range.startContainer.nodeType === Node.TEXT_NODE ) {
+                       // Alter this text node's content and move the cursor
+                       textNode = range.startContainer;
+                       textOffset = range.startOffset;
+                       textNode.nodeValue =
+                               textNode.nodeValue.substr( 0, textOffset - 
precedingCharCount ) +
+                               newText +
+                               textNode.nodeValue.substr( textOffset );
+                       newOffset = textOffset - precedingCharCount + 
newText.length;
+                       newRange = rangy.createRange();
+                       newRange.setStart( range.startContainer, newOffset );
+                       newRange.setEnd( range.startContainer, newOffset );
+                       rangy.getSelection().setSingleRange( newRange );
+               } else {
+                       // XXX assert precedingCharCount === 0
+                       // Insert a new text node with the new text
+                       textNode = document.createTextNode( newText );
+                       range.startContainer.insertBefore(
+                               textNode,
+                               range.startContainer.childNodes[ 
range.startOffset ]
+                       );
+                       newRange = rangy.createRange();
+                       newRange.setStart( textNode, textNode.length );
+                       newRange.setEnd( textNode, textNode.length );
+                       rangy.getSelection().setSingleRange( newRange );
+               }
 
+               // Trigger any externally registered jQuery compositionend / 
input event listeners.
+               // TODO: Try node.dispatchEvent( new CompositionEvent(...) ) so 
listeners not
+               // registered using jQuery will also get triggered, then 
fallback gracefully for
+               // browsers that do not support it.
+               this.$element.trigger( 'compositionend' );
+               this.$element.trigger( 'input' );
+       };
+
+       /**
+        * Get the selection range inside the wrapped element, or null
+        *
+        * @return {Range|null} The selection range
+        */
+       ContentEditableEntry.prototype.getSelectedRange = function () {
+               var sel, range;
                rangy.init();
                sel = rangy.getSelection();
-
-               function traverseTextNodes( node, range ) {
-                       var i, childNodesCount;
-
-                       if ( node.nodeType === Node.TEXT_NODE ) {
-                               if ( !foundStart && node === 
range.startContainer ) {
-                                       start = charIndex + range.startOffset;
-                                       foundStart = true;
-                               }
-
-                               if ( foundStart && node === range.endContainer 
) {
-                                       end = charIndex + range.endOffset;
-                                       foundEnd = true;
-                               }
-
-                               charIndex += node.length;
-                       } else {
-                               childNodesCount = node.childNodes.length;
-
-                               for ( i = 0; i < childNodesCount; ++i ) {
-                                       traverseTextNodes( node.childNodes[i], 
range );
-                                       if ( foundEnd ) {
-                                               break;
-                                       }
-                               }
-                       }
+               if ( sel.rangeCount === 0 ) {
+                       return null;
                }
-
-               if ( sel.rangeCount ) {
-                       traverseTextNodes( element, sel.getRangeAt( 0 ) );
+               range = sel.getRangeAt( 0 );
+               if ( !this.$element[ 0 ].contains( 
range.commonAncestorContainer ) ) {
+                       return null;
                }
+               return range;
+       };
 
-               return [ start, end ];
-       }
+       TextEntryFactory.static.singleton.register( ContentEditableEntry );
 
-       function setCaretPosition( $element, position ) {
-               var currentPosition,
-                       startCorrection = 0,
-                       endCorrection = 0,
-                       element = $element[0];
-
-               setDivCaretPosition( element, position );
-               currentPosition = getDivCaretPosition( element );
-               // see Bug https://bugs.webkit.org/show_bug.cgi?id=66630
-               while ( position.start !== currentPosition[0] ) {
-                       position.start -= 1; // go back one more position.
-                       if ( position.start < 0 ) {
-                               // never go beyond 0
-                               break;
-                       }
-                       setDivCaretPosition( element, position );
-                       currentPosition = getDivCaretPosition( element );
-                       startCorrection += 1;
-               }
-
-               while ( position.end !== currentPosition[1] ) {
-                       position.end += 1; // go forward one more position.
-                       setDivCaretPosition( element, position );
-                       currentPosition = getDivCaretPosition( element );
-                       endCorrection += 1;
-                       if ( endCorrection > 10 ) {
-                               // XXX avoid rare case of infinite loop here.
-                               break;
-                       }
-               }
-
-               return [startCorrection, endCorrection];
-       }
+       /* Exports */
 
        /**
-        * Set the caret position in the div.
-        * @param {Element} element The content editable div element
-        * @param position
+        * jQuery plugin ime
+        * @param {Object} option
         */
-       function setDivCaretPosition( element, position ) {
-               var nextCharIndex,
-                       charIndex = 0,
-                       range = rangy.createRange(),
-                       foundStart = false,
-                       foundEnd = false;
+       $.fn.ime = function ( option ) {
+               return this.each( function () {
+                       var data, textEntry,
+                               $this = $( this ),
+                               options = typeof option === 'object' && option;
 
-               range.collapseToPoint( element, 0 );
-
-               function traverseTextNodes( node ) {
-                       var i, len;
-
-                       if ( node.nodeType === 3 ) {
-                               nextCharIndex = charIndex + node.length;
-
-                               if ( !foundStart && position.start >= charIndex 
&& position.start <= nextCharIndex ) {
-                                       range.setStart( node, position.start - 
charIndex );
-                                       foundStart = true;
+                       data = $this.data( 'ime' );
+                       if ( !data ) {
+                               textEntry = 
TextEntryFactory.static.singleton.wrap( $this );
+                               if ( textEntry === undefined ) {
+                                       return;
                                }
-
-                               if ( foundStart && position.end >= charIndex && 
position.end <= nextCharIndex ) {
-                                       range.setEnd( node, position.end - 
charIndex );
-                                       foundEnd = true;
-                               }
-
-                               charIndex = nextCharIndex;
-                       } else {
-                               for ( i = 0, len = node.childNodes.length; i < 
len; ++i ) {
-                                       traverseTextNodes( node.childNodes[i] );
-                                       if ( foundEnd ) {
-                                               
rangy.getSelection().setSingleRange( range );
-                                               break;
-                                       }
-                               }
+                               data = new IME( this, textEntry, options );
+                               $this.data( 'ime', data );
                        }
-               }
 
-               traverseTextNodes( element );
+                       if ( typeof option === 'string' ) {
+                               data[option]();
+                       }
+               } );
+       };
 
-       }
+       $.ime = {};
+       $.ime.inputmethods = {};
+       $.ime.sources = {};
+       $.ime.preferences = {};
+       $.ime.languages = {};
+
+       $.ime.textEntryFactory = TextEntryFactory.static.singleton;
+       $.ime.TextEntry = TextEntry;
+       $.ime.inheritClass = inheritClass;
+
+       defaultInputMethod = {
+               contextLength: 0,
+               maxKeyLength: 1
+       };
+
+       $.ime.register = function ( inputMethod ) {
+               $.ime.inputmethods[inputMethod.id] = $.extend( {}, 
defaultInputMethod, inputMethod );
+       };
+
+       // default options
+       $.ime.defaults = {
+               imePath: '../', // Relative/Absolute path for the rules folder 
of jquery.ime
+               languages: [], // Languages to be used- by default all languages
+               helpHandler: null // Called for each ime option in the menu
+       };
 
        /**
-        * Find the point at which a and b diverge, i.e. the first position
-        * at which they don't have matching characters.
-        *
-        * @param a String
-        * @param b String
-        * @return Position at which a and b diverge, or -1 if a === b
+        * private function for debugging
         */
-       function firstDivergence( a, b ) {
-               var minLength, i;
-
-               minLength = a.length < b.length ? a.length : b.length;
-
-               for ( i = 0; i < minLength; i++ ) {
-                       if ( a.charCodeAt( i ) !== b.charCodeAt( i ) ) {
-                               return i;
-                       }
-               }
-
-               return -1;
-       }
-
-       /**
-        * Get the n characters in str that immediately precede pos
-        * Example: lastNChars( 'foobarbaz', 5, 2 ) === 'ba'
-        *
-        * @param str String to search in
-        * @param pos Position in str
-        * @param n Number of characters to go back from pos
-        * @return Substring of str, at most n characters long, immediately 
preceding pos
-        */
-       function lastNChars( str, pos, n ) {
-               if ( n === 0 ) {
-                       return '';
-               } else if ( pos <= n ) {
-                       return str.substr( 0, pos );
-               } else {
-                       return str.substr( pos - n, n );
+       function debug( $obj ) {
+               if ( window.console && window.console.log ) {
+                       window.console.log( $obj );
                }
        }
 
@@ -1601,6 +1616,10 @@
                        name: 'ফনেটিক',
                        source: 'rules/as/as-phonetic.js'
                },
+               'as-rodali': {
+                       name: 'ৰ\'দালি',
+                       source: 'rules/as/as-rodali.js'
+               },
                'as-transliteration': {
                        name: 'প্ৰতিৰূপান্তৰণ',
                        source: 'rules/as/as-transliteration.js'
@@ -2014,6 +2033,10 @@
                'or-transliteration': {
                        name: 'ଟ୍ରାନ୍ସଲିଟରେସନ',
                        source: 'rules/or/or-transliteration.js'
+               },
+               'or-OdiScript': {
+                       name: 'ଓଡ଼ିସ୍କ୍ରିପ୍ଟ',
+                       source: 'rules/or/or-OdiScript.js'
                },
                'or-inscript': {
                        name: 'ଇନସ୍କ୍ରିପ୍ଟ',
@@ -2435,7 +2458,7 @@
                },
                'or': {
                        autonym: 'ଓଡ଼ିଆ',
-                       inputmethods: [ 'or-phonetic', 'or-transliteration', 
'or-inscript', 'or-inscript2', 'or-lekhani' ]
+                       inputmethods: [ 'or-phonetic', 'or-transliteration', 
'or-inscript', 'or-inscript2', 'or-lekhani', 'or-OdiScript' ]
                },
                'pa': {
                        autonym: 'ਪੰਜਾਬੀ',
diff --git a/lib/jquery.ime/rules/or/or-lekhani.js 
b/lib/jquery.ime/rules/or/or-lekhani.js
index eb36675..364890a 100644
--- a/lib/jquery.ime/rules/or/or-lekhani.js
+++ b/lib/jquery.ime/rules/or/or-lekhani.js
@@ -7,7 +7,7 @@
                description: 'Odia Lekhani phonetic input method',
                date: '2012-10-14',
                URL: 'http://github.com/wikimedia/jquery.ime',
-               author: 'Junaid P V and Subhashish Panigrahi',
+               author: 'Junaid P V, Subhashish Panigrahi and Jnanaranjan Sahu',
                license: 'GPLv3',
                version: '1.0',
                contextLength: 4,
@@ -15,7 +15,7 @@
                patterns: [
                        ['\\\\([A-Za-z\\>_~\\.0-9])', '\\\\', '$1'],
 
-                       
['([(କ-ହୟୱଡ଼ଢ଼ଙ୍କଙ୍ଖଙ୍ଗଙ୍ଘଞ୍ଚଞ୍ଛଞ୍ଝଣ୍ଟଣ୍ଠଣ୍ଡଣ୍ଢନ୍ତନ୍ଥନ୍ଦନ୍ଧମ୍ପମ୍ଫମ୍ବମ୍ଭଞ୍ଜ])a', 
'$1ା'],
+                       
['([କ-ହୟୱଡ଼ଢ଼ଙ୍କଙ୍ଖଙ୍ଗଙ୍ଘଞ୍ଚଞ୍ଛଞ୍ଝଣ୍ଟଣ୍ଠଣ୍ଡଣ୍ଢନ୍ତନ୍ଥନ୍ଦନ୍ଧମ୍ପମ୍ଫମ୍ବମ୍ଭଞ୍ଜ])a', 
'$1ା'],
                        
['([କ-ଳଲନ୍ଧଥଡ଼ଢ଼ହୟୱରକ୍ଷଶସଷଙ୍କଙ୍ଖଙ୍ଗଙ୍ଘଞ୍ଚଞ୍ଛଞ୍ଝଣ୍ଟଣ୍ଠଣ୍ଡଣ୍ଢନ୍ତନ୍ଥନ୍ଦନ୍ଧମ୍ପମ୍ଫମ୍ବମ୍ଭଞ୍ଜ])i',
 '$1\u0b3f'],
                        
['([କ-ହୟୱଡ଼ଢ଼ଙ୍କଙ୍ଖଙ୍ଗଙ୍ଘଞ୍ଚଞ୍ଛଞ୍ଝଣ୍ଟଣ୍ଠଣ୍ଡଣ୍ଢନ୍ତନ୍ଥନ୍ଦନ୍ଧମ୍ପମ୍ଫମ୍ବମ୍ଭଞ୍])I', 
'$1ୀ'],
                        
['([କ-ହୟୱଡ଼ଢ଼ଙ୍କଙ୍ଖଙ୍ଗଙ୍ଘଞ୍ଚଞ୍ଛଞ୍ଝଣ୍ଟଣ୍ଠଣ୍ଡଣ୍ଢନ୍ତନ୍ଥନ୍ଦନ୍ଧମ୍ପମ୍ଫମ୍ବମ୍ଭଞ୍])u', 
'$1\u0b41'],
@@ -31,13 +31,13 @@
                        ['([କ-ହୟୱ])(w|v)', '$1୍ୱ'],
                        ['([କ-ହୟୱ])~', '$1\u200C'],
 
-                       ['([କ-ହୟୱ])y', '$1୍ୟ'], // <consonant>y
+                       ['([କ-ହୱ])y', '$1୍ୟ'], // <consonant>y
 
                        ['z', '୍'], // halanta
                        ['\\.', '।'], //purnacheda
                        ['ଅa', 'ଆ'],
                        ['ଏe', 'ଐ'],
-                       ['(ଅu|ଓo|ଓO)', 'ଔ'],
+                       ['(ଅu|O)', 'ଔ'],
                        ['ଋR', 'ୠ'], // RR
                        ['ଳl', 'ଌ'], // Ll
                        ['ଌl', 'ୡ'], // Lll
@@ -45,8 +45,6 @@
                        ['ଞ୍ଜh', 'ଞ୍ଝ'], // njh
                        ['ଙ୍କh', 'ଙ୍ଖ'], // nkh
                        ['ଙ୍ଗh', 'ଙ୍ଘ'], // ngh
-                       ['ହm', 'ହ୍ମ'], // mh
-                       ['ହn', 'ହ୍ନ'], // nh
                        ['ମ୍ବh', 'ମ୍ଭ'], // mbh or nbh
                        ['ଣ୍ଡai', 'ଣ୍ଡାଇ'], // NDai
                        ['ଜ୍ଜh', 'ଜ୍ଝ'], // jjh
@@ -67,7 +65,6 @@
                        ['ନD|ଣD', 'ଣ୍ଡ'], // nd
                        ['ଣDh', 'ଣ୍ଢ'], //ndh
                        ['ନdh', 'ନ୍ଧ'], // ndht
-                       ['ଷT', '$1୍ଟ'], // ST
                        ['ଟh', 'ଠ'], // Th
                        ['ଡh', 'ଢ'], // Dh
                        ['ତh', 'ଥ'], // th
diff --git a/lib/jquery.ime/rules/sdh/sdh-kbd.js 
b/lib/jquery.ime/rules/sdh/sdh-kbd.js
index e1b7c2f..c76a14c 100644
--- a/lib/jquery.ime/rules/sdh/sdh-kbd.js
+++ b/lib/jquery.ime/rules/sdh/sdh-kbd.js
@@ -17,7 +17,7 @@
                        ['3', '٣'],
                        ['4', '٤'],
                        ['5', '٥'],
-                       ['6', '٦'],
+                       ['6', '۶'],
                        ['7', '٧'],
                        ['8', '٨'],
                        ['9', '٩'],
diff --git a/lib/jquery.ime/rules/si/si-singlish.js 
b/lib/jquery.ime/rules/si/si-singlish.js
index 8ba93b1..d872015 100644
--- a/lib/jquery.ime/rules/si/si-singlish.js
+++ b/lib/jquery.ime/rules/si/si-singlish.js
@@ -11,7 +11,7 @@
                license: 'GPLv3',
                version: '1.0',
                contextLength: 5,
-               maxKeyLength: 2,
+               maxKeyLength: 5,
                patterns: [
                        //['ඬ්හ්a', 'ඳ'],       // nndha
                        ['ඬ්h', 'ඳ්'], // nndh
diff --git a/lib/jquery.ime/rules/yo/yo-alt.js 
b/lib/jquery.ime/rules/yo/yo-alt.js
index 2e8c41b..b272472 100644
--- a/lib/jquery.ime/rules/yo/yo-alt.js
+++ b/lib/jquery.ime/rules/yo/yo-alt.js
@@ -16,7 +16,7 @@
                        // Combining grave tone mark
                        ['\\\\', '\u0340'],
                        // Combining acute tone mark
-                       ["/", '\u0341']
+                       ['/', '\u0341']
                ]
        };
 

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia7301bddb79c1fbce2af7190494bdd7bdd909862
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/UniversalLanguageSelector
Gerrit-Branch: master
Gerrit-Owner: Amire80 <amir.ahar...@mail.huji.ac.il>

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

Reply via email to