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:
@@ -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: 'ਪੰਜਾਬੀ',
|
||||
|
||||
147
lib/jquery.ime/rules/as/as-rodali.js
Normal file
147
lib/jquery.ime/rules/as/as-rodali.js
Normal 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 ) );
|
||||
116
lib/jquery.ime/rules/or/or-OdiScript.js
Normal file
116
lib/jquery.ime/rules/or/or-OdiScript.js
Normal 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 ) );
|
||||
@@ -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
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
['3', '٣'],
|
||||
['4', '٤'],
|
||||
['5', '٥'],
|
||||
['6', '٦'],
|
||||
['6', '۶'],
|
||||
['7', '٧'],
|
||||
['8', '٨'],
|
||||
['9', '٩'],
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
license: 'GPLv3',
|
||||
version: '1.0',
|
||||
contextLength: 5,
|
||||
maxKeyLength: 2,
|
||||
maxKeyLength: 5,
|
||||
patterns: [
|
||||
//['ඬ්හ්a', 'ඳ'], // nndha
|
||||
['ඬ්h', 'ඳ්'], // nndh
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// Combining grave tone mark
|
||||
['\\\\', '\u0340'],
|
||||
// Combining acute tone mark
|
||||
["/", '\u0341']
|
||||
['/', '\u0341']
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user