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
This commit is contained in:
Amire80
2016-01-22 19:06:49 +02:00
parent b57814167d
commit 4cbb2ca88a
7 changed files with 653 additions and 370 deletions

View File

@@ -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,
@@ -456,10 +550,6 @@
newLines,
endRange;
if ( $element.is( '[contenteditable]' ) ) {
return getDivCaretPosition( el );
}
if ( typeof el.selectionStart === 'number' && typeof el.selectionEnd === 'number' ) {
start = el.selectionStart;
end = el.selectionEnd;
@@ -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;
}
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
} );
/**
* @inheritdoc SelectionWrapper
*/
ContentEditableEntry.prototype.replaceTextAtSelection = function ( precedingCharCount, newText ) {
var range, textNode, textOffset, newOffset, newRange;
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;
}
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 = $this.data( 'ime' );
if ( !data ) {
textEntry = TextEntryFactory.static.singleton.wrap( $this );
if ( textEntry === undefined ) {
return;
}
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'
@@ -2015,6 +2034,10 @@
name: 'ଟ୍ରାନ୍ସଲିଟରେସନ',
source: 'rules/or/or-transliteration.js'
},
'or-OdiScript': {
name: 'ଓଡ଼ିସ୍କ୍ରିପ୍ଟ',
source: 'rules/or/or-OdiScript.js'
},
'or-inscript': {
name: 'ଇନସ୍କ୍ରିପ୍ଟ',
source: 'rules/or/or-inscript.js'
@@ -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: 'ਪੰਜਾਬੀ',

View File

@@ -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 ) );

View File

@@ -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 ) );

View File

@@ -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

View File

@@ -17,7 +17,7 @@
['3', '٣'],
['4', '٤'],
['5', '٥'],
['6', '٦'],
['6', '۶'],
['7', '٧'],
['8', '٨'],
['9', '٩'],

View File

@@ -11,7 +11,7 @@
license: 'GPLv3',
version: '1.0',
contextLength: 5,
maxKeyLength: 2,
maxKeyLength: 5,
patterns: [
//['ඬ්හ්a', 'ඳ'], // nndha
['ඬ්h', 'ඳ්'], // nndh

View File

@@ -16,7 +16,7 @@
// Combining grave tone mark
['\\\\', '\u0340'],
// Combining acute tone mark
["/", '\u0341']
['/', '\u0341']
]
};