Update jquery.ime library

upstream: http://github.com/wikimedia/jquery.ime

changes:
* Support for contenteditable, like the VisualEditor surfaces. This
  support is very minimal now. Because of VE bugs on IME support, many
  things are broken. But one-one keyboard mappings should work with less
  issues. The UI of jquery.ime is not integrated with VE toolbar
* More input methods
	- IPA-X-SAMPA by Amir
	- Armenian keymaps by  Aleksey Chalabyan
	- Kurdish keymaps by Ghybu
	- Кыргыз keymap by Amir
	- Central Kurdish keyboards by Çalak
* A lot of input method bug fixes multiple contributors
* Minor UX fixes

Introduces Rangy library.
A module named rangy is defined in VisualEditor extension with more features of rangy.
Here we need only the core library. This module is loaded dynamically from
client when rangy is undefined. If VE is present rangy will be defined, the module
defined in VE will be used. ie, This get loaded only when VE is not present and
user trying to type in a contenteditable.

Bug: 49569
Bug: 50849
Bug: 50220

Change-Id: Iadad5a4e5972fbd1359847526d28e9dbbe00a7c4
This commit is contained in:
Santhosh Thottingal
2013-08-19 09:54:55 +05:30
committed by Santhosh
parent e13a4e2cb0
commit 8f5be106f5
127 changed files with 5454 additions and 643 deletions

View File

@@ -1,9 +1,12 @@
/*! jquery.ime - v0.1.0+20130722
/*! jquery.ime - v0.1.0+20130819
* https://github.com/wikimedia/jquery.ime
* Copyright (c) 2013 Santhosh Thottingal; Licensed GPL, MIT */
( function ( $ ) {
'use strict';
// rangy is defined in the rangy library
/*global rangy */
/**
* IME Class
* @param {Function} [options.helpHandler] Called for each input method row in the selector
@@ -139,7 +142,8 @@
this.$element.val() || this.$element.text(),
startPos,
this.inputmethod.maxKeyLength
) + c;
);
input += c;
replacement = this.transliterate( input, this.context, altGr );
@@ -169,6 +173,7 @@
replaceText( this.$element, replacement, startPos - input.length + 1, endPos );
e.stopPropagation();
return false;
},
@@ -267,10 +272,17 @@
}
dependency = $.ime.sources[inputmethodId].depends;
if ( dependency ) {
return $.when( this.load( dependency ), this.load( inputmethodId ) );
if ( dependency && !$.ime.inputmethods[dependency] ) {
ime.load( dependency ).done( function () {
ime.load( inputmethodId ).done( function () {
deferred.resolve();
} );
} );
return deferred;
}
debug( 'Loading ' + inputmethodId );
deferred = $.getScript(
ime.options.imePath + $.ime.sources[inputmethodId].source
).done( function () {
@@ -291,6 +303,17 @@
return getCaretPosition( $element );
},
/**
* 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 );
},
/**
* Find the point at which a and b diverge, i.e. the first position
* at which they don't have matching characters.
@@ -394,6 +417,10 @@
newLines,
endRange;
if ( $element.is( '[contenteditable]' ) ) {
return getDivCaretPosition( el );
}
if ( typeof el.selectionStart === 'number' && typeof el.selectionEnd === 'number' ) {
start = el.selectionStart;
end = el.selectionEnd;
@@ -434,40 +461,75 @@
}
}
return [ start, end ];
return [start, end];
}
/**
* Helper function to get an IE TextRange object for an element
*/
function rangeForElementIE( e ) {
if ( e.nodeName.toLowerCase() === 'input' ) {
return e.createTextRange();
} else {
var sel = document.body.createTextRange();
function rangeForElementIE( element ) {
var selection;
sel.moveToElementText( e );
return sel;
if ( element.nodeName.toLowerCase() === 'input' ) {
selection = element.createTextRange();
} else {
selection = document.body.createTextRange();
selection.moveToElementText( element );
}
return selection;
}
function replaceText( $element, replacement, start, end ) {
var element = $element.get( 0 ),
selection,
var selection,
length,
newLines,
scrollTop;
scrollTop,
range,
correction,
textNode,
element = $element.get( 0 );
if ( $element.is( '[contenteditable]' ) ) {
correction = setCaretPosition( $element, {
start: start,
end: end
} );
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
} );
return;
}
if ( typeof element.selectionStart === 'number' && typeof element.selectionEnd === 'number' ) {
// IE9+ and all other browsers
scrollTop = element.scrollTop;
// 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 );
element.value = element.value.substring( 0, start ) +
replacement +
element.value.substring( end, element.value.length );
// restore scroll
element.scrollTop = scrollTop;
// set selection
@@ -492,6 +554,127 @@
}
}
function getDivCaretPosition( element ) {
var charIndex = 0,
start = 0,
end = 0,
foundStart = false,
foundEnd = false,
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 ) {
traverseTextNodes( element, sel.getRangeAt( 0 ) );
}
return [ start, end ];
}
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];
}
/**
* Set the caret position in the div.
* @param {Element} element The content editable div element
*/
function setDivCaretPosition( element, position ) {
var nextCharIndex,
charIndex = 0,
range = rangy.createRange(),
foundStart = false,
foundEnd = false;
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;
}
}
}
}
traverseTextNodes( element );
}
/**
* Find the point at which a and b diverge, i.e. the first position
* at which they don't have matching characters.
@@ -533,12 +716,10 @@
}
}
function arrayKeys( obj ) {
var rv = [];
$.each( obj, function ( key ) {
rv.push( key );
function arrayKeys ( obj ) {
return $.map( obj, function( element, index ) {
return index;
} );
return rv;
}
}( jQuery ) );
@@ -674,6 +855,14 @@
}
} );
// Hide the menu when clicked outside
$( 'html' ).click( $.proxy( this.hide, this ) );
// ... but when clicked on window do not propagate it.
this.$menu.on( 'click', function ( event ) {
event.stopPropagation();
} );
imeselector.$imeSetting.mouseenter( function () {
// We don't want the selector to disappear
// while the user is trying to click it
@@ -1296,11 +1485,11 @@
source: 'rules/as/as-bornona.js'
},
'as-inscript': {
name: 'ইন্‌স্ক্ৰিপ্',
name: 'ইনস্ক্ৰিপ্',
source: 'rules/as/as-inscript.js'
},
'as-inscript2': {
name: 'ইন্‌স্ক্ৰিপ্ ২',
name: 'ইনস্ক্ৰিপ্ ২',
source: 'rules/as/as-inscript2.js'
},
'as-phonetic': {
@@ -1332,11 +1521,11 @@
source: 'rules/bn/bn-avro.js'
},
'bn-inscript': {
name: 'ইন্‌স্ক্ৰিপ্',
name: 'ইনস্ক্ৰিপ্',
source: 'rules/bn/bn-inscript.js'
},
'bn-inscript2': {
name: 'ইন্‌স্ক্ৰিপ্ ২',
name: 'ইনস্ক্ৰিপ্ ২',
source: 'rules/bn/bn-inscript2.js'
},
'bn-nkb': {
@@ -1355,6 +1544,18 @@
name: 'इनस्क्रिप्ट २',
source: 'rules/brx/brx-inscript2.js'
},
'ckb-transliteration-arkbd': {
name: 'باشووری',
source: 'rules/ckb/ckb-transliteration-arkbd.js'
},
'ckb-transliteration-fakbd': {
name: 'ڕۆژھەڵاتی',
source: 'rules/ckb/ckb-transliteration-fakbd.js'
},
'ckb-transliteration-lakbd': {
name: 'لاتینی',
source: 'rules/ckb/ckb-transliteration-lakbd.js'
},
'cv-cyr-altgr': {
name: 'Чăвашла (AltGr)',
source: 'rules/cv/cv-cyr-altgr.js'
@@ -1517,9 +1718,25 @@
name: 'Croatian kbd',
source: 'rules/hr/hr-kbd.js'
},
'hy-kbd': {
name: 'Ստանդարտ ստեղնաշար',
source: 'rules/hy/hy-kbd.js'
'hy-ephonetic': {
name: 'Հնչյունային դասավորություն',
source: 'rules/hy/hy-ephonetic.js'
},
'hy-typewriter': {
name: 'Գրամեքենայի դասավորություն',
source: 'rules/hy/hy-typewriter.js'
},
'hy-ephoneticalt': {
name: 'Հնչյունային նոր (R→Ր, F→Թ)',
source: 'rules/hy/hy-ephoneticalt.js'
},
'hy-emslegacy': {
name: 'Մայքրոսոֆթի հին արևելահայերեն',
source: 'rules/hy/hy-emslegacy.js'
},
'hy-wmslegacy': {
name: 'Մայքրոսոֆթի հին արևմտահայերեն',
source: 'rules/hy/hy-wmslegacy.js'
},
'gu-inscript': {
name: 'ઇનસ્ક્રિપ્ટ',
@@ -1558,7 +1775,7 @@
source: 'rules/kn/kn-inscript.js'
},
'kn-inscript2': {
name: 'ಇನ್ಸ್ಕ್ರಿಪ್ಟ್ ೨',
name: 'ಇನ್\u200cಸ್ಕ್ರಿಪ್ಟ್ ೨',
source: 'rules/kn/kn-inscript2.js'
},
'kn-transliteration': {
@@ -1569,6 +1786,10 @@
name: 'KGP/Nudi/KP Rao',
source: 'rules/kn/kn-kgp.js'
},
'ky-cyrl-alt': {
name: 'Кыргыз Alt',
source: 'rules/ky/ky-cyrl-alt.js'
},
'gom-inscript2': {
name: 'इनस्क्रिप्ट २',
source: 'rules/gom/gom-inscript2.js'
@@ -1581,6 +1802,14 @@
name: 'Kashmiri Arabic',
source: 'rules/ks/ks-kbd.js'
},
'ku-h': {
name: 'Ku h',
source: 'rules/ku/ku-h.js'
},
'ku-tr': {
name: 'Ku tr',
source: 'rules/ku/ku-tr.js'
},
'lo-kbd': {
name: 'າຶກ',
source: 'rules/lo/lo-kbd.js'
@@ -1594,7 +1823,7 @@
source: 'rules/mn/mn-cyrl.js'
},
'mni-inscript2': {
name: 'ইন্‌স্ক্ৰিপ্ ২',
name: 'ইনস্ক্ৰিপ্ ২',
source: 'rules/mni/mni-inscript2.js'
},
'mr-inscript': {
@@ -1613,10 +1842,6 @@
name: 'फोनेटिक',
source: 'rules/mr/mr-phonetic.js'
},
'my-kbd': {
name: 'မြန်မာဘာသာ kbd',
source: 'rules/my/my-kbd.js'
},
'my-xkb': {
name: 'မြန်မာဘာသာ xkb',
source: 'rules/my/my-xkb.js'
@@ -1641,16 +1866,20 @@
name: 'Traditional',
source: 'rules/ne/ne-trad.js'
},
'no-normforms': {
'nb-normforms': {
name: 'Normal transliterasjon',
source: 'rules/no/no-normforms.js'
source: 'rules/nb/nb-normforms.js'
},
'no-tildeforms': {
'nb-tildeforms': {
name: 'Tildemerket transliterasjon',
source: 'rules/no/no-tildeforms.js'
source: 'rules/nb/nb-tildeforms.js'
},
'nn-tildeforms': {
name: 'Tildemerkt transliterasjon',
source: 'rules/nb/nb-tildeforms.js'
},
'or-transliteration': {
name: 'ଟ୍ରାନ୍ସଲି ଟରେସନ',
name: 'ଟ୍ରାନ୍ସଲିଟରେସନ',
source: 'rules/or/or-transliteration.js'
},
'or-inscript': {
@@ -1686,11 +1915,11 @@
source: 'rules/sr/sr-kbd.js'
},
'te-inscript': {
name: 'ఇన్స్క్రిప్ట్',
name: 'ఇన్\u200dస్క్రిప్ట్',
source: 'rules/te/te-inscript.js'
},
'te-inscript2': {
name: 'ఇన్స్క్రిప్ట్ 2',
name: 'ఇన్\u200dస్క్రిప్ట్ 2',
source: 'rules/te/te-inscript2.js'
},
'te-transliteration': {
@@ -1777,6 +2006,10 @@
name: 'International Phonetic Alphabet - SIL',
source: 'rules/fonipa/ipa-sil.js'
},
'ipa-x-sampa': {
name: 'International Phonetic Alphabet - X-SAMPA',
source: 'rules/fonipa/ipa-x-sampa.js'
},
'udm-alt': {
name: 'Удмурт ALT',
source: 'rules/udm/udm-alt.js'
@@ -1844,6 +2077,10 @@
autonym: 'बोड़ो',
inputmethods: [ 'brx-inscript', 'brx-inscript2' ]
},
'ckb': {
autonym: 'کوردی',
inputmethods: [ 'ckb-transliteration-arkbd', 'ckb-transliteration-fakbd', 'ckb-transliteration-lakbd' ]
},
'ce': {
autonym: 'нохчийн',
inputmethods: [ 'cyrl-palochka' ]
@@ -1860,13 +2097,17 @@
autonym: 'Deutsch',
inputmethods: [ 'de-transliteration' ]
},
'diq': {
autonym: 'Kirdkî',
inputmethods: [ 'ku-h', 'ku-tr' ]
},
'doi': {
autonym: 'डोगरी',
inputmethods: [ 'doi-inscript2' ]
},
'en': {
autonym: 'English',
inputmethods: [ 'ipa-sil' ]
inputmethods: [ 'ipa-sil', 'ipa-x-sampa' ]
},
'el': {
autonym: 'Ελληνικά',
@@ -1905,8 +2146,8 @@
inputmethods: [ 'hr-kbd' ]
},
'hy': {
autonym: 'Հայերեն',
inputmethods: [ 'hy-kbd' ]
autonym: 'հայերեն',
inputmethods: [ 'hy-ephonetic', 'hy-typewriter', 'hy-ephoneticalt', 'hy-emslegacy', 'hy-wmslegacy' ]
},
'hne': {
autonym: 'छत्तीसगढ़ी',
@@ -1918,7 +2159,7 @@
},
'fonipa': {
autonym: 'International Phonetic Alphabet',
inputmethods: [ 'ipa-sil' ]
inputmethods: [ 'ipa-sil', 'ipa-x-sampa' ]
},
'jv': {
autonym: 'ꦧꦱꦗꦮ',
@@ -1944,10 +2185,18 @@
autonym: 'कॉशुर / کٲشُر',
inputmethods: [ 'ks-inscript', 'ks-kbd' ]
},
'ky': {
autonym: 'Кыргыз',
inputmethods: [ 'ky-cyrl-alt' ]
},
'kab': {
autonym: 'ⵜⴰⵇⴱⴰⵢⵍⵉⵜ',
inputmethods: [ 'ber-tfng' ]
},
'ku': {
autonym: 'Kurdî',
inputmethods: [ 'ku-h', 'ku-tr' ]
},
'lbe': {
autonym: 'лакку',
inputmethods: [ 'cyrl-palochka' ]
@@ -1986,7 +2235,7 @@
},
'my': {
autonym: 'မြန်မာ',
inputmethods: [ 'my-kbd', 'my-xkb' ]
inputmethods: [ 'my-xkb' ]
},
'ne': {
autonym: 'नेपाली',
@@ -1996,17 +2245,13 @@
autonym: 'नेपाल भाषा',
inputmethods: [ 'hi-transliteration', 'hi-inscript' ]
},
'no': {
autonym: 'Norsk',
inputmethods: [ 'no-normforms', 'no-tildeforms' ]
},
'nb': {
autonym: 'Norsk (bokmål)',
inputmethods: [ 'no-normforms', 'no-tildeforms' ]
inputmethods: [ 'nb-normforms', 'nb-tildeforms' ]
},
'nn': {
autonym: 'Norsk (nynorsk)',
inputmethods: [ 'no-normforms', 'no-tildeforms' ]
inputmethods: [ 'nb-normforms', 'nn-tildeforms' ]
},
'or': {
autonym: 'ଓଡ଼ିଆ',