jenkins-bot has submitted this change and it was merged.
Change subject: Update jquery.ime from upstream
......................................................................
Update jquery.ime from upstream
* Digit fix in Southern Kurdish.
* Rodali, Or-Lekhani and OdiScript layouts.
* Major updates for VisualEditor integration by David Chan.
Change-Id: Ia7301bddb79c1fbce2af7190494bdd7bdd909862
---
M lib/jquery.ime/jquery.ime.js
A lib/jquery.ime/rules/as/as-rodali.js
A lib/jquery.ime/rules/or/or-OdiScript.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
7 files changed, 653 insertions(+), 370 deletions(-)
Approvals:
Divec: Looks good to me, approved
jenkins-bot: Verified
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/as/as-rodali.js
b/lib/jquery.ime/rules/as/as-rodali.js
new file mode 100644
index 0000000..a26e6cd
--- /dev/null
+++ b/lib/jquery.ime/rules/as/as-rodali.js
@@ -0,0 +1,147 @@
+( function ( $ ) {
+ 'use strict';
+
+ var asRodali = {
+ id: 'as-rodali',
+ name: 'ৰ\'দালি',
+ description: 'Rodali Keyboard',
+ date: '2015-07-26',
+ URL: 'http://github.com/wikimedia/jquery.ime',
+ author: 'Gunadeep Chetia, Subhashish Panigrahi',
+ license: 'GPLv3',
+ version: '1.0',
+ contextLength: 4,
+ maxKeyLength: 5,
+ patterns: [
+ ['([ক-হড়ঢ়য়])্?ৰৰi','[^a`]', '$1ৃ'],
+ ['ৰৰi','[^a`]', 'ঋ'],
+ ['(([ক-হড়ঢ়ৰৱয়]))a','[^a`]', '$1'],
+ ['([ক-হড়ঢ়ৰৱয়])a','a', '$1া'],
+ ['([ক-হড়ঢ়ৰৱয়])i','[^a`]', '$1ি'],
+ ['([ক-হড়ঢ়ৰৱয়])(িi|েe)','[^a`]', '$1ী'],
+ ['([ক-হড়ঢ়ৰৱয়])u','[^a`]', '$1ু'],
+ ['([ক-হড়ঢ়ৰৱয়])ুu','[^a`]', '$1ূ'],
+ ['([ক-হড়ঢ়ৰৱয়])o','[^a`]', '$1ো'],
+ ['([ক-হড়ঢ়ৰৱয়])e','[^a`]', '$1ে'],
+ ['([ক-হড়ঢ়ৰৱয়])োi','[^a`]', '$1ৈ'],
+ ['([ক-হড়ঢ়ৰৱয়])োu','[^a`]', '$1ৌ'],
+ ['([কঙলষস])(k|K)','[^a`]','$1্ক'],
+ ['([গঙদল])(g)','[^a`]','$1্গ'],
+ ['([চশ])c','[^a`]','$1্চ'],
+ ['([জঞব])j','[^a`]','$1্জ'],
+ ['নj','[^a`]','ঞ্জ'],
+ ['([কটণনপলষস])T','[^a`]','$1্ট'],
+ ['([ডণনল])D','[^a`]','$1্ড'],
+ ['([গষহ])N','[^a`]','$1্ণ'],
+ ['([কতনপশসহ])t','[^a`]','$1্ত'],
+ ['([গদনব])d','[^a`]','$1্দ'],
+ ['([গঘণতধনপমশসহ])n','[^a`]','$1্ন'],
+ ['([পমলষস])p','[^a`]','$1্প'],
+ ['([মস])f', '[^a`]', '$1্ফ'],
+ ['([বমল])b','[^a`]','$1্ব'],
+ ['([কগঙটণতদধনমলশষসহ])m','[^a`]','$1্ম'],
+ ['([ক-ঘচ-ঝট-যলশ-হড়ঢ়য়])r','[^a`]','$1্ৰ'],
+ ['([কগপ-বমলশসহ])l','[^a`]','$1্ল'],
+ ['([কনপ])s','[^a`]','$1্স'],
+ ['([ক-হড়ঢ়য়])(w|b|v)','[^a`]','$1্ব'],
+ ['([ক-হড়ঢ়য়])y','[^a`]','$1্য'],
+ ['নc','[^a`]','ঞ্চ'],
+ ['ৰk','r','ৰ্ক'],
+ ['ৰg','r','ৰ্গ'],
+ ['ৰc','r','ৰ্চ'],
+ ['ৰj','r','ৰ্জ'],
+ ['ৰT','r','ৰ্ট'],
+ ['ৰD','r','ৰ্ড'],
+ ['ৰN','r','ৰ্ণ'],
+ ['ৰt','r','ৰ্ত'],
+ ['ৰd','r','ৰ্দ'],
+ ['ৰn','r','ৰ্ন'],
+ ['ৰp','r','ৰ্প'],
+ ['ৰf','r','ৰ্ফ'],
+ ['ৰb','r','ৰ্ব'],
+ ['ৰv','r','ৰ্ভ'],
+ ['ৰm','r','ৰ্ম'],
+ ['ৰz','r','ৰ্য'],
+ ['ৰl','r','ৰ্ল'],
+ ['ৰx','r','ৰ্শ'],
+ ['ৰS','r','ৰ্ষ'],
+ ['ৰs','r','ৰ্স'],
+ ['ৰh','r','ৰ্হ'],
+ ['ৰR','r','ৰ্ড়'],
+ ['ৰy','r','ৰ্য়'],
+ ['ত~','t','ৎ'],
+ ['অa','a', 'আ'],
+ ['কh','k', 'খ'],
+ ['গh','g', 'ঘ'],
+ ['ণg','N', 'ঙ'],
+ ['চh','c', 'ছ'],
+ ['জh','j', 'ঝ'],
+ ['নG','n', 'ঞ'],
+ ['টh','T', 'ঠ'],
+ ['ডh','D', 'ঢ'],
+ ['তh','t', 'থ'],
+ ['দh','d', 'ধ'],
+ ['পh','p', 'ফ'],
+ ['বh','b', 'ভ'],
+ ['সh','s', 'শ'],
+ ['ড়h','R', 'ঢ়'],
+ ['নg','n', 'ং'],
+ ['ওi','o', 'ঐ'],
+ ['ওu','o', 'ঔ'],
+ ['ইi','i', 'ঈ'],
+ ['উu','u', 'ঊ'],
+ ['([kK])', 'ক'],
+ ['g', 'গ'],
+ ['G', 'জ্ঞ'],
+ ['(c|C)', 'চ'],
+ ['(j|J)', 'জ'],
+ ['T', 'ট'],
+ ['D', 'ড'],
+ ['N', 'ণ'],
+ ['t', 'ত'],
+ ['d', 'দ'],
+ ['n', 'ন'],
+ ['(p|P)', 'প'],
+ ['f', 'ফ'],
+ ['(b|B)', 'ব'],
+ ['(v|V)', 'ৱ'],
+ ['(m|M)', 'ম'],
+ ['z|Z', 'য'],
+ ['r', 'ৰ'],
+ ['(l|L)', 'ল'],
+ ['S', 'ষ'],
+ ['s', 'স'],
+ ['h', 'হ'],
+ ['H', 'ঃ'],
+ ['R', 'ড়'],
+ ['(w|W)', 'ৱ'],
+ ['x', 'শ'],
+ ['X', 'ক্ষ'],
+ ['y', 'য়'],
+ ['a', 'অ'],
+ ['i', 'ই'],
+ ['u', 'উ'],
+ ['e', 'এ'],
+ ['o', 'ও'],
+ ['0', '০'],
+ ['1', '১'],
+ ['2', '২'],
+ ['3', '৩'],
+ ['4', '৪'],
+ ['5', '৫'],
+ ['6', '৬'],
+ ['7', '৭'],
+ ['8', '৮'],
+ ['9', '৯'],
+ ['<','ৃ'],
+ ['`', '্'],
+ ['\\^', 'ঁ'],
+ ['\\.', '।'],
+ ['~', '্'],
+ ['&', '°'],
+ ['\\*', '৺']
+ ]
+ };
+
+ $.ime.register( asRodali );
+}( jQuery ) );
diff --git a/lib/jquery.ime/rules/or/or-OdiScript.js
b/lib/jquery.ime/rules/or/or-OdiScript.js
new file mode 100644
index 0000000..d4927b4
--- /dev/null
+++ b/lib/jquery.ime/rules/or/or-OdiScript.js
@@ -0,0 +1,116 @@
+( function ( $ ) {
+ 'use strict';
+
+ var orOdiScript = {
+ id: 'or-OdiScript',
+ name: 'ଓଡ଼ିସ୍କ୍ରିପ୍ଟ',
+ description: 'Odia OdiScript input method',
+ date: '2015-7-28',
+ URL: 'http://github.com/wikimedia/jquery.ime',
+ author: 'Manoj Sahukar and Subhashish Panigrahi',
+ license: 'GPLv3',
+ version: '1.0',
+ contextLength: 6,
+ maxKeyLength: 4,
+ patterns: [
+
['/([A-Za-z\\>_\\-\\!@#\\$\\^\\&\\%\\*\\~\\.\\|\\\\0-9])', '$1'],
+ ['\'([\'])','\"'], //'' to "
+ ['\"([\'])','\'\'\''], //'''
+ ['([କ-ହ]୍[କ-ହ])@@', 'ର୍\$1'], //reph
+ ['([କ-ହ])@@', 'ର୍\$1'], //reph
+ ['%%', 'ଙ୍କ' ], // Anka
+ ['"', 'ଁ' ], //chanda bindu
+ ['([ର])}', 'ର୍ୟ'], // special case: Ja phala (ର + ZWJ
+ ୍ୟ)
+ ['\\}', '୍ୟ' ], // Ja phala
+ ['୍\ ', '୍ '], // ending with halant+zwnj
+ ['{', 'ୃ' ], // Ru kara
+ ['େk', 'ୋ' ], // l= ekar, lk = okar
+ ['ାl', 'ୋ' ], // l= ekar, kl = okar
+ ['େp', 'ୈ' ], //
+ ['ୈk', 'ୌ' ], //
+ ['\\]', '୍ର'], // Ra phala
+ ['\\[', 'ଅ'], // Type ଅ
+ ['ଅk','ଆ'], // ଅ + ା = ଆ
+ ['ଓ##','ୱ'],
+ ['([ର])##', 'ର୍ୱ'], // special case ର + ZWJ + ୍ୱ
+ ['([କ-ହ])##', '$1୍ୱ'], //
+ ['ଦQ', 'ହ'],
+ ['([କନପସମ])Q', 'ତ୍\$1' ],
+ ['([ଖଥଧ])Q', '$1ି' ],
+ ['([ନସ])_', '$1୍ତ୍ର' ], //ନ୍ତ୍ର , ସ୍ତ୍ର
+ ['\\$', 'କ୍ଷ'],
+ ['\\&&','ଏବଂ'],
+ ['\\^', 'ଋ'],
+ ['\\|', 'ଞ'],
+ ['\\\\', 'ୟ'],
+ ['<', 'ଏ'],
+ ['>', 'ଐ'],
+ ['0', '୦'],
+ ['1', '୧'],
+ ['2', '୨'],
+ ['3', '୩'],
+ ['4', '୪'],
+ ['5', '୫'],
+ ['6', '୬'],
+ ['7', '୭'],
+ ['8', '୮'],
+ ['9', '୯'],
+ ['a', 'ମ'],
+ ['A', 'ଢ଼'],
+ ['b', 'ୁ'],
+ ['B', 'ଉ'],
+ ['c', 'ଜ'],
+ ['C', 'ଝ'],
+ ['d', '୍'],
+ ['D', ''], //zwnj
+ ['e', 'ନ'],
+ ['E', 'ଡ଼'],
+ ['f', 'ତ'],
+ ['F', 'ଥ'],
+ ['G', 'ଇ'],
+ ['g', 'ି'],
+ ['H', 'ଈ'],
+ ['h', 'ୀ'],
+ ['i', 'ଂ'],
+ ['I', 'ଠ'],
+ ['j', 'ର'],
+ ['J', 'ଣ'],
+ ['k', 'ା'],
+ ['K', 'ଶ'],
+ ['l', 'େ'],
+ ['L', 'ଷ'],
+ ['m', 'ଳ'],
+ ['M', 'ଲ'],
+ ['n', 'ୂ'],
+ ['N', 'ଊ'],
+ ['o', 'ହ'],
+ ['O', 'ଡ'],
+ ['p', 'ୈ'],
+ ['P', 'ଢ'],
+ ['q', 'ବ'],
+ ['r', 'ଦ'],
+ ['R', 'ଧ'],
+ ['s', 'କ'],
+ ['S', 'ଖ'],
+ ['t', 'ସ'],
+ ['T', 'ଓ'],
+ ['u', 'ଯ'],
+ ['U', 'ଟ'],
+ ['v', 'ଚ'],
+ ['V', 'ଛ'],
+ ['w', 'ପ'],
+ ['W', 'ଫ'],
+ ['x', 'ଗ'],
+ ['X', 'ଘ'],
+ ['y', 'ୌ'],
+ ['Y', 'ଔ'],
+ ['z', 'ଭ'],
+ ['Z', 'ଙ'],
+ ['`', '।'],
+ ['~', 'ଃ'],
+
+ ]
+ };
+
+ $.ime.register( orOdiScript );
+}( jQuery ) );
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: merged
Gerrit-Change-Id: Ia7301bddb79c1fbce2af7190494bdd7bdd909862
Gerrit-PatchSet: 3
Gerrit-Project: mediawiki/extensions/UniversalLanguageSelector
Gerrit-Branch: master
Gerrit-Owner: Amire80 <[email protected]>
Gerrit-Reviewer: Divec <[email protected]>
Gerrit-Reviewer: Santhosh <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits