From 8f5be106f508615c3536bbdf1bcbc7d4720d2651 Mon Sep 17 00:00:00 2001 From: Santhosh Thottingal Date: Mon, 19 Aug 2013 09:54:55 +0530 Subject: [PATCH] Update jquery.ime library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- Resources.php | 9 + lib/jquery.ime/css/jquery.ime.css | 2 +- lib/jquery.ime/jquery.ime.js | 351 +- lib/jquery.ime/rules/am/am-transliteration.js | 1 - lib/jquery.ime/rules/ar/ar-kbd.js | 9 +- lib/jquery.ime/rules/as/as-avro.js | 2 +- lib/jquery.ime/rules/as/as-bornona.js | 2 +- lib/jquery.ime/rules/as/as-inscript.js | 4 +- lib/jquery.ime/rules/as/as-inscript2.js | 6 +- lib/jquery.ime/rules/as/as-phonetic.js | 5 +- lib/jquery.ime/rules/as/as-transliteration.js | 2 +- lib/jquery.ime/rules/be/be-latin.js | 1 - lib/jquery.ime/rules/be/be-transliteration.js | 3 +- lib/jquery.ime/rules/bn/bn-avro.js | 2 +- lib/jquery.ime/rules/bn/bn-inscript.js | 4 +- lib/jquery.ime/rules/bn/bn-inscript2.js | 6 +- lib/jquery.ime/rules/bn/bn-nkb.js | 2 +- lib/jquery.ime/rules/bn/bn-probhat.js | 2 +- lib/jquery.ime/rules/brx/brx-inscript.js | 2 +- lib/jquery.ime/rules/brx/brx-inscript2.js | 2 +- .../rules/ckb/ckb-transliteration-arkbd.js | 103 + .../rules/ckb/ckb-transliteration-fakbd.js | 104 + .../rules/ckb/ckb-transliteration-lakbd.js | 100 + lib/jquery.ime/rules/cv/cv-cyr-numbers.js | 1 - lib/jquery.ime/rules/cv/cv-lat-altgr.js | 1 - lib/jquery.ime/rules/cyrl/cyrl-palochka.js | 1 - lib/jquery.ime/rules/da/da-normforms.js | 3 +- lib/jquery.ime/rules/de/de-transliteration.js | 1 - lib/jquery.ime/rules/doi/doi-inscript2.js | 2 +- lib/jquery.ime/rules/el/el-kbd.js | 1 - lib/jquery.ime/rules/eo/eo-h-f.js | 1 - lib/jquery.ime/rules/eo/eo-h.js | 1 - lib/jquery.ime/rules/eo/eo-q.js | 1 - lib/jquery.ime/rules/eo/eo-transliteration.js | 2 +- lib/jquery.ime/rules/eo/eo-vi.js | 1 - lib/jquery.ime/rules/eo/eo-x.js | 1 - lib/jquery.ime/rules/fi/fi-transliteration.js | 2 +- lib/jquery.ime/rules/fo/fo-normforms.js | 1 - lib/jquery.ime/rules/fonipa/ipa-sil.js | 8 +- lib/jquery.ime/rules/fonipa/ipa-x-sampa.js | 189 + lib/jquery.ime/rules/gu/gu-inscript.js | 2 +- lib/jquery.ime/rules/gu/gu-inscript2.js | 10 +- lib/jquery.ime/rules/gu/gu-phonetic.js | 4 +- lib/jquery.ime/rules/gu/gu-transliteration.js | 3 +- .../rules/he/he-standard-2012-extonly.js | 1 - lib/jquery.ime/rules/hi/hi-bolnagri.js | 1 - lib/jquery.ime/rules/hi/hi-inscript.js | 2 +- lib/jquery.ime/rules/hi/hi-inscript2.js | 2 +- lib/jquery.ime/rules/hi/hi-phonetic.js | 6 +- lib/jquery.ime/rules/hi/hi-transliteration.js | 2 +- lib/jquery.ime/rules/hr/hr-kbd.js | 1 - lib/jquery.ime/rules/hy/hy-emslegacy.js | 169 + lib/jquery.ime/rules/hy/hy-ephonetic.js | 172 + lib/jquery.ime/rules/hy/hy-ephoneticalt.js | 172 + lib/jquery.ime/rules/hy/hy-kbd.js | 113 - lib/jquery.ime/rules/hy/hy-typewriter.js | 168 + lib/jquery.ime/rules/hy/hy-wmslegacy.js | 169 + lib/jquery.ime/rules/jv/jv-transliteration.js | 418 ++- lib/jquery.ime/rules/ka/ka-kbd.js | 3 +- lib/jquery.ime/rules/ka/ka-transliteration.js | 4 +- lib/jquery.ime/rules/kk/kk-arabic.js | 3 +- lib/jquery.ime/rules/kk/kk-kbd.js | 3 +- lib/jquery.ime/rules/kn/kn-inscript.js | 4 +- lib/jquery.ime/rules/kn/kn-inscript2.js | 7 +- lib/jquery.ime/rules/kn/kn-kgp.js | 201 +- lib/jquery.ime/rules/kn/kn-transliteration.js | 5 +- lib/jquery.ime/rules/ks/ks-inscript.js | 3 +- lib/jquery.ime/rules/ks/ks-kbd.js | 3 +- lib/jquery.ime/rules/ku/ku-h.js | 48 + lib/jquery.ime/rules/ku/ku-tr.js | 33 + lib/jquery.ime/rules/ky/ky-cyrl-alt.js | 25 + lib/jquery.ime/rules/lo/lo-kbd.js | 1 - lib/jquery.ime/rules/mai/mai-inscript.js | 1 - lib/jquery.ime/rules/mai/mai-inscript2.js | 1 - lib/jquery.ime/rules/mh/mh.js | 1 - lib/jquery.ime/rules/ml/ml-inscript.js | 1 - lib/jquery.ime/rules/ml/ml-inscript2.js | 4 +- lib/jquery.ime/rules/ml/ml-transliteration.js | 2 +- lib/jquery.ime/rules/mn/mn-cyrl.js | 1 - lib/jquery.ime/rules/mni/mni-inscript2.js | 7 +- lib/jquery.ime/rules/mr/mr-inscript.js | 2 +- lib/jquery.ime/rules/mr/mr-inscript2.js | 2 +- lib/jquery.ime/rules/mr/mr-phonetic.js | 8 +- lib/jquery.ime/rules/mr/mr-transliteration.js | 3 +- lib/jquery.ime/rules/my/my-xkb.js | 2 +- .../no-normforms.js => nb/nb-normforms.js} | 5 +- .../no-tildeforms.js => nb/nb-tildeforms.js} | 5 +- lib/jquery.ime/rules/ne/ne-inscript.js | 2 +- lib/jquery.ime/rules/ne/ne-inscript2.js | 2 +- lib/jquery.ime/rules/ne/ne-rom.js | 1 - lib/jquery.ime/rules/ne/ne-trad.js | 2 +- lib/jquery.ime/rules/ne/ne-transliteration.js | 3 +- lib/jquery.ime/rules/or/or-inscript.js | 1 - lib/jquery.ime/rules/or/or-inscript2.js | 5 +- lib/jquery.ime/rules/or/or-lekhani.js | 2 - lib/jquery.ime/rules/or/or-phonetic.js | 1 - lib/jquery.ime/rules/or/or-transliteration.js | 4 +- lib/jquery.ime/rules/pa/pa-inscript.js | 2 +- lib/jquery.ime/rules/pa/pa-inscript2.js | 6 +- lib/jquery.ime/rules/pa/pa-phonetic.js | 3 +- lib/jquery.ime/rules/pa/pa-transliteration.js | 3 +- lib/jquery.ime/rules/ru/ru-jcuken.js | 2 +- lib/jquery.ime/rules/ru/ru-kbd.js | 2 +- lib/jquery.ime/rules/ru/ru-phonetic.js | 3 +- lib/jquery.ime/rules/ru/ru-yawerty.js | 3 +- lib/jquery.ime/rules/sa/sa-iast.js | 2 +- lib/jquery.ime/rules/sa/sa-inscript.js | 2 +- lib/jquery.ime/rules/sa/sa-transliteration.js | 3 +- .../rules/sah/sah-transliteration.js | 3 +- lib/jquery.ime/rules/si/si-singlish.js | 3 +- lib/jquery.ime/rules/si/si-wijesekara.js | 3 +- lib/jquery.ime/rules/sk/sk-kbd.js | 3 +- lib/jquery.ime/rules/sv/sv-normforms.js | 3 +- lib/jquery.ime/rules/ta/ta-99.js | 1 - lib/jquery.ime/rules/ta/ta-bamini.js | 1 - lib/jquery.ime/rules/ta/ta-inscript.js | 1 - lib/jquery.ime/rules/ta/ta-inscript2.js | 4 +- lib/jquery.ime/rules/ta/ta-transliteration.js | 1 - lib/jquery.ime/rules/te/te-inscript.js | 3 +- lib/jquery.ime/rules/te/te-inscript2.js | 6 +- lib/jquery.ime/rules/te/te-transliteration.js | 2 - lib/jquery.ime/rules/udm/udm-alt.js | 1 - lib/jquery.ime/rules/ug/ug-kbd.js | 2 - lib/jquery.ime/rules/ur/ur-phonetic.js | 24 +- lib/jquery.ime/rules/ur/ur-transliteration.js | 2 - lib/rangy/rangy-core.js | 3224 +++++++++++++++++ resources/js/ext.uls.ime.js | 12 +- 127 files changed, 5454 insertions(+), 643 deletions(-) create mode 100644 lib/jquery.ime/rules/ckb/ckb-transliteration-arkbd.js create mode 100644 lib/jquery.ime/rules/ckb/ckb-transliteration-fakbd.js create mode 100644 lib/jquery.ime/rules/ckb/ckb-transliteration-lakbd.js create mode 100644 lib/jquery.ime/rules/fonipa/ipa-x-sampa.js create mode 100644 lib/jquery.ime/rules/hy/hy-emslegacy.js create mode 100644 lib/jquery.ime/rules/hy/hy-ephonetic.js create mode 100644 lib/jquery.ime/rules/hy/hy-ephoneticalt.js delete mode 100644 lib/jquery.ime/rules/hy/hy-kbd.js create mode 100644 lib/jquery.ime/rules/hy/hy-typewriter.js create mode 100644 lib/jquery.ime/rules/hy/hy-wmslegacy.js create mode 100644 lib/jquery.ime/rules/ku/ku-h.js create mode 100644 lib/jquery.ime/rules/ku/ku-tr.js create mode 100644 lib/jquery.ime/rules/ky/ky-cyrl-alt.js rename lib/jquery.ime/rules/{no/no-normforms.js => nb/nb-normforms.js} (95%) rename lib/jquery.ime/rules/{no/no-tildeforms.js => nb/nb-tildeforms.js} (95%) create mode 100644 lib/rangy/rangy-core.js diff --git a/Resources.php b/Resources.php index c80b22ab..02a674b9 100644 --- a/Resources.php +++ b/Resources.php @@ -203,3 +203,12 @@ $wgResourceModules['jquery.uls.grid'] = array( $wgResourceModules['jquery.webfonts'] = array( 'scripts' => 'lib/jquery.webfonts.js', ) + $resourcePaths; + +// A module named rangy is defined in VisualExtension 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 +$wgResourceModules['rangy.core'] = array( + 'scripts' => 'lib/rangy/rangy-core.js', +) + $resourcePaths; diff --git a/lib/jquery.ime/css/jquery.ime.css b/lib/jquery.ime/css/jquery.ime.css index 5894f0fd..177a4d9b 100644 --- a/lib/jquery.ime/css/jquery.ime.css +++ b/lib/jquery.ime/css/jquery.ime.css @@ -15,7 +15,7 @@ text-align: left; font-family: sans-serif; white-space: nowrap; - z-index: 9999; + z-index: 1000; } .imeselector:hover { diff --git a/lib/jquery.ime/jquery.ime.js b/lib/jquery.ime/jquery.ime.js index 8bb1ff9e..fbe5dd8e 100644 --- a/lib/jquery.ime/jquery.ime.js +++ b/lib/jquery.ime/jquery.ime.js @@ -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: 'ଓଡ଼ିଆ', diff --git a/lib/jquery.ime/rules/am/am-transliteration.js b/lib/jquery.ime/rules/am/am-transliteration.js index 93e6dc3d..511bcfec 100644 --- a/lib/jquery.ime/rules/am/am-transliteration.js +++ b/lib/jquery.ime/rules/am/am-transliteration.js @@ -429,5 +429,4 @@ }; $.ime.register( amTransliteration ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ar/ar-kbd.js b/lib/jquery.ime/rules/ar/ar-kbd.js index a1471a36..6ca5ccd1 100644 --- a/lib/jquery.ime/rules/ar/ar-kbd.js +++ b/lib/jquery.ime/rules/ar/ar-kbd.js @@ -102,15 +102,14 @@ ['\\.', '<'], ['\\[', ']'], ['\\]', '['], - ['J', '‍'], - ['L', '‎'], - ['N', '‌'], - ['R', '‏'], + ['J', '\u200d'], + ['L', '\u200e'], + ['N', '\u200c'], + ['R', '\u200f'], ['\\{', '}'], ['\\}', '{'] ] }; $.ime.register( arKbd ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/as/as-avro.js b/lib/jquery.ime/rules/as/as-avro.js index 4120cac4..3fd422b3 100644 --- a/lib/jquery.ime/rules/as/as-avro.js +++ b/lib/jquery.ime/rules/as/as-avro.js @@ -163,6 +163,6 @@ ['ঃ`', ':'], ['`', '']] }; - $.ime.register( asAvro ); + $.ime.register( asAvro ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/as/as-bornona.js b/lib/jquery.ime/rules/as/as-bornona.js index f9960ebc..6daa8d3a 100644 --- a/lib/jquery.ime/rules/as/as-bornona.js +++ b/lib/jquery.ime/rules/as/as-bornona.js @@ -79,6 +79,6 @@ ['9', '৯'], ['\\`', '\u200C']] }; - $.ime.register( asBornona ); + $.ime.register( asBornona ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/as/as-inscript.js b/lib/jquery.ime/rules/as/as-inscript.js index 504f061d..e2491f4e 100644 --- a/lib/jquery.ime/rules/as/as-inscript.js +++ b/lib/jquery.ime/rules/as/as-inscript.js @@ -3,7 +3,7 @@ var asInScript = { id: 'as-inscript', - name: 'ইন্‌স্ক্ৰিপ্ত', + name: 'ইনস্ক্ৰিপ্ট', description: 'InScript input method for Assamese according to CDAC\'s Enhanced InScript Keyboard Layout 5.2', date: '2012-10-10', URL: 'http://github.com/wikimedia/jquery.ime', @@ -119,6 +119,6 @@ ['4', '₹']] }; - $.ime.register( asInScript ); + $.ime.register( asInScript ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/as/as-inscript2.js b/lib/jquery.ime/rules/as/as-inscript2.js index 2c248ff8..e7da7dd8 100644 --- a/lib/jquery.ime/rules/as/as-inscript2.js +++ b/lib/jquery.ime/rules/as/as-inscript2.js @@ -3,7 +3,7 @@ var asInScript2 = { id: 'as-inscript2', - name: 'ইন্‌স্ক্ৰিপ্ত ২', + name: 'ইনস্ক্ৰিপ্ট ২', description: 'Enhanced InScript keyboard for Assamese language', date: '2013-02-09', URL: 'http://github.com/wikimedia/jquery.ime', @@ -98,9 +98,9 @@ ], patterns_x: [ ['\\!', '৴'], - ['1', '‍'], + ['1', '\u200d'], ['\\@', '৵'], - ['2', '‌'], + ['2', '\u200c'], ['\\#', '৶'], ['\\$', '৷'], ['4', '₹'], diff --git a/lib/jquery.ime/rules/as/as-phonetic.js b/lib/jquery.ime/rules/as/as-phonetic.js index c1065238..b877c430 100644 --- a/lib/jquery.ime/rules/as/as-phonetic.js +++ b/lib/jquery.ime/rules/as/as-phonetic.js @@ -83,8 +83,8 @@ ['\'', '\''], ['\\|', '৺'], ['\\\\', 'ৱ'], - ['\\~', '‌'], - ['\\`', '‍'], + ['\\~', '\u200c'], + ['\\`', '\u200d'], ['Z', 'য'], ['z', 'য়'], ['X', 'ঢ়'], @@ -109,5 +109,4 @@ }; $.ime.register( asPhonetic ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/as/as-transliteration.js b/lib/jquery.ime/rules/as/as-transliteration.js index 77e495f1..379005a5 100644 --- a/lib/jquery.ime/rules/as/as-transliteration.js +++ b/lib/jquery.ime/rules/as/as-transliteration.js @@ -109,6 +109,6 @@ ['(\u200C)*_', '\u200C'], ['(\u200D)*`', '\u200D']] }; - $.ime.register( asTransliteration ); + $.ime.register( asTransliteration ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/be/be-latin.js b/lib/jquery.ime/rules/be/be-latin.js index e6631696..ca6c9954 100644 --- a/lib/jquery.ime/rules/be/be-latin.js +++ b/lib/jquery.ime/rules/be/be-latin.js @@ -35,5 +35,4 @@ }; $.ime.register( beLatin ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/be/be-transliteration.js b/lib/jquery.ime/rules/be/be-transliteration.js index 6fc66731..c8d29de1 100644 --- a/lib/jquery.ime/rules/be/be-transliteration.js +++ b/lib/jquery.ime/rules/be/be-transliteration.js @@ -81,7 +81,6 @@ ['\\.', 'ю'], ['/', '.'], - ['@', '"'], // 2 ['#', '№'], // 3 ['\\$', ';'], // 4 @@ -90,6 +89,6 @@ ['&', '?']] // 7 // '*', '(' and ')' are the same // 8, 9, 0 }; - $.ime.register( beTransliteration ); + $.ime.register( beTransliteration ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/bn/bn-avro.js b/lib/jquery.ime/rules/bn/bn-avro.js index 58079fe3..af16cd21 100644 --- a/lib/jquery.ime/rules/bn/bn-avro.js +++ b/lib/jquery.ime/rules/bn/bn-avro.js @@ -189,6 +189,6 @@ ['ঃ`', ':'], ['`', '']] }; - $.ime.register( bnAvro ); + $.ime.register( bnAvro ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/bn/bn-inscript.js b/lib/jquery.ime/rules/bn/bn-inscript.js index cf57525a..f26a97a0 100644 --- a/lib/jquery.ime/rules/bn/bn-inscript.js +++ b/lib/jquery.ime/rules/bn/bn-inscript.js @@ -3,7 +3,7 @@ var bnInScript = { id: 'bn-inscript', - name: 'ইন্সক্রিপ্ট', + name: 'ইনস্ক্ৰিপ্ট', description: 'Bengali InScript input method', date: '2012-10-10', URL: 'http://github.com/wikimedia/jquery.ime', @@ -118,6 +118,6 @@ ['\\?', '৻'], ['4', '₹']] }; - $.ime.register( bnInScript ); + $.ime.register( bnInScript ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/bn/bn-inscript2.js b/lib/jquery.ime/rules/bn/bn-inscript2.js index 671adcf3..3ea9e284 100644 --- a/lib/jquery.ime/rules/bn/bn-inscript2.js +++ b/lib/jquery.ime/rules/bn/bn-inscript2.js @@ -3,7 +3,7 @@ var bnInScript2 = { id: 'bn-inscript2', - name: 'ইন্‌স্ক্ৰিপ্ত ২', + name: 'ইনস্ক্ৰিপ্ট ২', description: 'Enhanced InScript keyboard for Bengali language', date: '2013-02-09', URL: 'http://github.com/wikimedia/jquery.ime', @@ -97,9 +97,9 @@ ], patterns_x: [ ['\\!', '৴'], - ['1', '‍'], + ['1', '\u200d'], ['\\@', '৵'], - ['2', '‌'], + ['2', '\u200c'], ['\\#', '৶'], ['\\$', '৷'], ['4', '₹'], diff --git a/lib/jquery.ime/rules/bn/bn-nkb.js b/lib/jquery.ime/rules/bn/bn-nkb.js index 34418e83..7a35a214 100644 --- a/lib/jquery.ime/rules/bn/bn-nkb.js +++ b/lib/jquery.ime/rules/bn/bn-nkb.js @@ -128,6 +128,6 @@ ['X', 'ঔ'], ['C', 'ঐ']] }; - $.ime.register( bnNkb ); + $.ime.register( bnNkb ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/bn/bn-probhat.js b/lib/jquery.ime/rules/bn/bn-probhat.js index 5938c138..27d56b36 100644 --- a/lib/jquery.ime/rules/bn/bn-probhat.js +++ b/lib/jquery.ime/rules/bn/bn-probhat.js @@ -97,6 +97,6 @@ ['>', 'ঁ'], ['\\\\', '\u200C']] }; - $.ime.register( bnProbhat ); + $.ime.register( bnProbhat ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/brx/brx-inscript.js b/lib/jquery.ime/rules/brx/brx-inscript.js index 4427a600..e706d191 100644 --- a/lib/jquery.ime/rules/brx/brx-inscript.js +++ b/lib/jquery.ime/rules/brx/brx-inscript.js @@ -107,6 +107,6 @@ [',', '\u0970'], ['\\$', '\u20B9']] }; - $.ime.register( brxInscript ); + $.ime.register( brxInscript ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/brx/brx-inscript2.js b/lib/jquery.ime/rules/brx/brx-inscript2.js index f5be43fc..14bb0ff0 100644 --- a/lib/jquery.ime/rules/brx/brx-inscript2.js +++ b/lib/jquery.ime/rules/brx/brx-inscript2.js @@ -112,6 +112,6 @@ ['\\>', 'ऽ'], ['\\.', '॥']] }; - $.ime.register( brxInScript2 ); + $.ime.register( brxInScript2 ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ckb/ckb-transliteration-arkbd.js b/lib/jquery.ime/rules/ckb/ckb-transliteration-arkbd.js new file mode 100644 index 00000000..b53a28ec --- /dev/null +++ b/lib/jquery.ime/rules/ckb/ckb-transliteration-arkbd.js @@ -0,0 +1,103 @@ +( function ( $ ) { + 'use strict'; + + var ckbTransliterationArkbd = { + id: 'ckb-transliteration-arkbd', + name: 'باشووری', + description: 'Central Kurdish keyboard based on Arabic keyboard', + date: '2013-07-06', + URL: 'http://github.com/wikimedia/jquery.ime', + author: 'Çalak', + license: 'GPLv3', + version: '1.0', + patterns: [ + ['`', 'ژ'], + ['1', '١'], + ['2', '٢'], + ['3', '٣'], + ['4', '٤'], + ['5', '٥'], + ['6', '٦'], + ['7', '٧'], + ['8', '٨'], + ['9', '٩'], + ['0', '٠'], + + ['q', 'چ'], + ['w', 'ص'], + ['e', 'پ'], + ['r', 'ق'], + ['t', 'ف'], + ['y', 'غ'], + ['u', 'ع'], + ['i', 'ھ'], + ['o', 'خ'], + ['p', 'ح'], + ['\\[', 'ج'], + ['\\]', 'د'], + + ['a', 'ش'], + ['s', 'س'], + ['d', 'ی'], + ['f', 'ب'], + ['g', 'ل'], + ['h', 'ا'], + ['j', 'ت'], + ['k', 'ن'], + ['l', 'م'], + ['\\;', 'ک'], + ['\'', 'گ'], + + ['z', 'ئ'], + ['x', 'ء'], + ['c', 'ۆ'], + ['v', 'ر'], + ['b', 'لا'], + ['n', 'ى'], + ['m', 'ە'], + ['\\,', 'و'], + ['\\.', 'ز'], + + ['\\%', '٪'], + ['\\(', ')'], + ['\\)', '('], + + ['Q', 'ض'], + ['W', '}'], + ['E', 'ث'], + ['R', '{'], + ['T', 'ڤ'], + ['Y', 'إ'], + ['U', 'ۊ'], + ['I', '\''], + ['O', '\"'], + ['P', '؛'], + ['\\{', '>'], + ['\\}', '<'], + + ['A', '['], + ['S', ']'], + ['D', 'ێ'], + ['F', ''], + ['G', 'ڵ'], + ['H', 'أ'], + ['J', 'ـ'], + ['K', '،'], + ['L', '\\'], + ['\"', 'ط'], + + ['Z', 'ڎ'], + ['X', 'وو'], + ['C', 'ؤ'], + ['V', 'ڕ'], + ['B', 'ڵا'], + ['N', 'آ'], + ['M', 'ة'], + ['\\<', '٫'], + ['\\>', '.'], + ['\\?', '؟'] + ] + }; + $.ime.register( ckbTransliterationArkbd ); + +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/ckb/ckb-transliteration-fakbd.js b/lib/jquery.ime/rules/ckb/ckb-transliteration-fakbd.js new file mode 100644 index 00000000..4dcd52af --- /dev/null +++ b/lib/jquery.ime/rules/ckb/ckb-transliteration-fakbd.js @@ -0,0 +1,104 @@ +( function ( $ ) { + 'use strict'; + + var ckbTransliterationFakbd = { + id: 'ckb-transliteration-fakbd', + name: 'ڕۆژھەڵاتی', + description: 'Central Kurdish keyboard based on Persian keyboard', + date: '2013-07-06', + URL: 'http://github.com/wikimedia/jquery.ime', + author: 'Çalak', + license: 'GPLv3', + version: '1.0', + patterns: [ + ['`', 'پ'], + ['1', '١'], + ['2', '٢'], + ['3', '٣'], + ['4', '٤'], + ['5', '٥'], + ['6', '٦'], + ['7', '٧'], + ['8', '٨'], + ['9', '٩'], + ['0', '٠'], + + ['q', 'ڵ'], + ['w', 'ۆ'], + ['e', 'ێ'], + ['r', 'ق'], + ['t', 'ف'], + ['y', 'غ'], + ['u', 'ع'], + ['i', 'ە'], + ['o', 'خ'], + ['p', 'ح'], + ['\\[', 'ج'], + ['\\]', 'چ'], + ['\\\\', 'ژ'], + + ['a', 'ش'], + ['s', 'س'], + ['d', 'ی'], + ['f', 'ب'], + ['g', 'ل'], + ['h', 'ا'], + ['j', 'ت'], + ['k', 'ن'], + ['l', 'م'], + ['\\;', 'ک'], + ['\'', 'گ'], + + ['z', 'ڤ'], + ['x', 'ھ'], + ['c', 'ز'], + ['v', 'ر'], + ['b', 'ڕ'], + ['n', 'د'], + ['m', 'ئ'], + ['\\,', 'و'], + ['\\.', '.'], + ['/', '/'], + + ['\\%', '٪'], + ['\\(', ')'], + ['\\)', '('], + + ['Q', 'ض'], + ['W', 'ص'], + ['E', 'ث'], + ['R', 'ك'], + ['T', '،'], + ['Y', '؛'], + ['U', '\\'], + ['I', ']'], + ['O', '['], + ['P', '\''], + ['\\{', '}'], + ['\\}', '{'], + + ['A', 'ڎ'], + ['S', 'إ'], + ['D', 'ي'], + ['F', 'ة'], + ['G', 'ۀ'], + ['H', 'آ'], + ['J', 'ـ'], + ['K', '»'], + ['L', '«'], + + ['Z', 'ظ'], + ['X', 'ط'], + ['C', 'ژ'], + ['V', 'ؤ'], + ['B', 'ذ'], + ['N', '\u200cأ'], + ['M', 'ء'], + ['\\<', '>'], + ['\\>', '<'], + ['\\?', '؟'] + ] + }; + $.ime.register( ckbTransliterationFakbd ); + +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/ckb/ckb-transliteration-lakbd.js b/lib/jquery.ime/rules/ckb/ckb-transliteration-lakbd.js new file mode 100644 index 00000000..5b0016fa --- /dev/null +++ b/lib/jquery.ime/rules/ckb/ckb-transliteration-lakbd.js @@ -0,0 +1,100 @@ +( function ( $ ) { + 'use strict'; + + var ckbTransliterationLakbd = { + id: 'ckb-transliteration-lakbd', + name: 'لاتینی', + description: 'Central Kurdish keyboard based on Latin keyboard', + date: '2013-07-06', + URL: 'http://github.com/wikimedia/jquery.ime', + author: 'Çalak', + license: 'GPLv3', + version: '1.0', + patterns: [ + ['1', '١'], + ['2', '٢'], + ['3', '٣'], + ['4', '٤'], + ['5', '٥'], + ['6', '٦'], + ['7', '٧'], + ['8', '٨'], + ['9', '٩'], + ['0', '٠'], + + ['q', 'ق'], + ['w', 'و'], + ['e', 'ە'], + ['r', 'ر'], + ['t', 'ت'], + ['y', 'ی'], + ['u', 'ئ'], + ['i', 'ح'], + ['o', 'ۆ'], + ['p', 'پ'], + ['\\[', ']'], + ['\\]', '['], + + ['a', 'ا'], + ['s', 'س'], + ['d', 'د'], + ['f', 'ف'], + ['g', 'گ'], + ['h', 'ھ'], + ['j', 'ژ'], + ['k', 'ک'], + ['l', 'ل'], + ['\\;', '؛'], + + ['z', 'ز'], + ['x', 'خ'], + ['c', 'ج'], + ['v', 'ڤ'], + ['b', 'ب'], + ['n', 'ن'], + ['m', 'م'], + ['\\,', '،'], + ['\\.', '.'], + + ['\\%', '٪'], + ['\\(', ')'], + ['\\)', '('], + + ['Q', 'ڎ'], + ['W', 'وو'], + ['E', 'ێ'], + ['R', 'ڕ'], + ['T', 'ط'], + ['Y', 'ي'], + ['U', 'ء'], + ['I', 'ع'], + ['O', 'ؤ'], + ['P', 'ث'], + ['\\{', '}'], + ['\\}', '{'], + + ['A', 'آ'], + ['S', 'ش'], + ['D', 'ذ'], + ['F', 'إ'], + ['G', 'غ'], + ['H', 'ه'], + ['J', 'أ'], + ['K', 'ك'], + ['L', 'ڵ'], + + ['Z', 'ض'], + ['X', 'ص'], + ['C', 'چ'], + ['V', 'ظ'], + ['B', 'ى'], + ['N', 'ة'], + ['M', 'ـ'], + ['\\<', '>'], + ['\\>', '<'], + ['\\?', '؟'] + ] + }; + $.ime.register( ckbTransliterationLakbd ); + +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/cv/cv-cyr-numbers.js b/lib/jquery.ime/rules/cv/cv-cyr-numbers.js index ba842657..91a57135 100644 --- a/lib/jquery.ime/rules/cv/cv-cyr-numbers.js +++ b/lib/jquery.ime/rules/cv/cv-cyr-numbers.js @@ -109,5 +109,4 @@ }; $.ime.register( cv ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/cv/cv-lat-altgr.js b/lib/jquery.ime/rules/cv/cv-lat-altgr.js index 1ac27a1c..a225293e 100644 --- a/lib/jquery.ime/rules/cv/cv-lat-altgr.js +++ b/lib/jquery.ime/rules/cv/cv-lat-altgr.js @@ -30,5 +30,4 @@ }; $.ime.register( cv ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/cyrl/cyrl-palochka.js b/lib/jquery.ime/rules/cyrl/cyrl-palochka.js index 378ef600..f4e8d8e4 100644 --- a/lib/jquery.ime/rules/cyrl/cyrl-palochka.js +++ b/lib/jquery.ime/rules/cyrl/cyrl-palochka.js @@ -18,7 +18,6 @@ // so it's better to give them names to avoid confusion. var cyrlPalochka; - cyrlPalochka = { id: 'cyrl-palochka', name: 'Cyrillic Palochka', diff --git a/lib/jquery.ime/rules/da/da-normforms.js b/lib/jquery.ime/rules/da/da-normforms.js index e061bd83..382cd0f3 100644 --- a/lib/jquery.ime/rules/da/da-normforms.js +++ b/lib/jquery.ime/rules/da/da-normforms.js @@ -46,5 +46,4 @@ }; $.ime.register( defs ); - -}( jQuery ) ); \ No newline at end of file +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/de/de-transliteration.js b/lib/jquery.ime/rules/de/de-transliteration.js index bf074b85..e85a8822 100644 --- a/lib/jquery.ime/rules/de/de-transliteration.js +++ b/lib/jquery.ime/rules/de/de-transliteration.js @@ -24,5 +24,4 @@ }; $.ime.register( de ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/doi/doi-inscript2.js b/lib/jquery.ime/rules/doi/doi-inscript2.js index bf98e4e4..52f095fa 100644 --- a/lib/jquery.ime/rules/doi/doi-inscript2.js +++ b/lib/jquery.ime/rules/doi/doi-inscript2.js @@ -114,6 +114,6 @@ ['\\>', 'ऽ'], ['\\.', '॥']] }; + $.ime.register( doiInScript2 ); }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/el/el-kbd.js b/lib/jquery.ime/rules/el/el-kbd.js index 48f95701..13d042dc 100644 --- a/lib/jquery.ime/rules/el/el-kbd.js +++ b/lib/jquery.ime/rules/el/el-kbd.js @@ -92,5 +92,4 @@ }; $.ime.register( elKbd ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/eo/eo-h-f.js b/lib/jquery.ime/rules/eo/eo-h-f.js index 92f2bbd1..cecf1ae5 100644 --- a/lib/jquery.ime/rules/eo/eo-h-f.js +++ b/lib/jquery.ime/rules/eo/eo-h-f.js @@ -56,5 +56,4 @@ }; $.ime.register( eoHF ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/eo/eo-h.js b/lib/jquery.ime/rules/eo/eo-h.js index f8de1cac..0fe4b898 100644 --- a/lib/jquery.ime/rules/eo/eo-h.js +++ b/lib/jquery.ime/rules/eo/eo-h.js @@ -51,5 +51,4 @@ }; $.ime.register( eoH ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/eo/eo-q.js b/lib/jquery.ime/rules/eo/eo-q.js index ca6215a8..978cdaaf 100644 --- a/lib/jquery.ime/rules/eo/eo-q.js +++ b/lib/jquery.ime/rules/eo/eo-q.js @@ -52,5 +52,4 @@ }; $.ime.register( eoQ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/eo/eo-transliteration.js b/lib/jquery.ime/rules/eo/eo-transliteration.js index 22c30c33..fa82fd66 100644 --- a/lib/jquery.ime/rules/eo/eo-transliteration.js +++ b/lib/jquery.ime/rules/eo/eo-transliteration.js @@ -2,7 +2,7 @@ 'use strict'; function prepareRules () { - var rules= [], chars; + var rules = [], chars; chars = { C: 'Ĉ', diff --git a/lib/jquery.ime/rules/eo/eo-vi.js b/lib/jquery.ime/rules/eo/eo-vi.js index 44867d23..b1d0586e 100644 --- a/lib/jquery.ime/rules/eo/eo-vi.js +++ b/lib/jquery.ime/rules/eo/eo-vi.js @@ -62,5 +62,4 @@ }; $.ime.register( eoVi ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/eo/eo-x.js b/lib/jquery.ime/rules/eo/eo-x.js index ca7620b1..3d7c96ef 100644 --- a/lib/jquery.ime/rules/eo/eo-x.js +++ b/lib/jquery.ime/rules/eo/eo-x.js @@ -50,5 +50,4 @@ }; $.ime.register( eoX ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/fi/fi-transliteration.js b/lib/jquery.ime/rules/fi/fi-transliteration.js index 9fa30590..15e70448 100644 --- a/lib/jquery.ime/rules/fi/fi-transliteration.js +++ b/lib/jquery.ime/rules/fi/fi-transliteration.js @@ -27,6 +27,6 @@ ['e', '€'] ] }; - $.ime.register( fiTransliteration ); + $.ime.register( fiTransliteration ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/fo/fo-normforms.js b/lib/jquery.ime/rules/fo/fo-normforms.js index b1e5a721..460cb227 100644 --- a/lib/jquery.ime/rules/fo/fo-normforms.js +++ b/lib/jquery.ime/rules/fo/fo-normforms.js @@ -62,5 +62,4 @@ }; $.ime.register( defs ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/fonipa/ipa-sil.js b/lib/jquery.ime/rules/fonipa/ipa-sil.js index 7f479a63..5dde561e 100644 --- a/lib/jquery.ime/rules/fonipa/ipa-sil.js +++ b/lib/jquery.ime/rules/fonipa/ipa-sil.js @@ -185,8 +185,8 @@ ['ʽ\\[', '˞'], // [[[ ['\\[\\[', 'ʽ'], // [[ // Not IPA sanctioned ['(?:\u031a)\\]', '‘'], // ]]]] // Not IPA sanctioned - ['’\\]', '\u031a'], // ]]] // Combining left angle above - ['\\]\\]', '’'], // ]] + ['ʼ\\]', '\u031a'], // ]]] // Combining left angle above + ['\\]\\]', 'ʼ'], // ]] ['(?:\u032f)\\$', '\u0330'], // $$$ // Combining tilde below ['(?:\u0329)\\$', '\u032f'], // $$ // Combining inverted breve below @@ -206,7 +206,7 @@ ['(?:\u033b)\\{', '\u033c'], // {{{{ // Combining seagull below ['(?:\u033a)\\{', '\u033b'], // {{{ // Combining square below ['(?:\u032a)\\{', '\u033a'], // {{ // Combining inverted bridge below - ['\\{', '\u032a'], // { // Combining bridge below + ['\\{', '\u032a'], // { // Combining bridge below ['(?:\u0303)~', '\u0334'], // ~~ // Combining tilde overlay ['~', '\u0303'], // ~ // Combining tilde @@ -235,6 +235,6 @@ ['=<', '\u200d'] // Combining Grapheme Joiner ] }; - $.ime.register( ipaSil ); + $.ime.register( ipaSil ); } ( jQuery ) ); diff --git a/lib/jquery.ime/rules/fonipa/ipa-x-sampa.js b/lib/jquery.ime/rules/fonipa/ipa-x-sampa.js new file mode 100644 index 00000000..546401a5 --- /dev/null +++ b/lib/jquery.ime/rules/fonipa/ipa-x-sampa.js @@ -0,0 +1,189 @@ +( function ( $ ) { + 'use strict'; + + var ipaSil = { + id: 'ipa-x-sampa', + name: 'International Phonetic Alphabet - X-SAMPA', + description: 'International Phonetic Alphabet - X-SAMPA', + date: '2012-11-26', + URL: 'http://www.phon.ucl.ac.uk/home/sampa/x-sampa.htm', + author: 'mapping by John C. Wells; implementation by Amir E. Aharoni', + license: 'GPLv3', + version: '1.0', + contextLength: 0, + maxKeyLength: 4, + patterns: [ + // Tones + ['_/', '\u030C'], // Combining caron + ['_\\\\', '\u0302'], // Combining circumflex accent + ['_ɥ_T', '\u1dc4'], // _H_T - Combining macron-acute + ['_β_L', '\u1dc5'], // _B_L - Combining grave-macron + ['_ʁ_F', '\u1dc8'], // _R_F - Combining grave-acute-grave + + ['β\\\\', 'ʙ'], + ['p\\\\', 'ɸ'], + ['B', 'β'], + + ['F', 'ɱ'], + // ⱱ is not in X-SAMPA + ['P', 'ʋ'], + ['v\\\\', 'ʋ'], + + ['T', 'θ'], + ['D', 'ð'], + + ['4', 'ɾ'], + ['K', 'ɬ'], + ['ɬ\\\\', 'ɮ'], + ['r\\\\', 'ɹ'], + + ['S', 'ʃ'], + ['Z', 'ʒ'], + + ['t`', 'ʈ'], + ['d`', 'ɖ'], + ['n`', 'ɳ'], + ['r`', 'ɽ'], + ['s`', 'ʂ'], + ['z`', 'ʐ'], + ['ɹ`', 'ɻ'], + ['l`', 'ɭ'], + + ['ɲ\\\\', 'ɟ'], + ['J', 'ɲ'], + ['C', 'ç'], + ['j\\\\', 'ʝ'], + ['L', 'ʎ'], + + ['g', 'ɡ'], + ['_N', '\u033c'], // Combining seagull below + ['N', 'ŋ'], + ['_G', 'ˠ'], + ['G', 'ɣ'], + ['ɯ\\\\', 'ɰ'], + ['ʎ\\\\', 'ʟ'], + + ['ɣ\\\\', 'ɢ'], + ['ŋ\\\\', 'ɴ'], + ['ʁ\\\\', 'ʀ'], + ['_X', '\u0306'], // Combining breve + ['X', 'χ'], + ['R', 'ʁ'], + + ['χ\\\\', 'ħ'], + ['_ʔ\\\\', 'ˤ'], + ['ʔ\\\\', 'ʕ'], + + ['\\?', 'ʔ'], + ['h\\\\', 'ɦ'], + + ['ɔ\\\\', 'ʘ'], + ['ǀ\\|\\\\', 'ǁ'], + ['\\|\\\\', 'ǀ'], + ['ꜜ\\\\', 'ǃ'], // !\ -> Retroflex (postalveolar) click + ['_?=', '\u0329'], // Combining vertical line below + ['\u0329\\\\', 'ǂ'], + + ['b_<', 'ɓ'], + ['d_<', 'ɗ'], + ['ɟ_<', 'ʄ'], + ['ɡ_<', 'ɠ'], + ['ɢ_<', 'ʛ'], + + ['W', 'ʍ'], + ['H', 'ɥ'], + ['ɥ\\\\', 'ʜ'], + ['<\\\\', 'ʢ'], + ['>\\\\', 'ʡ'], + + ['s\\\\', 'ɕ'], + ['z\\\\', 'ʑ'], + ['l\\\\', 'ɺ'], + ['x\\\\', 'ɧ'], + + ['I', 'ɪ'], + ['E', 'ɛ'], + ['\\{', 'æ'], + + ['Y', 'ʏ'], + ['2', 'ø'], + ['9', 'œ'], + ['&', 'ɶ'], + + ['1', 'ɨ'], + ['ə\\\\', 'ɘ'], + ['@', 'ə'], + ['ɜ\\\\', 'ɞ'], + ['3', 'ɜ'], + ['6', 'ɐ'], + ['_\\}', '\u031a'], + ['\\}', 'ʉ'], + ['8', 'ɵ'], + + ['M', 'ɯ'], + ['7', 'ɤ'], + ['V', 'ʌ'], + ['_A', '\u0318'], // Combining right tack below + ['A', 'ɑ'], + ['U', 'ʊ'], + ['_O', '\u0339'], // ++++ // Combining right half ring below + ['O', 'ɔ'], + ['Q', 'ɒ'], + + ['%', 'ˌ'], + ['_"', '\u0308'], // Combining diaeresis + ['"', 'ˈ'], + ['ː\\\\', 'ˑ'], + [':', 'ː'], + ['\\.<', '|'], + ['\\|\\|', '‖'], + ['-\\\\', '‿'], + + ['<ʁ>', '↗'], // + ['<ɱ>', '↘'], // + ['!', 'ꜜ'], + ['_\\^', '\u032f'], // Combining inverted breve below + ['\\^', 'ꜛ'], + + // Diacritics and suprasegmentals + ['_h', 'ʰ'], + ['_w', 'ʷ'], + ['_j', 'ʲ'], + // see above for ˠ + // see above for ˤ + ['_n', 'ⁿ'], + ['_l', 'ˡ'], + + ['`', '˞'], + ['_>', 'ʼ'], + // See above for No audible release + // See above for Syllabic + // See above for Non-syllabic + ['_k', '\u0330'], // Combining tilde below + + ['([ɱɮɳɖʐɻɽɭɲɟʝjŋɡɣɰ])_0', '$1\u030a'], // Combining ring above + ['(.)_0', '$1\u0325'], // Combining ring below + ['_v', '\u032c'], // Combining caron below + ['_t', '\u0324'], // Combining diaeresis below + ['_d', '\u032a'], // Combining bridge below + ['_a', '\u033a'], // Combining inverted bridge below + ['_m', '\u033b'], // Combining square below + // See above for linguolabial + ['_?~', '\u0303'], // Combining tilde + ['_e', '\u0334'], // Combining tilde overlay + // See above for centralised + ['_x', '\u033d'], // Combining x above + // See above for extra short + ['_\\+', '\u031f'], // Combining plus sign below + ['_-', '\u0320'], // Combining minus sign below + ['_r', '\u031d'], // Combining up tack below + ['_o', '\u031e'], // Combining down tack below + // See above for advanced tongue root + ['_q', '\u0319'], // Combining left tack below + // See above for more rounded + ['_c', '\u031c'] + ] + }; + + $.ime.register( ipaSil ); +} ( jQuery ) ); diff --git a/lib/jquery.ime/rules/gu/gu-inscript.js b/lib/jquery.ime/rules/gu/gu-inscript.js index c6cf5bd8..75b1bbc1 100644 --- a/lib/jquery.ime/rules/gu/gu-inscript.js +++ b/lib/jquery.ime/rules/gu/gu-inscript.js @@ -108,6 +108,6 @@ ['$', '\u20B9'] ] }; - $.ime.register( guInscript ); + $.ime.register( guInscript ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/gu/gu-inscript2.js b/lib/jquery.ime/rules/gu/gu-inscript2.js index 19dc1f37..cb60e6c1 100644 --- a/lib/jquery.ime/rules/gu/gu-inscript2.js +++ b/lib/jquery.ime/rules/gu/gu-inscript2.js @@ -16,7 +16,7 @@ ['2', '૨'], ['\\#', '્ર'], ['3', '૩'], - ['$', 'ર્'], + ['\\$', 'ર્'], ['4', '૪'], ['5', '૫'], ['6', '૬'], @@ -73,7 +73,7 @@ ['l', 'ત'], [':', 'છ'], [';', 'ચ'], - ['"', 'ઠ'], + ['\"', 'ઠ'], ['\\\'', 'ટ'], ['\\|', 'ઑ'], ['\\', 'ૉ'], @@ -98,8 +98,8 @@ ['\\*', 'શ્ર'] ], patterns_x: [ - ['1', '‍'], - ['2', '‌'], + ['1', '\u200d'], + ['2', '\u200c'], ['4', '₹'], ['\\+', 'ૠ'], ['\\=', 'ૄ'], @@ -113,6 +113,6 @@ ['\\.', 'ઽ'] ] }; - $.ime.register( guInScript2 ); + $.ime.register( guInScript2 ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/gu/gu-phonetic.js b/lib/jquery.ime/rules/gu/gu-phonetic.js index 8e6ecb97..109aeab7 100644 --- a/lib/jquery.ime/rules/gu/gu-phonetic.js +++ b/lib/jquery.ime/rules/gu/gu-phonetic.js @@ -80,7 +80,7 @@ ['"', 'ઊ'], ['\\\'', 'ઉ'], ['\\|', 'ઑ'], - ['\\', 'ૉ'], + ['\\\\', 'ૉ'], ['Z', 'ઁ'], ['z', 'ઙ'], ['x', 'ષ'], @@ -105,6 +105,6 @@ ['\\^', 'ત્ર'], ['\\*', 'શ્ર']] }; - $.ime.register( guPhonetic ); + $.ime.register( guPhonetic ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/gu/gu-transliteration.js b/lib/jquery.ime/rules/gu/gu-transliteration.js index 467d8e4a..3dd489b2 100644 --- a/lib/jquery.ime/rules/gu/gu-transliteration.js +++ b/lib/jquery.ime/rules/gu/gu-transliteration.js @@ -151,7 +151,6 @@ ['J', '઼'], // Nukta ['(\u200C)*`', '\u200C']] // ZWNJ }; + $.ime.register( guTransliteration ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/he/he-standard-2012-extonly.js b/lib/jquery.ime/rules/he/he-standard-2012-extonly.js index 3c368f60..b5397826 100644 --- a/lib/jquery.ime/rules/he/he-standard-2012-extonly.js +++ b/lib/jquery.ime/rules/he/he-standard-2012-extonly.js @@ -63,5 +63,4 @@ }; $.ime.register( heStandardExtOnly ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/hi/hi-bolnagri.js b/lib/jquery.ime/rules/hi/hi-bolnagri.js index 56a5cf6e..7ea921a4 100644 --- a/lib/jquery.ime/rules/hi/hi-bolnagri.js +++ b/lib/jquery.ime/rules/hi/hi-bolnagri.js @@ -105,5 +105,4 @@ }; $.ime.register( hiBolNagri ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/hi/hi-inscript.js b/lib/jquery.ime/rules/hi/hi-inscript.js index 6cd866f9..8138c469 100644 --- a/lib/jquery.ime/rules/hi/hi-inscript.js +++ b/lib/jquery.ime/rules/hi/hi-inscript.js @@ -117,6 +117,6 @@ [ '\\$', '\u20B9' ] ] }; - $.ime.register( hiInScript ); + $.ime.register( hiInScript ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/hi/hi-inscript2.js b/lib/jquery.ime/rules/hi/hi-inscript2.js index 19feaf34..40962d9e 100644 --- a/lib/jquery.ime/rules/hi/hi-inscript2.js +++ b/lib/jquery.ime/rules/hi/hi-inscript2.js @@ -122,6 +122,6 @@ ['\\.', '॥'] ] }; - $.ime.register( hiInScript2 ); + $.ime.register( hiInScript2 ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/hi/hi-phonetic.js b/lib/jquery.ime/rules/hi/hi-phonetic.js index 1d9fd619..b4a97f2e 100644 --- a/lib/jquery.ime/rules/hi/hi-phonetic.js +++ b/lib/jquery.ime/rules/hi/hi-phonetic.js @@ -10,6 +10,7 @@ license: 'GPLv3', version: '1.0', patterns: [ + ['्f', '्\u200c'], ['\\~', 'ऎ'], ['\\`","ॆ'], ['\\!', 'ऍ'], @@ -102,10 +103,9 @@ ['/', 'ए'], ['\\^', 'ज्ञ'], ['X', 'क्ष'], - ['\\*', 'श्र'], - ['ff', '्‌'] + ['\\*', 'श्र'] ] }; - $.ime.register( hiPhonetic ); + $.ime.register( hiPhonetic ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/hi/hi-transliteration.js b/lib/jquery.ime/rules/hi/hi-transliteration.js index 878ae920..442e650d 100644 --- a/lib/jquery.ime/rules/hi/hi-transliteration.js +++ b/lib/jquery.ime/rules/hi/hi-transliteration.js @@ -193,6 +193,6 @@ [ '([क-ह]़?)्(.)', '\\~', '$1्$2' ], [ '([क-ह]़?)्(.)', '$1$2' ] ] }; - $.ime.register( hiTransliteration ); + $.ime.register( hiTransliteration ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/hr/hr-kbd.js b/lib/jquery.ime/rules/hr/hr-kbd.js index 82fe5197..2c0b8229 100644 --- a/lib/jquery.ime/rules/hr/hr-kbd.js +++ b/lib/jquery.ime/rules/hr/hr-kbd.js @@ -57,5 +57,4 @@ }; $.ime.register( hrKbd ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/hy/hy-emslegacy.js b/lib/jquery.ime/rules/hy/hy-emslegacy.js new file mode 100644 index 00000000..725c2a4f --- /dev/null +++ b/lib/jquery.ime/rules/hy/hy-emslegacy.js @@ -0,0 +1,169 @@ +/** + * Eastern Armenian phonetic layout introduced by Microsoft in Windows 2000 and depreceated in Windows 8. + * Original layout was created in late 90-ies based on Unicode 3, and was never updated since release, + * causing it to be incompatible with Unicode. + * + * This layout version complies with Unicode 6.1, including all valid Armenian punctuation signs, + * mijaket (outside of main Armenian Unicode range) and Dram (AMD) sign under USD sign (Shift + 4). + * Please, double-check with Unicode before making any changes here. + * + * Layout supports extended keys, with AltGr (Alt or Alt+Ctrl on some systems) + key, + * producing digits and punctuation marks from standard US keyboard layout. + */ + +( function ( $ ) { + 'use strict'; + + var hyEmslegacy = { + id: 'hy-emslegacy', + name: 'ՄՍ Արևելահայերեն (հնացած)', + description: 'Legacy keyboard layout for Eastern Armenian by Microsoft', + date: '2013-02-11', + URL: 'http://www.microsoft.com/resources/msdn/goglobal/keyboards/kbdarme.html', + author: 'Parag Nemade, Aleksey Chalabyan', + license: 'GPLv3', + version: '1.1', + patterns: [ + ['1', '։'], + ['\\!', '1'], + ['2', 'ձ'], + ['\\@', 'Ձ'], + ['3', 'յ'], + ['\\#', 'Յ'], + ['4', '՛'], + ['\\$', '֏'], + ['5', ','], + ['\\%', '4'], + ['6', '-'], + ['\\^', '9'], + ['7', '․'], + ['\\&', 'և'], + ['8', '«'], + ['\\*', '('], + ['9', '»'], + ['\\(', ')'], + ['0', 'օ'], + ['\\)', 'Օ'], + ['\\-', 'ռ'], + ['\\_', 'Ռ'], + ['\\=', 'ժ'], + ['\\+', 'Ժ'], + ['\\`', '՝'], + ['\\~', '՜'], + ['q', 'խ'], + ['Q', 'Խ'], + ['w', 'ւ'], + ['W', 'Ւ'], + ['e', 'է'], + ['E', 'Է'], + ['r', 'ր'], + ['R', 'Ր'], + ['t', 'տ'], + ['T', 'Տ'], + ['y', 'ե'], + ['Y', 'Ե'], + ['u', 'ը'], + ['U', 'Ը'], + ['i', 'ի'], + ['I', 'Ի'], + ['o', 'ո'], + ['O', 'Ո'], + ['p', 'պ'], + ['P', 'Պ'], + ['\\[', 'չ'], + ['\\{', 'Չ'], + ['\\]', 'ջ'], + ['\\}', 'Ջ'], + ['\\\\', '\''], + ['\\|', '՞'], + ['a', 'ա'], + ['A', 'Ա'], + ['s', 'ս'], + ['S', 'Ս'], + ['d', 'դ'], + ['D', 'Դ'], + ['f', 'ֆ'], + ['F', 'Ֆ'], + ['g', 'ք'], + ['G', 'Ք'], + ['h', 'հ'], + ['H', 'Հ'], + ['j', 'ճ'], + ['J', 'Ճ'], + ['k', 'կ'], + ['K', 'Կ'], + ['l', 'լ'], + ['L', 'Լ'], + [';', 'թ'], + [':', 'Թ'], + ['\'', 'փ'], + ['\"', 'Փ'], + ['z', 'զ'], + ['Z', 'Զ'], + ['x', 'ց'], + ['X', 'Ց'], + ['c', 'գ'], + ['C', 'Գ'], + ['v', 'վ'], + ['V', 'Վ'], + ['b', 'բ'], + ['B', 'Բ'], + ['n', 'ն'], + ['N', 'Ն'], + ['m', 'մ'], + ['M', 'Մ'], + [',', 'շ'], + ['\\<', 'Շ'], + ['\\.', 'ղ'], + ['\\>', 'Ղ'], + ['/', 'ծ'], + ['\\?', 'Ծ'] + ], + patterns_x: [ + ['1', '1'], + ['\\!', '!'], + ['2', '2'], + ['\\@', '@'], + ['3', '3'], + ['\\#', '#'], + ['4', '4'], + ['\\$', '$'], + ['5', '5'], + ['\\%', '%'], + ['6', '6'], + ['\\^', '^'], + ['7', '7'], + ['\\&', '&'], + ['8', '8'], + ['\\*', '*'], + ['9', '9'], + ['\\(', '('], + ['0', '0'], + ['\\)', ')'], + ['\\-', '-'], + ['\\_', '_'], + ['\\=', '='], + ['\\+', '+'], + ['\\`', '`'], + ['\\~', '~'], + ['\\[', '['], + ['\\{', '{'], + ['\\]', ']'], + ['\\}', '}'], + ['\\\\', '\\'], + ['\\|', '|'], + [';', ';'], + ['\\:', ':'], + ['\'', '\''], + ['\"', '\"'], + ['\\<', '<'], + ['\\.', '.'], + ['\\>', '>'], + ['/', '/'], + ['\\?', '?'] + ] + }; + + $.ime.register( hyEmslegacy ); + +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/hy/hy-ephonetic.js b/lib/jquery.ime/rules/hy/hy-ephonetic.js new file mode 100644 index 00000000..66f70390 --- /dev/null +++ b/lib/jquery.ime/rules/hy/hy-ephonetic.js @@ -0,0 +1,172 @@ +/** + * This is a phonetic layout for the Armenian language (hy, arm, hye). + * The layout comes from DOS times, and was later popularised by KDWin and WinKeys keyboard "drivers". + * While not as efficient and well-thought as the official typewriter layout, it is very popular as + * it uses similary sounding Latin letters, which is very handy, as keyboards in Armenia + * don't come engraved with Armenian letters. + * + * This layout complies with Unicode 6.1, including all valid Armenian punctuation signs, + * mijaket (outside of main Armenian Unicode range) and Dram (AMD) sign. + * Please, double-check with Unicode before making any changes here. + * + * Layout supports extended keys, with AltGr (Alt or Alt+Ctrl on some systems) + key, + * producing digits and punctuation marks from standard US keyboard layout. + */ + +( function ( $ ) { + 'use strict'; + + var hyEphonetic = { + id: 'hy-ephonetic', + name: 'Հայերեն Հնչյունային', + description: 'Armenian phonetic (Eastern) keyboard layout', + date: '2013-07-06', + URL: 'http://hy.am', + author: 'Aleksey Chalabyan Ալեքսեյ Չալաբյան a.k.a Xelgen', + license: 'GPLv3', + version: '1.0', + contextLength: 0, + maxKeyLength: 0, + patterns: [ + ['1', 'է'], + ['\\!', 'Է'], + ['2', 'թ'], + ['\\@', 'Թ'], + ['3', 'փ'], + ['\\#', 'Փ'], + ['4', 'ձ'], + ['\\$', 'Ձ'], + ['5', 'ջ'], + ['\\%', 'Ջ'], + ['6', '֏'], + ['\\^', '('], + ['7', 'և'], + ['\\&', ')'], + ['8', 'ր'], + ['\\*', 'Ր'], + ['9', 'չ'], + ['\\(', 'Չ'], + ['0', 'ճ'], + ['\\)', 'Ճ'], + ['\\-', '–'], + ['\\_', '—'], + ['\\=', 'ժ'], + ['\\+', 'Ժ'], + ['\\`', '՝'], + ['\\~', '՜'], + ['q', 'ք'], + ['Q', 'Ք'], + ['w', 'ո'], + ['W', 'Ո'], + ['e', 'ե'], + ['E', 'Ե'], + ['r', 'ռ'], + ['R', 'Ռ'], + ['t', 'տ'], + ['T', 'Տ'], + ['y', 'ը'], + ['Y', 'Ը'], + ['u', 'ւ'], + ['U', 'Ւ'], + ['i', 'ի'], + ['I', 'Ի'], + ['o', 'օ'], + ['O', 'Օ'], + ['p', 'պ'], + ['P', 'Պ'], + ['\\[', 'խ'], + ['\\{', 'Խ'], + ['\\]', 'ծ'], + ['\\}', 'Ծ'], + ['\\\\', 'շ'], + ['\\|', 'Շ'], + ['a', 'ա'], + ['A', 'Ա'], + ['s', 'ս'], + ['S', 'Ս'], + ['d', 'դ'], + ['D', 'Դ'], + ['f', 'ֆ'], + ['F', 'Ֆ'], + ['g', 'գ'], + ['G', 'Գ'], + ['h', 'հ'], + ['H', 'Հ'], + ['j', 'յ'], + ['J', 'Յ'], + ['k', 'կ'], + ['K', 'Կ'], + ['l', 'լ'], + ['L', 'Լ'], + [';', ';'], + [':', '։'], + ['\'', '՛'], + ['\"', '"'], + ['z', 'զ'], + ['Z', 'Զ'], + ['x', 'ղ'], + ['X', 'Ղ'], + ['c', 'ց'], + ['C', 'Ց'], + ['v', 'վ'], + ['V', 'Վ'], + ['b', 'բ'], + ['B', 'Բ'], + ['n', 'ն'], + ['N', 'Ն'], + ['m', 'մ'], + ['M', 'Մ'], + [',', ','], + ['\\<', '«'], + ['\\.', '․'], + ['\\>', '»'], + ['/', '…'], + ['\\?', '՞'] + ], + patterns_x: [ + ['1', '1'], + ['\\!', '!'], + ['2', '2'], + ['\\@', '@'], + ['3', '3'], + ['\\#', '#'], + ['4', '4'], + ['\\$', '$'], + ['5', '5'], + ['\\%', '%'], + ['6', '6'], + ['\\^', '^'], + ['7', '7'], + ['\\&', '&'], + ['8', '8'], + ['\\*', '*'], + ['9', '9'], + ['\\(', '('], + ['0', '0'], + ['\\)', ')'], + ['\\-', '-'], + ['\\_', '_'], + ['\\=', '='], + ['\\+', '+'], + ['\\`', '`'], + ['\\~', '~'], + ['\\[', '['], + ['\\{', '{'], + ['\\]', ']'], + ['\\}', '}'], + ['\\\\', '\\'], + ['\\|', '|'], + [';', ';'], + ['\\:', ':'], + ['\'', '\''], + ['\"', '\"'], + ['\\<', '<'], + ['\\.', '.'], + ['\\>', '>'], + ['/', '/'], + ['\\?', '?'] + ] + }; + + $.ime.register( hyEphonetic ); +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/hy/hy-ephoneticalt.js b/lib/jquery.ime/rules/hy/hy-ephoneticalt.js new file mode 100644 index 00000000..c3466484 --- /dev/null +++ b/lib/jquery.ime/rules/hy/hy-ephoneticalt.js @@ -0,0 +1,172 @@ +/** + * This is alternative phonetic layout for Armenian language (hy, arm, hye). + * Based on Armenian phonetic layout, it improves few things, by placing ր under latin r, + * as ր is much more frequent in Armenian. ռ goes under 8, where ր is in standart phonetic. + * Another change, which is not yet in xkb, ( as of July 2013), is swapping ֆ and թ: Ֆ is + * placed under F, where left index finger is, but is the least used letter in Armenian, + * so much more used թ takes it place, comming down from 2. + * + * This layout complies with Unicode 6.1, including all valid Armenian punctuation signs, + * mijaket (outside of main Armenian Unicode range) and Dram (AMD) sign. + * Please, double-check with Unicode before making any changes here. + * + * Layout supports extended keys, with AltGr (Alt or Alt+Ctrl on some systems) + key, + * producing digits and punctuation marks from standard US keyboard layout. + */ + +( function ( $ ) { + 'use strict'; + + var hyEphonetic = { + id: 'hy-ephoneticalt', + name: 'Հայերեն Հնչյունային (R->Ր, F->Թ)', + description: 'Eastern Armenian alternative phonetic keyboard layout', + date: '2013-07-08', + URL: 'http://github.com/wikimedia/jquery.ime', + author: 'Aleksey Chalabyan Ալեքսեյ Չալաբյան a.k.a Xelgen', + license: 'GPLv3', + version: '1.0', + patterns: [ + ['1', 'է'], + ['\\!', 'Է'], + ['2', 'ֆ'], + ['\\@', 'Ֆ'], + ['3', 'փ'], + ['\\#', 'Փ'], + ['4', 'ձ'], + ['\\$', 'Ձ'], + ['5', 'ջ'], + ['\\%', 'Ջ'], + ['6', '֏'], + ['\\^', '('], + ['7', 'և'], + ['\\&', ')'], + ['8', 'ռ'], + ['\\*', 'Ռ'], + ['9', 'չ'], + ['\\(', 'Չ'], + ['0', 'ճ'], + ['\\)', 'Ճ'], + ['\\-', '–'], + ['\\_', '—'], + ['\\=', 'ժ'], + ['\\+', 'Ժ'], + ['\\`', '՝'], + ['\\~', '՜'], + ['q', 'ք'], + ['Q', 'Ք'], + ['w', 'ո'], + ['W', 'Ո'], + ['e', 'ե'], + ['E', 'Ե'], + ['r', 'ր'], + ['R', 'Ր'], + ['t', 'տ'], + ['T', 'Տ'], + ['y', 'ը'], + ['Y', 'Ը'], + ['u', 'ւ'], + ['U', 'Ւ'], + ['i', 'ի'], + ['I', 'Ի'], + ['o', 'օ'], + ['O', 'Օ'], + ['p', 'պ'], + ['P', 'Պ'], + ['\\[', 'խ'], + ['\\{', 'Խ'], + ['\\]', 'ծ'], + ['\\}', 'Ծ'], + ['\\\\', 'շ'], + ['\\|', 'Շ'], + ['a', 'ա'], + ['A', 'Ա'], + ['s', 'ս'], + ['S', 'Ս'], + ['d', 'դ'], + ['D', 'Դ'], + ['f', 'թ'], + ['F', 'Թ'], + ['g', 'գ'], + ['G', 'Գ'], + ['h', 'հ'], + ['H', 'Հ'], + ['j', 'յ'], + ['J', 'Յ'], + ['k', 'կ'], + ['K', 'Կ'], + ['l', 'լ'], + ['L', 'Լ'], + [';', ';'], + [':', '։'], + ['\'', '՛'], + ['\"', '"'], + ['z', 'զ'], + ['Z', 'Զ'], + ['x', 'ղ'], + ['X', 'Ղ'], + ['c', 'ց'], + ['C', 'Ց'], + ['v', 'վ'], + ['V', 'Վ'], + ['b', 'բ'], + ['B', 'Բ'], + ['n', 'ն'], + ['N', 'Ն'], + ['m', 'մ'], + ['M', 'Մ'], + [',', ','], + ['\\<', '«'], + ['\\.', '․'], + ['\\>', '»'], + ['/', '…'], + ['\\?', '՞'] + ], + patterns_x: [ + ['1', '1'], + ['\\!', '!'], + ['2', '2'], + ['\\@', '@'], + ['3', '3'], + ['\\#', '#'], + ['4', '4'], + ['\\$', '$'], + ['5', '5'], + ['\\%', '%'], + ['6', '6'], + ['\\^', '^'], + ['7', '7'], + ['\\&', '&'], + ['8', '8'], + ['\\*', '*'], + ['9', '9'], + ['\\(', '('], + ['0', '0'], + ['\\)', ')'], + ['\\-', '-'], + ['\\_', '_'], + ['\\=', '='], + ['\\+', '+'], + ['\\`', '`'], + ['\\~', '~'], + ['\\[', '['], + ['\\{', '{'], + ['\\]', ']'], + ['\\}', '}'], + ['\\\\', '\\'], + ['\\|', '|'], + [';', ';'], + ['\\:', ':'], + ['\'', '\''], + ['\"', '\"'], + ['\\<', '<'], + ['\\.', '.'], + ['\\>', '>'], + ['/', '/'], + ['\\?', '?'] + ] + }; + + $.ime.register( hyEphonetic ); + +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/hy/hy-kbd.js b/lib/jquery.ime/rules/hy/hy-kbd.js deleted file mode 100644 index 96083d21..00000000 --- a/lib/jquery.ime/rules/hy/hy-kbd.js +++ /dev/null @@ -1,113 +0,0 @@ -( function ( $ ) { - 'use strict'; - - var hyKbd = { - id: 'hy-kbd', - name: 'kbd', - description: 'Eastern Armenian keyboard layout', - date: '2013-02-11', - URL: 'http://github.com/wikimedia/jquery.ime', - author: 'Parag Nemade', - license: 'GPLv3', - version: '1.0', - patterns: [ - ['1', ':'], - ['\\!', '1'], - ['2', 'ձ'], - ['\\@', 'Ձ'], - ['3', 'յ'], - ['\\#', 'Յ'], - ['4', '՛'], - ['\\$', '3'], - ['5', ','], - ['\\%', '4'], - ['6', '-'], - ['\\^', '9'], - ['7', '.'], - ['\\&', 'և'], - ['8', '«'], - ['\\*', '('], - ['9', '»'], - ['\\(', ')'], - ['0', 'օ'], - ['\\)', 'Օ'], - ['\\-', 'ռ'], - ['\\_', 'Ռ'], - ['\\=', 'ժ'], - ['\\+', 'Ժ'], - ['\\`', '՝'], - ['\\~', '՜'], - ['q', 'խ'], - ['Q', 'Խ'], - ['w', 'ւ'], - ['W', 'Ւ'], - ['e', 'է'], - ['E', 'Է'], - ['r', 'ր'], - ['R', 'Ր'], - ['t', 'տ'], - ['T', 'Տ'], - ['y', 'ե'], - ['Y', 'Ե'], - ['u', 'ը'], - ['U', 'Ը'], - ['i', 'ի'], - ['I', 'Ի'], - ['o', 'ո'], - ['O', 'Ո'], - ['p', 'պ'], - ['P', 'Պ'], - ['\\[', 'չ'], - ['\\{', 'Չ'], - ['\\]', 'ջ'], - ['\\}', 'Ջ'], - ['\\', '\''], - ['\\|', '՞'], - ['a', 'ա'], - ['A', 'Ա'], - ['s', 'ս'], - ['S', 'Ս'], - ['d', 'դ'], - ['D', 'Դ'], - ['f', 'ֆ'], - ['F', 'Ֆ'], - ['g', 'ք'], - ['G', 'Ք'], - ['h', 'հ'], - ['H', 'Հ'], - ['j', 'ճ'], - ['J', 'Ճ'], - ['k', 'կ'], - ['K', 'Կ'], - ['l', 'լ'], - ['L', 'Լ'], - [';', 'թ'], - [':', 'Թ'], - ['\'', 'փ'], - ['\"', 'Փ'], - ['z', 'զ'], - ['Z', 'Զ'], - ['x', 'ց'], - ['X', 'Ց'], - ['c', 'գ'], - ['C', 'Գ'], - ['v', 'վ'], - ['V', 'Վ'], - ['b', 'բ'], - ['B', 'Բ'], - ['n', 'ն'], - ['N', 'Ն'], - ['m', 'մ'], - ['M', 'Մ'], - [',', 'շ'], - ['\\<', 'Շ'], - ['.', 'ղ'], - ['\\>', 'Ղ'], - ['/', 'ծ'], - ['\\?', 'Ծ'] - ] - }; - - $.ime.register( hyKbd ); - -}( jQuery ) ); diff --git a/lib/jquery.ime/rules/hy/hy-typewriter.js b/lib/jquery.ime/rules/hy/hy-typewriter.js new file mode 100644 index 00000000..63b18725 --- /dev/null +++ b/lib/jquery.ime/rules/hy/hy-typewriter.js @@ -0,0 +1,168 @@ +/** + * Armenian typewriter layout + * Based on themonly official state standard for Armenian keyboard layout: + * http://www.sarm.am/en/standarts/view/5741 + * + * This layout complies with Unicode 6.1, including all valid Armenian punctuation signs, + * mijaket (outside of main Armenian Unicode range) and Dram (AMD) sign. + * Please, double-check with Unicode before making any changes here. + * + * Layout supports extended keys, with AltGr (Alt or Alt+Ctrl on some systems) + key, + * producing digits and punctuation marks from standard US keyboard layout. + */ + +( function ( $ ) { + 'use strict'; + + var hyTypewriter = { + id: 'hy-typewriter', + name: 'Հայերեն Գրամեքենա', + description: 'Armenian typewriter keyboard layout', + date: '2013-07-08', + URL: 'http://www.sarm.am/en/standarts/view/5741', + author: 'Aleksey Chalabyan Ալեքսեյ Չալաբյան a.k.a Xelgen', + license: 'GPLv3', + version: '1.0', + patterns: [ + ['1', 'ֆ'], + ['\\!', 'Ֆ'], + ['2', 'ձ'], + ['\\@', 'Ձ'], + ['3', '-'], + ['\\#', ''], + ['4', ','], + ['\\$', '֏'], + ['5', '։'], + ['\\%', '֊'], + ['6', '՞'], + ['\\^', '—'], + ['7', '․'], + ['\\&', 'և'], + ['8', '՛'], + ['\\*', '՚'], + ['9', ')'], + ['\\(', '('], + ['0', 'օ'], + ['\\)', 'Օ'], + ['\\-', 'է'], + ['\\_', 'Է'], + ['\\=', 'ղ'], + ['\\+', 'Ղ'], + ['\\`', '՝'], + ['\\~', '՜'], + ['q', 'ճ'], + ['Q', 'Ճ'], + ['w', 'փ'], + ['W', 'Փ'], + ['e', 'բ'], + ['E', 'Բ'], + ['r', 'ս'], + ['R', 'Ս'], + ['t', 'մ'], + ['T', 'Մ'], + ['y', 'ո'], + ['Y', 'Ո'], + ['u', 'ւ'], + ['U', 'Ւ'], + ['i', 'կ'], + ['I', 'Կ'], + ['o', 'ը'], + ['O', 'Ը'], + ['p', 'թ'], + ['P', 'Թ'], + ['\\[', 'ծ'], + ['\\{', 'Ծ'], + ['\\]', 'ց'], + ['\\}', 'Ց'], + ['\\\\', '»'], + ['\\|', '«'], + ['a', 'ջ'], + ['A', 'Ջ'], + ['s', 'վ'], + ['S', 'Վ'], + ['d', 'գ'], + ['D', 'Գ'], + ['f', 'ե'], + ['F', 'Ե'], + ['g', 'ա'], + ['G', 'Ա'], + ['h', 'ն'], + ['H', 'Ն'], + ['j', 'ի'], + ['J', 'Ի'], + ['k', 'տ'], + ['K', 'Տ'], + ['l', 'հ'], + ['L', 'Հ'], + [';', 'պ'], + [':', 'Պ'], + ['\'', 'ր'], + ['\"', 'Ր'], + ['z', 'ժ'], + ['Z', 'Ժ'], + ['x', 'դ'], + ['X', 'Դ'], + ['c', 'չ'], + ['C', 'Չ'], + ['v', 'յ'], + ['V', 'Յ'], + ['b', 'զ'], + ['B', 'Զ'], + ['n', 'լ'], + ['N', 'Լ'], + ['m', 'ք'], + ['M', 'Ք'], + [',', 'խ'], + ['\\<', 'Խ'], + ['\\.', 'շ'], + ['\\>', 'Շ'], + ['/', 'ռ'], + ['\\?', 'Ռ'] + ], + patterns_x: [ + ['1', '1'], + ['\\!', '!'], + ['2', '2'], + ['\\@', '@'], + ['3', '3'], + ['\\#', '#'], + ['4', '4'], + ['\\$', '$'], + ['5', '5'], + ['\\%', '%'], + ['6', '6'], + ['\\^', '^'], + ['7', '7'], + ['\\&', '&'], + ['8', '8'], + ['\\*', '*'], + ['9', '9'], + ['\\(', '('], + ['0', '0'], + ['\\)', ')'], + ['\\-', '-'], + ['\\_', '_'], + ['\\=', '='], + ['\\+', '+'], + ['\\`', '`'], + ['\\~', '~'], + ['\\[', '['], + ['\\{', '{'], + ['\\]', ']'], + ['\\}', '}'], + ['\\\\', '\\'], + ['\\|', '|'], + [';', ';'], + ['\\:', ':'], + ['\'', '\''], + ['\"', '\"'], + ['\\<', '<'], + ['\\.', '.'], + ['\\>', '>'], + ['/', '/'], + ['\\?', '?'] + ] + }; + + $.ime.register( hyTypewriter ); +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/hy/hy-wmslegacy.js b/lib/jquery.ime/rules/hy/hy-wmslegacy.js new file mode 100644 index 00000000..24efceac --- /dev/null +++ b/lib/jquery.ime/rules/hy/hy-wmslegacy.js @@ -0,0 +1,169 @@ +/** + * Western Armenian phonetic layout introduced by Microsoft in Windows 2000 and depreceated in Windows 8. + * Original layout was created in late 90-ies based on Unicode 3, and was never updated since release, + * causing it to be incompatible with Unicode. + * + * This layout version complies with Unicode 6.1, including all valid Armenian punctuation signs, + * mijaket (outside of main Armenian Unicode range) and Dram (AMD) sign under USD sign (Shift + 4). + * Please, double-check with Unicode before making any changes here. + * + * Layout supports extended keys, with AltGr (Alt or Alt+Ctrl on some systems) + key, + * producing digits and punctuation marks from standard US keyboard layout. + */ + +( function ( $ ) { + 'use strict'; + + var hyWmslegacy = { + id: 'hy-wmslegacy', + name: 'ՄՍ Արևմտահայերեն (հնացած)', + description: 'Legacy keyboard layout for Western Armenian by Microsoft', + date: '2013-07-08', + URL: 'http://www.microsoft.com/resources/msdn/goglobal/keyboards/kbdarmw.html', + author: 'Aleksey Chalabyan Ալեքսեյ Չալաբյան a.k.a Xelgen', + license: 'GPLv3', + version: '1.0', + patterns: [ + ['1', '։'], + ['\\!', '1'], + ['2', 'ձ'], + ['\\@', 'Ձ'], + ['3', 'յ'], + ['\\#', 'Յ'], + ['4', '՛'], + ['\\$', '֏'], + ['5', ','], + ['\\%', '4'], + ['6', '-'], + ['\\^', '9'], + ['7', '․'], + ['\\&', 'և'], + ['8', '«'], + ['\\*', '('], + ['9', '»'], + ['\\(', ')'], + ['0', 'օ'], + ['\\)', 'Օ'], + ['\\-', 'ռ'], + ['\\_', 'Ռ'], + ['\\=', 'ժ'], + ['\\+', 'Ժ'], + ['\\`', '՝'], + ['\\~', '՜'], + ['q', 'խ'], + ['Q', 'Խ'], + ['w', 'վ'], + ['W', 'Վ'], + ['e', 'է'], + ['E', 'Է'], + ['r', 'ր'], + ['R', 'Ր'], + ['t', 'դ'], + ['T', 'Դ'], + ['y', 'ե'], + ['Y', 'Ե'], + ['u', 'ը'], + ['U', 'Ը'], + ['i', 'ի'], + ['I', 'Ի'], + ['o', 'ո'], + ['O', 'Ո'], + ['p', 'բ'], + ['P', 'Բ'], + ['\\[', 'չ'], + ['\\{', 'Չ'], + ['\\]', 'ջ'], + ['\\}', 'Ջ'], + ['\\\\', '\''], + ['\\|', '՞'], + ['a', 'ա'], + ['A', 'Ա'], + ['s', 'ս'], + ['S', 'Ս'], + ['d', 'տ'], + ['D', 'Տ'], + ['f', 'ֆ'], + ['F', 'Ֆ'], + ['g', 'կ'], + ['G', 'Կ'], + ['h', 'հ'], + ['H', 'Հ'], + ['j', 'ճ'], + ['J', 'Ճ'], + ['k', 'ք'], + ['K', 'Ք'], + ['l', 'լ'], + ['L', 'Լ'], + [';', 'թ'], + [':', 'Թ'], + ['\'', 'փ'], + ['\"', 'Փ'], + ['z', 'զ'], + ['Z', 'Զ'], + ['x', 'ց'], + ['X', 'Ց'], + ['c', 'գ'], + ['C', 'Գ'], + ['v', 'ւ'], + ['V', 'Ւ'], + ['b', 'պ'], + ['B', 'Պ'], + ['n', 'ն'], + ['N', 'Ն'], + ['m', 'մ'], + ['M', 'Մ'], + [',', 'շ'], + ['\\<', 'Շ'], + ['\\.', 'ղ'], + ['\\>', 'Ղ'], + ['/', 'ծ'], + ['\\?', 'Ծ'] + ], + patterns_x: [ + ['1', '1'], + ['\\!', '!'], + ['2', '2'], + ['\\@', '@'], + ['3', '3'], + ['\\#', '#'], + ['4', '4'], + ['\\$', '$'], + ['5', '5'], + ['\\%', '%'], + ['6', '6'], + ['\\^', '^'], + ['7', '7'], + ['\\&', '&'], + ['8', '8'], + ['\\*', '*'], + ['9', '9'], + ['\\(', '('], + ['0', '0'], + ['\\)', ')'], + ['\\-', '-'], + ['\\_', '_'], + ['\\=', '='], + ['\\+', '+'], + ['\\`', '`'], + ['\\~', '~'], + ['\\[', '['], + ['\\{', '{'], + ['\\]', ']'], + ['\\}', '}'], + ['\\\\', '\\'], + ['\\|', '|'], + [';', ';'], + ['\\:', ':'], + ['\'', '\''], + ['\"', '\"'], + ['\\<', '<'], + ['\\.', '.'], + ['\\>', '>'], + ['/', '/'], + ['\\?', '?'] + ] + }; + + $.ime.register( hyWmslegacy ); + +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/jv/jv-transliteration.js b/lib/jquery.ime/rules/jv/jv-transliteration.js index 8c086dbd..6b02062c 100644 --- a/lib/jquery.ime/rules/jv/jv-transliteration.js +++ b/lib/jquery.ime/rules/jv/jv-transliteration.js @@ -5,213 +5,269 @@ id: 'jv-transliteration', name: 'Javanese', description: 'Javanese transliteration', - date: '2012-09-01', + date: '2013-08-10', URL: 'http://github.com/wikimedia/jquery.ime', author: 'Bennylin', license: 'GPLv3', - version: '1.0', + version: '1.1', contextLength: 1, maxKeyLength: 2, patterns: [ [ '\\\\([A-Za-z\\>_~\\.0-9])', '\\\\', '$1' ], + ['ꦝ꧀q', '','ꦞ꧀'], // Dha murda + ['ꦚ꧀q', '','ꦘ꧀'], // Nya murda + ['ꦧ꧀q', '','ꦨ꧀'], // Ba murda + ['ꦕ꧀q', '','ꦖ꧀'], // Ca murda(?) + ['ꦒ꧀q', '','ꦓ꧀'], // Ga murda + ['ꦗ꧀q', '','ꦙ꧀'], // Ja Mahaprana + ['ꦏ꧀q', '','ꦑ꧀'], // Ka murda + ['ꦤ꧀q', '','ꦟ꧀'], // Na murda + ['ꦥ꧀q', '','ꦦ꧀'], // Pa murda + ['ꦱ꧀q', '','ꦯ꧀'], // Sa murda + ['ꦠ꧀q', '','ꦡ꧀'], // Ta murda - [ '꧀ꦃa', '', '꧀​ꦲ' ], // pangkon and start with h - [ '꧀ꦃe', '', '꧀​ꦲꦺ' ], // pangkon and start with h - [ '꧀ꦃi', '', '꧀​ꦲꦶ' ], // pangkon and start with h - [ '꧀ꦃo', '', '꧀​ꦲꦺꦴ' ], // pangkon and start with h - [ '꧀ꦃu', '', '꧀​ꦲꦸ' ], // pangkon and start with h + // VII. Vocal ended with special pasangan followed by vocal = back to normal + ['ꦃa', '','ꦲ'], // vocal ended with -h followed by a + ['ꦃe', '','ꦲꦺ'], // vocal ended with -h followed by e + ['ꦃi', '','ꦲꦶ'], // vocal ended with -h followed by i + ['ꦃo', '','ꦲꦺꦴ'], // vocal ended with -h followed by o + ['ꦃu', '','ꦲꦸ'], // vocal ended with -h followed by u - [ '꧀ꦂa', '', '꧀​ꦫ' ], // pangkon and start with r - [ '꧀ꦂe', '', '꧀​ꦫꦺ' ], // pangkon and start with r - [ '꧀ꦂi', '', '꧀​ꦫꦶ' ], // pangkon and start with r - [ '꧀ꦂo', '', '꧀​ꦫꦺꦴ' ], // pangkon and start with r - [ '꧀ꦂu', '', '꧀​ꦫꦸ' ], // pangkon and start with r + ['ꦂa', '','ꦫ'], // vocal ended with -r followed by a + ['ꦂe', '','ꦫꦺ'], // vocal ended with -r followed by e + ['ꦂi', '','ꦫꦶ'], // vocal ended with -r followed by i + ['ꦂo', '','ꦫꦺꦴ'], // vocal ended with -r followed by o + ['ꦂu', '','ꦫꦸ'], // vocal ended with -r followed by u + ['ꦂy', '','ꦫꦾ'], // vocal ended with -r followed by y (Special) - [ '꧀ꦁa', '', '꧀​ꦔ' ], // pangkon and start with ng - [ '꧀ꦁe', '', '꧀​ꦔꦺ' ], // pangkon and start with ng - [ '꧀ꦁi', '', '꧀​ꦔꦶ' ], // pangkon and start with ng - [ '꧀ꦁo', '', '꧀​ꦔꦺꦴ' ], // pangkon and start with ng - [ '꧀ꦁu', '', '꧀​ꦔꦸ' ], // pangkon and start with ng + ['ꦁa', '','ꦔ'], // vocal ended with -ng followed by a + ['ꦁe', '','ꦔꦺ'], // vocal ended with -ng followed by e + ['ꦁi', '','ꦔꦶ'], // vocal ended with -ng followed by i + ['ꦁo', '','ꦔꦺꦴ'], // vocal ended with -ng followed by o + ['ꦁu', '','ꦔꦸ'], // vocal ended with -ng followed by u - [ 'ꦃa', '', 'ꦲ​' ], // vocal ended with -h followed by a - [ 'ꦃe', '', 'ꦲꦺ' ], // vocal ended with -h followed by e - [ 'ꦃi', '', 'ꦲꦶ' ], // vocal ended with -h followed by i - [ 'ꦃo', '', 'ꦲꦺꦴ' ], // vocal ended with -h followed by o - [ 'ꦃu', '', 'ꦲꦸ' ], // vocal ended with -h followed by u + // VI. Vocal (lowercase, uppercase, extended) ended with h/r/ng = special pasangan (-h, -r, -ng) + ['꧀​h', '','꧀ꦲ꧀'], + // vocal a ended with h/r/ng + ['(ꦲ|ꦤ|ꦕ|ꦫ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦝ|ꦗ|ꦪ|ꦚ|ꦩ|ꦒ|ꦧ|ꦛ|ꦔ|ꦘ|ꦿ|ꦾ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ|꦳)(h|H)', '','$1ꦃ'], // hanacaraka + h = -h + ['(ꦲ|ꦤ|ꦕ|ꦫ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦝ|ꦗ|ꦪ|ꦚ|ꦩ|ꦒ|ꦧ|ꦛ|ꦔ|ꦘ|ꦿ|ꦾ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ|꦳)(r|R)', '','$1ꦂ'], // hanacaraka + r = -r + ['(ꦲ|ꦤ|ꦕ|ꦫ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦝ|ꦗ|ꦪ|ꦚ|ꦩ|ꦒ|ꦧ|ꦛ|ꦔ|ꦘ|ꦿ|ꦾ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ|꦳)(ꦤ|ꦟ)꧀(g|G)', '','$1ꦁ'], // hanacaraka + ng = -ng + // other vocals ended with h/r/ng + ['(ꦴ|ꦻ|ꦍ|ꦺ|ꦼ|ꦶ|ꦷ|ꦸ|ꦹ|ꦄ|ꦌ|ꦆ|ꦎ|ꦈ)(h|H)', '','$1ꦃ'], // other vocal ended with -h + ['(ꦴ|ꦻ|ꦍ|ꦺ|ꦼ|ꦶ|ꦷ|ꦸ|ꦹ|ꦄ|ꦌ|ꦆ|ꦎ|ꦈ)(r|R)', '','$1ꦂ'], // other vocal ended with -r + ['(ꦴ|ꦻ|ꦍ|ꦺ|ꦼ|ꦶ|ꦷ|ꦸ|ꦹ|ꦄ|ꦌ|ꦆ|ꦎ|ꦈ)(ꦤ|ꦟ)꧀(g|G)', '','$1ꦁ'], // other vocal ended with -ng - [ 'ꦂa', '', 'ꦫ​' ], // vocal ended with -r followed by a - [ 'ꦂe', '', 'ꦫꦺ' ], // vocal ended with -r followed by e - [ 'ꦂi', '', 'ꦫꦶ' ], // vocal ended with -r followed by i - [ 'ꦂo', '', 'ꦫꦺꦴ' ], // vocal ended with -r followed by o - [ 'ꦂu', '', 'ꦫꦸ' ], // vocal ended with -r followed by u - [ 'ꦂy', '', 'ꦫꦾ' ], // vocal ended with -r followed by y + // V. Lower case consonant followed by lower case consonant: Basic + // Note: not all of these combination are valid in Javanese language, for example -hn-, + // so they are here only for logical reason, practically they should never be used. + // Obvious removal are noted (such as -yy-). th, dh, ny, ng, c, h, r, w, y are special cases: - [ 'ꦁa', '', 'ꦔ​' ], // vocal ended with -ng followed by a - [ 'ꦁe', '', 'ꦔꦺ' ], // vocal ended with -ng followed by e - [ 'ꦁi', '', 'ꦔꦶ' ], // vocal ended with -ng followed by i - [ 'ꦁo', '', 'ꦔꦺꦴ' ], // vocal ended with -ng followed by o - [ 'ꦁu', '', 'ꦔꦸ' ], // vocal ended with -ng followed by u + // pasangan 'ha'(ꦲ/ꦃ) is considered final, exception: about 60 words can be found of "ha" followed by consonant y/r/l/w + // pasangan 'ra'(ꦫ/ꦂ) is considered final, exception: 5 words can be found of "ra" followed by consonant y/w + // pasangan bigraf nga(ꦔ/ꦁ) is considered final, exception: "nga" can only be found followed by consonant y/r/l/w + // (some problem may occur - see http://jv.wikipedia.org/wiki/Dhiskusi_Panganggo:Bennylin/Narayam#Ng) + // pasangan bigraf nya can only be found followed by consonant r/l/w, and + // although not found in Latin, it also found in Javanese script representation of nasal sounds ñ (see nyc and nyj) + // pasangan bigraf dha can only be found followed by consonant y/r/ w + // pasangan bigraf tha can only be found followed by consonant r + // the letter 'w' can only be found followed by consonant y/r/l/w (nasal for 'u') + // the letter 'c' can only be found followed by consonant r/l, and ch + // the letter 'y' can only be found followed by consonant w (nasal for 'i') - [ '(​)h', '', 'ꦃ' ], // vocal a ended with -h - [ '(​)r', '', 'ꦂ' ], // vocal a ended with -r - [ '(​)ꦤg', '', 'ꦁ' ], // vocal a ended with -ng - [ '(ꦴ|ꦍ|ꦺ|ꦼ|ꦶ|ꦷ|ꦸ|ꦹ)h', '', '$1ꦃ' ], // other vocal ended with -h - [ '(ꦴ|ꦍ|ꦺ|ꦼ|ꦶ|ꦷ|ꦸ|ꦹ)r', '', '$1ꦂ' ], // other vocal ended with -r - [ '(ꦴ|ꦍ|ꦺ|ꦼ|ꦶ|ꦷ|ꦸ|ꦹ)ꦤg', '', '$1ꦁ' ], // other vocal ended with -ng - - // consonant followed by consonant, basic - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)ꦢh', '', '$1꧀ꦝ' ], // dh - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)ꦤy', '', '$1꧀ꦚ' ], // ny - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)ꦠh', '', '$1꧀ꦛ' ], // th - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)ꦤg', '', '$1꧀ꦔ' ], // ng - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)b', '', '$1꧀ꦧ' ], - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)c', '', '$1꧀ꦤ' ], - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)d', '', '$1꧀ꦢ' ], - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)(f|v)', '', '$1꧀ꦥ꦳' ], - [ '(ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)g', '', '$1꧀ꦒ' ], // can't be started with n, reserved for bigraf ng - [ '(ꦤ|ꦕ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦧ)h', '', '$1꧀ꦲ' ], // can't be started with k/d/t/g, reserved for bigraf kh/dh/th/gh - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)j', '', '$1꧀ꦗ' ], - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)k', '', '$1꧀ꦏ' ], - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)l', '', '$1꧀ꦭ' ], - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)m', '', '$1꧀ꦩ' ], - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)n', '', '$1꧀ꦤ' ], - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)p', '', '$1꧀ꦥ' ], - // ['(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)q', '',''], - [ 'ꦿꦺ`', '', 'ꦽ' ], // special biconsonant -rê - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)r', '', '$1ꦿ' ], // special biconsonant -ra - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)s', '', '$1꧀ꦱ' ], - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)t', '', '$1꧀ꦠ' ], + ['꧀a', '',''], // default vowel is a, so, remove the pangkon + ['꧀A', '','ꦄ'], // A + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀b', '','$1꧀ꦧ꧀'], + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀B', '','$1꧀ꦨ꧀'], // pasangan Ba murda + ['ꦤ꧀​(c|C)', '','ꦚ꧀ꦕ꧀'], // n+zero-width-space+c + ['ꦤ꧀(c|C)', '','ꦚ꧀ꦕ꧀'], // n followed by c became nasalized (nasal sound 'ny' + c)(REF:nyc) + ['(ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀c', '','$1꧀ꦕ꧀'], + ['(ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀C', '','$1꧀ꦖ꧀'], // pasangan Ca murda(?) + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀d', '','$1꧀ꦢ꧀'], + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀D', '','$1꧀ꦣ꧀'], + ['꧀e', '','ꦺ'], // é|è + ['꧀E', '','ꦌ'], // É|È + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀(f|v|F|V)', '','$1꧀ꦥ꦳꧀'], + ['(ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀g', '','$1꧀ꦒ꧀'], // can't be started with n, reserved for bigraf ng + ['(ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀G', '','$1꧀ꦓ꧀'], // pasangan Ga murda (can't be started with n - see II. 2.) + ['(ꦤ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀(h|H)', '','$1꧀ꦲ꧀'], // can't be started with k/d/t/g, reserved for bigraf kh/dh/th/gh + ['꧀i', '','ꦶ'], // i + ['꧀I', '','ꦆ'], // I + ['ꦤ꧀​(j|J)', '','ꦤ꧀ꦗ꧀'], // n+zero-width-space+j + ['ꦤ꧀(j|J)', '','ꦚ꧀ꦗ꧀'], // n followed by j became nasalized (nasal sound 'ny' + j)(REF:nyj) + ['(ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀(j|J)', '','$1꧀ꦗ꧀'], + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀k', '','$1꧀ꦏ꧀'], + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀K', '','$1꧀ꦑ꧀'], // pasangan Ka murda + ['(ꦲ|ꦃ|ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦚ|ꦩ|ꦒ|ꦧ|ꦔ|ꦁ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀(l|L)', '','$1꧀ꦭ꧀'], + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀(m|M)', '','$1꧀ꦩ꧀'], + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀n', '','$1꧀ꦤ꧀'], + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀N', '','$1꧀ꦟ꧀'], // pasangan Na murda + ['꧀o', '','ꦺꦴ'], // o + ['꧀O', '','ꦎ'], // O + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀p', '','$1꧀ꦥ꧀'], + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀P', '','$1꧀ꦦ꧀'], // pasangan Pa murda + // q + ['(ꦲ|ꦃ|ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦝ|ꦗ|ꦚ|ꦩ|ꦒ|ꦧ|ꦛ|ꦔ|ꦁ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀​r', '','$1꧀ꦫ꧀'], // consonant+zero-width-space+(r|R) doesn't make special biconsonant -ra + ['(ꦲ|ꦃ|ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦝ|ꦗ|ꦚ|ꦩ|ꦒ|ꦧ|ꦛ|ꦔ|ꦁ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀​R', '','$1꧀ꦬ꧀'], // consonant+zero-width-space+(r|R) doesn't make special biconsonant -ra + ['(ꦲ|ꦃ|ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦝ|ꦗ|ꦚ|ꦩ|ꦒ|ꦧ|ꦛ|ꦔ|ꦁ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀(r|R)', '','$1ꦿ'], // special biconsonant -ra + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀s', '','$1꧀ꦱ꧀'], + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀S', '','$1꧀ꦯ꧀'], // pasangan Sa murda + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀t', '','$1꧀ꦠ꧀'], + ['(ꦤ|ꦏ|ꦢ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀T', '','$1꧀ꦡ꧀'], // pasangan Ta murda + ['꧀u', '','ꦸ'], // u + ['꧀U', '','ꦈ'], // U // v = f - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)w', '', '$1꧀ꦮ' ], - // ['(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)x', '',''], - [ '(ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ)y', '', '$1ꦾ' ], // special biconsonant -ya, can't be started - // with n or y, reserved for bigraf ny - [ '(ꦤ|ꦕ|ꦏ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)z', '', '$1ꦾꦗ꦳' ], // can't be started with d, reserved for bigraf dz + ['(ꦲ|ꦃ|ꦤ|ꦫ|ꦂ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦝ|ꦗ|ꦪ|ꦚ|ꦩ|ꦒ|ꦧ|ꦔ|ꦁ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀(w|W)꧀', '','$1꧀ꦮ'], + ['(ꦲ|ꦃ|ꦫ|ꦂ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦝ|ꦗ|ꦩ|ꦒ|ꦧ|ꦔ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀​(y|Y)', '','$1꧀ꦪ꧀'], // consonant+zero-width-space+(y|Y) doesn't make special biconsonant -ya - // consonant followed by consonant, extended - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)ꦤ(y|Y)', '', '$1꧀ꦘ' ], // Nya murda - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)B', '', '$1꧀ꦨ' ], // Ba murda - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)C', '', '$1꧀ꦖ' ], // Ca murda(?) - [ '(ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)G', '', '$1꧀ꦓ' ], // Ga murda //can't be started with n, reserved for bigraf nG (Ng) - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)K', '', '$1꧀ꦑ' ], // Ka murda - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)N', '', '$1꧀ꦟ' ], // Na murda - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)P', '', '$1꧀ꦦ' ], // Pa murda - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)S', '', '$1꧀ꦯ' ], // Sa murda - [ '(ꦤ|ꦕ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦗ|ꦪ|ꦩ|ꦒ|ꦧ)T', '', '$1꧀ꦡ' ], // Ta murda + ['(ꦲ|ꦃ|ꦫ|ꦂ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦝ|ꦗ|ꦩ|ꦒ|ꦧ|ꦔ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦦ|ꦯ|ꦡ)꧀(y|Y)', '','$1ꦾ'], // special biconsonant -ya, + // can't be started with n or y, reserved for bigraf ny (REF:-yy-) + ['(ꦤ|ꦏ|ꦠ|ꦱ|ꦭ|ꦥ|ꦗ|ꦩ|ꦒ|ꦧ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ)꧀(z|Z)', '','$1ꦾꦗ꦳꧀'], // can't be started with d, reserved for bigraf dz - // extended vowel - [ '​a', '', 'ꦴ' ], // long a (aa) - [ '​i', '', 'ꦍ' ], // (ai) - [ 'ꦶi', '', 'ꦷ' ], // long i (ii) - [ 'ꦸu', '', 'ꦹ' ], // long u (uu) + // IV. 1. Special consonant + ['(ꦾ|ꦿ)a', '','$1'], + ['ꦿx', '','ꦽ'], // special biconsonant -rê + ['ꦊq', '','ꦋ'], // special character lê Raswadi + ['ꦭ꧀x', '','ꦊ'], // special character lê + ['ꦫ꧀x', '','ꦉ'], // special character rê + ['ꦌx', '','ꦄꦼ'], // Ê + ['꧀x', '','ꦼ'], // x is another way to write ê + ['꧀X', '','ꦄꦼ'], // X is another way to write Ê - // extended consonant - [ 'ꦏh', '', 'ꦏ꦳' ], // kh - [ 'ꦒh', '', 'ꦒ꦳' ], // gh - [ 'ꦢz', '', 'ꦢ꦳' ], // dz - [ 'ꦗ`', '', 'ꦙ' ], // Ja mahaprana + // IV. 3. Extended vowel + // long a (aa) - see II. + ['(ꦲ|ꦤ|ꦕ|ꦫ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦝ|ꦗ|ꦪ|ꦚ|ꦩ|ꦒ|ꦧ|ꦛ|ꦔ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ|꦳)i', '','$1ꦻ'], // hanacaraka + i = -ai + ['(ꦲ|ꦤ|ꦕ|ꦫ|ꦏ|ꦢ|ꦠ|ꦱ|ꦮ|ꦭ|ꦥ|ꦝ|ꦗ|ꦪ|ꦚ|ꦩ|ꦒ|ꦧ|ꦛ|ꦔ|ꦘ|ꦨ|ꦖ|ꦓ|ꦑ|ꦟ|ꦦ|ꦯ|ꦡ|꦳)u', '','$1ꦻꦴ'], // hanacaraka + u = -au + ['ꦄi', '','ꦍ'], // Ai + ['ꦄu', '','ꦎꦴ'], // Au + ['ꦶi', '','ꦷ'], // long i (ii) + ['ꦆi', '','ꦇ'], // long i (Ii) + ['ꦸu', '','ꦹ'], // long u (uu) + ['ꦈu', '','ꦈꦴ'], // long u (Uu) + ['ꦺꦴo', '','ꦵ'], // Sundanese -o - // special consonant - [ 'ꦭꦺ`', '', 'ꦊ' ], // special character lê - [ 'ꦫꦺ`', '', 'ꦉ' ], // special character rê + // IV. 2. Extended consonant + ['ꦱ꧀​(s|h)', '','ꦰ꧀'], // s_s (with zero-width-space) + ['ꦏ꧀​h', '','ꦏ꧀ꦲ꧀'], // k_h (with zero-width-space) + ['ꦒ꧀​h', '','ꦒ꧀ꦲ꧀'], // g_h (with zero-width-space) + ['ꦢ꧀​z', '','ꦢ꧀ꦗ꦳꧀'], // d_z (with zero-width-space) + ['ꦗ꧀​h', '','ꦙ'], // j_h (with zero-width-space) + ['ꦱ꧀(s|h)', '','ꦰ꧀'], // ss/sh + ['ꦏ꧀h', '','ꦏ꦳'], // kh + ['ꦒ꧀h', '','ꦒ꦳'], // gh + ['ꦢ꧀z', '','ꦢ꦳'], // dz + ['ꦗ꧀h', '','ꦙ'], // jh/Ja mahaprana - // non words - [ ' ', '', '​' ], // zero-width-space, since javanese have no space - [ 'q`', '', '꧀' ], // pengkal - to cut off the default -a vowel - [ 'x`', '', '꦳' ], // cecak telu - [ '꦳`', '', 'ꦀ' ], // panyangga - [ 'ꦀ`', '', '̈' ], // combining-diaresis - [ '̈`', '', '͜' ], // double-breve + // III. Non-words + // q and Q are special characters for choosing less used characters by pressing q/Q multiple times (rotating back) + [' ', '','​'], // zero-width-space, since javanese have no space + ['꧅q', '','꧁'], // rêrênggan kiwa + ['꧄q', '','꧅'], // pada luhur + ['꧃q', '','꧄'], // pada madya + ['꧂q', '', '꧃'],// pada andhap + ['꧁q', '','꧂'], // rêrênggan têngên + ['Q', '','꧁'], // rêrênggan kiwa + ['꧟[Q|q]', '','꧀'], // pangkon + ['꧞[Q|q]', '','꧟'], // pada isen-isen + ['꧆[Q|q]', '','꧞'], // pada tirta tumetes + ['ꦀ[Q|q]', '', '꧆'],// pada windu + ['꦳[Q|q]', '','ꦀ'], // panyangga + ['꧀[Q|q]', '','꦳'], // cecak telu + ['q', '','꧀'], // pangkon - to cut off the default -a vowel - [ 'ꦫ`', '', 'ꦿ' ], // another way to write -ra - [ 'ꦪ`', '', 'ꦾ' ], // another way to write -ya + ['ꦫq', '','ꦿ'], // another way to write -ra + ['ꦪq', '','ꦾ'], // another way to write -ya - // basic ha-na-ca-ra-ka - [ 'ꦢh', '', 'ꦝ' ], // dh - [ 'ꦠh', '', 'ꦛ' ], // th - [ 'ꦤy', '', 'ꦚ' ], // ny - [ 'ꦤg', '', 'ꦔ' ], // ng - [ 'ꦺ`', '', 'ꦼ' ], // ê - [ 'a', '', '​' ], // default vowel is a, by default using zero-width-non-joiner - [ 'b', '', 'ꦧ' ], - [ 'c', '', 'ꦕ' ], - [ 'd', '', 'ꦢ' ], - [ 'e', '', 'ꦺ' ], // é|è - [ '(f|v)', '', 'ꦥ꦳' ], - [ 'g', '', 'ꦒ' ], - [ 'h', '', 'ꦲ' ], - [ 'i', '', 'ꦶ' ], - [ 'j', '', 'ꦗ' ], - [ 'k', '', 'ꦏ' ], - [ 'l', '', 'ꦭ' ], - [ 'm', '', 'ꦩ' ], - [ 'n', '', 'ꦤ' ], - [ 'o', '', 'ꦺꦴ' ], - [ 'p', '', 'ꦥ' ], - // ['q', '',''], - [ 'r', '', 'ꦫ' ], - [ 's', '', 'ꦱ' ], - [ 't', '', 'ꦠ' ], - [ 'u', '', 'ꦸ' ], + // II. 1. Alphabetical ha-na-ca-ra-ka + ['ꦠ꧀​h', '','ꦠ꧀ꦲ꧀'], // t_h (with zero-width-space) + ['ꦢ꧀​h', '','ꦢ꧀ꦲ꧀'], // d_h (with zero-width-space) + ['ꦤ꧀​y', '','ꦚ꧀ꦪ꧀'], // n_y (with zero-width-space) + ['ꦤ꧀​g', '','ꦔ꧀ꦒ꧀'], // n_g (with zero-width-space) + ['ꦠ꧀h', '','ꦛ꧀'], // th + ['ꦢ꧀h', '','ꦝ꧀'], // dh + ['ꦤ꧀y', '','ꦚ꧀'], // ny + ['ꦤ꧀g', '','ꦁ'], // ng + ['a', '','ꦲ'], + ['b', '','ꦧ꧀'], + ['c', '','ꦕ꧀'], + ['d', '','ꦢ꧀'], + ['e', '','ꦲꦺ'], // é|è + ['(f|v)', '','ꦥ꦳꧀'], + ['g', '','ꦒ꧀'], + ['h', '','ꦲ꧀'], + ['i', '','ꦲꦶ'], + ['j', '','ꦗ꧀'], + ['k', '','ꦏ꧀'], + ['l', '','ꦭ꧀'], + ['m', '','ꦩ꧀'], + ['n', '','ꦤ꧀'], + ['o', '','ꦲꦺꦴ'], + ['p', '','ꦥ꧀'], + // q = special letters, see III. + ['r', '','ꦫ꧀'], + ['s', '','ꦱ꧀'], + ['t', '','ꦠ꧀'], + ['u', '','ꦲꦸ'], // v = f - [ 'w', '', 'ꦮ' ], - // ['x', '',''], - [ 'y', '', 'ꦪ' ], - [ 'z', '', 'ꦗ꦳' ], + ['w', '','ꦮ꧀'], + ['x', '','ꦲꦼ'], // ê + ['y', '','ꦪ꧀'], + ['z', '','ꦗ꦳꧀'], - // capital Ha-Na-Ca-Ra-Ka - [ 'ꦢ(h|H)', '', 'ꦝ' ], - [ 'ꦤ(y|Y)', '', 'ꦘ' ], // Nya murda - [ 'ꦠ(h|H)', '', 'ꦛ' ], - [ 'ꦤ(g|G)', '', 'ꦔ' ], - [ 'ꦌ`', '', 'ꦄꦼ' ], // Ê - [ 'A', '', 'ꦄ' ], // A - [ 'B', '', 'ꦨ' ], // Ba murda - [ 'C', '', 'ꦖ' ], // Ca murda(?) - [ 'D', '', 'ꦢ' ], - [ 'E', '', 'ꦌ' ], // É|È - [ '(F|V)', '', 'ꦥ꦳' ], - [ 'G', '', 'ꦓ' ], // Ga murda - [ 'H', '', 'ꦲ' ], - [ 'I', '', 'ꦆ' ], // I - [ 'J', '', 'ꦗ' ], - [ 'K', '', 'ꦑ' ], // Ka murda - [ 'L', '', 'ꦭ' ], - [ 'M', '', 'ꦩ' ], - [ 'N', '', 'ꦟ' ], //Na murda - [ 'O', '', 'ꦎ' ], //O - [ 'P', '', 'ꦦ' ], //Pa murda - [ 'Q', '', '' ], - [ 'R', '', 'ꦫ' ], - [ 'S', '', 'ꦯ' ], //Sa murda - [ 'T', '', 'ꦡ' ], //Ta murda - [ 'U', '', 'ꦈ' ], //U - //v = f - [ 'W', '', 'ꦮ' ], - [ 'X', '', '' ], - [ 'Y', '', 'ꦪ' ], - [ 'Z', '', 'ꦗ꦳' ], + // II. Basic Letters: + // II. 2. Capital Ha-Na-Ca-Ra-Ka (Aksara Murda) + ['(ꦠ|ꦡ)꧀(h|H)', '','ꦛ꧀'], + ['ꦣ꧀h', '','ꦞ꧀'], // Dha murda + ['(ꦢ|ꦣ)꧀H', '','ꦞ꧀'], // Dha murda + ['ꦟ꧀y', '','ꦘ꧀'], // Nya murda + ['(ꦤ|ꦟ)꧀Y', '','ꦘ꧀'], // NYA murda + ['(ꦤ|ꦟ)꧀(g|G)', '','ꦔ꧀'],// nga + ['A', '','ꦄ'], // A + ['B', '','ꦨ꧀'], // Ba murda + ['C', '','ꦖ꧀'], // Ca murda(?) + ['D', '','ꦣ꧀'], + ['E', '','ꦌ'], // É|È + ['(F|V)', '','ꦥ꦳꧀'], + ['G', '','ꦓ꧀'], // Ga murda + ['H', '','ꦲ꧀'], + ['I', '','ꦆ'], // I + ['J', '','ꦙ꧀'],// Ja Mahaprana + ['K', '','ꦑ꧀'], // Ka murda + ['L', '','ꦭ꧀'], + ['M', '','ꦩ꧀'], + ['N', '','ꦟ꧀'], // Na murda + ['O', '','ꦎ'], // O + ['P', '','ꦦ꧀'], // Pa murda + // Q = special letters, see III. + ['R', '','ꦬ꧀'], + ['S', '','ꦯ꧀'], // Sa murda + ['T', '','ꦡ꧀'], // Ta murda + ['U', '','ꦈ'], // U + // V = F + ['W', '','ꦮ꧀'], + ['X', '','ꦄꦼ'], // X is another way to write Ê + ['Y', '','ꦪ꧀'], + ['Z', '','ꦗ꦳꧀'], - [ '0', '', '꧐' ], - [ '1', '', '꧑' ], - [ '2', '', '꧒' ], - [ '3', '', '꧓' ], - [ '4', '', '꧔' ], - [ '5', '', '꧕' ], - [ '6', '', '꧖' ], - [ '7', '', '꧗' ], - [ '8', '', '꧘' ], - [ '9', '', '꧙' ], - [ ',', '', '꧈' ], - [ '\\.', '', '꧉' ], - [ '꧊\\|', '', '꧋' ], // '||' - [ '\\|', '', '꧊' ], // '|' - [ '\\(', '', '꧌' ], // '(' - [ '\\)', '', '꧍' ], // ')' - [ '(\u200C)*_', '', '\u200c' ] + // I. Number + ['0', '','꧐'], + ['1', '','꧑'], + ['2', '','꧒'], + ['3', '','꧓'], + ['4', '','꧔'], + ['5', '','꧕'], + ['6', '','꧖'], + ['7', '','꧗'], + ['8', '','꧘'], + ['9', '','꧙'], + [':', '','꧇'], // 'enclose Javanese numbers, e.g. ":1:"' + [',', '','꧈'], // 'comma' + ['\\.', '','꧉'], // 'period' + ['꧊\\|', '','꧋'], // 'opening paragraph character' + ['\\|', '','꧊'], // 'poem character' + ['\\(', '','꧌'], // 'Javanese opening bracket' + ['\\)', '','꧍'] // 'Javanese closing bracket' ] }; $.ime.register( jvTransliteration ); - -}( jQuery ) ); \ No newline at end of file +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/ka/ka-kbd.js b/lib/jquery.ime/rules/ka/ka-kbd.js index 41f9a531..a974a686 100644 --- a/lib/jquery.ime/rules/ka/ka-kbd.js +++ b/lib/jquery.ime/rules/ka/ka-kbd.js @@ -51,7 +51,6 @@ ['w', 'ჳ'], ['f', 'ჶ']] }; + $.ime.register( kaKbd ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/ka/ka-transliteration.js b/lib/jquery.ime/rules/ka/ka-transliteration.js index 109213ad..08fc1db5 100644 --- a/lib/jquery.ime/rules/ka/ka-transliteration.js +++ b/lib/jquery.ime/rules/ka/ka-transliteration.js @@ -53,8 +53,6 @@ ['Z', 'ძ'], ['C', 'ჩ']] }; + $.ime.register( kaTransliteration ); - }( jQuery ) ); - - diff --git a/lib/jquery.ime/rules/kk/kk-arabic.js b/lib/jquery.ime/rules/kk/kk-arabic.js index 90a49021..72db1d3b 100644 --- a/lib/jquery.ime/rules/kk/kk-arabic.js +++ b/lib/jquery.ime/rules/kk/kk-arabic.js @@ -57,7 +57,6 @@ ['\\}', '{'] ] }; + $.ime.register( kkArabic ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/kk/kk-kbd.js b/lib/jquery.ime/rules/kk/kk-kbd.js index 8dc93682..4a6e273e 100644 --- a/lib/jquery.ime/rules/kk/kk-kbd.js +++ b/lib/jquery.ime/rules/kk/kk-kbd.js @@ -103,7 +103,6 @@ ['/', '№'] ] }; + $.ime.register( kkKbd ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/kn/kn-inscript.js b/lib/jquery.ime/rules/kn/kn-inscript.js index 931376f6..09ca185a 100644 --- a/lib/jquery.ime/rules/kn/kn-inscript.js +++ b/lib/jquery.ime/rules/kn/kn-inscript.js @@ -3,7 +3,7 @@ var knInscript = { id: 'kn-inscript', - name: 'ಇನ್‌ಸ್ಕ್ರಿಪ್ಟ್', + name: 'ಇನ್\u200cಸ್ಕ್ರಿಪ್ಟ್', description: 'Inscript keyboard for Kannada script', date: '2012-10-14', author: 'Junaid P V', @@ -106,6 +106,6 @@ ['j', '\u0CF2'], ['\\$', '\u20B9']] }; - $.ime.register( knInscript ); + $.ime.register( knInscript ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/kn/kn-inscript2.js b/lib/jquery.ime/rules/kn/kn-inscript2.js index 364f3f7e..5a01dc96 100644 --- a/lib/jquery.ime/rules/kn/kn-inscript2.js +++ b/lib/jquery.ime/rules/kn/kn-inscript2.js @@ -3,7 +3,7 @@ var knInscript2 = { id: 'kn-inscript2', - name: 'ಇನ್‌ಸ್ಕ್ರಿಪ್ಟ್ ೨', + name: 'ಇನ್\u200cಸ್ಕ್ರಿಪ್ಟ್ ೨', description: 'Enhanced InScript keyboard for Kannada script', date: '2013-01-16', author: 'Parag Nemade', @@ -98,8 +98,8 @@ ['\\*', 'ಶ್ರ'] ], patterns_x: [ - ['1', '‍'], - ['2', '‌'], + ['1', '\u200d'], + ['2', '\u200c'], ['4', '₹'], ['\\+', 'ೠ'], ['\\=', 'ೄ'], @@ -116,5 +116,4 @@ }; $.ime.register( knInscript2 ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/kn/kn-kgp.js b/lib/jquery.ime/rules/kn/kn-kgp.js index 8e12a262..3676c118 100644 --- a/lib/jquery.ime/rules/kn/kn-kgp.js +++ b/lib/jquery.ime/rules/kn/kn-kgp.js @@ -1,103 +1,104 @@ ( function ( $ ) { - 'use strict'; + 'use strict'; - var knKGP = { - id: 'kn-kgp', - name: 'ಕಗಪ/ನುಡಿ', - description: 'Kannada kgp/nudi/KP Rao layout', - date: '2012-11-09', - URL: 'http://github.com/wikimedia/jquery.ime', - author: 'Aravinda VK', - license: 'GPLv3,MIT', - version: '1.0', - contextLength: 4, - maxKeyLength: 2, - patterns: [ - ['([ಕ-ಹೞ]಼?)f', '$1್'], - ['([ಕ-ಹೞ]಼?್)f', '$1'], - ['\\\\([A-Za-z\\>_~\\.0-9])','\\\\','$1'], - ['([ಕ-ಹೞ]಼?)A', '$1ಾ'], - ['([ಕ-ಹೞ]಼?)i', '$1ಿ'], - ['([ಕ-ಹೞ]಼?)I', '$1ೀ'], - ['([ಕ-ಹೞ]಼?)u', '$1ು'], - ['([ಕ-ಹೞ]಼?)U', '$1ೂ'], - ['([ಕ-ಹೞ]಼?)R', '$1ೃ'], - ['([ಕ-ಹೞ]಼?)ೃX', '$1ೄ'], - ['([ಕ-ಹೞ]಼?)e', '$1ೆ'], - ['([ಕ-ಹೞ]಼?)E', '$1ೇ'], - ['([ಕ-ಹೞ]಼?)Y', '$1ೈ'], - ['([ಕ-ಹೞ]಼?)o', '$1ೊ'], - ['([ಕ-ಹೞ]಼?)O', '$1ೋ'], - ['([ಕ-ಹೞ]಼?)V', '$1ೌ'], - ['ಸX', 'ಽ'], - ['([ಕ-ಹೞ]಼?\u200D)f', '$1್'], - ['(\u200D)F', '\u200C'], // 0x200C Zero width non-joiner - ['F', '\u200D'], // 0x200D Zero width joiner - ['k', 'ಕ'], - ['K', 'ಖ'], - ['g', 'ಗ'], - ['G', 'ಘ'], - ['Z', 'ಙ'], - ['c', 'ಚ'], - ['C', 'ಛ'], - ['j', 'ಜ'], - ['ಜX', 'ಜ಼'], - ['J', 'ಝ'], - ['z', 'ಞ'], - ['q', 'ಟ'], - ['Q', 'ಠ'], - ['w', 'ಡ'], - ['W', 'ಢ'], - ['N', 'ಣ'], - ['t', 'ತ'], - ['T', 'ಥ'], - ['d', 'ದ'], - ['D', 'ಧ'], - ['n', 'ನ'], - ['p', 'ಪ'], - ['P', 'ಫ'], - ['ಫX', 'ಫ಼'], - ['b', 'ಬ'], - ['B', 'ಭ'], - ['m', 'ಮ'], - ['y', 'ಯ'], - ['r', 'ರ'], - ['ರX', 'ಱ'], - ['l', 'ಲ'], - ['v', 'ವ'], - ['S', 'ಶ'], - ['x', 'ಷ'], - ['s', 'ಸ'], - ['h', 'ಹ'], - ['L', 'ಳ'], - ['ಳX', 'ೞ'], - ['a', 'ಅ'], - ['A', 'ಆ'], - ['i', 'ಇ'], - ['I', 'ಈ'], - ['u', 'ಉ'], - ['U', 'ಊ'], - ['R', 'ಋ'], - ['ಋX', 'ೠ'], - ['e', 'ಎ'], - ['E', 'ಏ'], - ['Y', 'ಐ'], - ['o', 'ಒ'], - ['O', 'ಓ'], - ['V', 'ಔ'], - ['M', 'ಂ'], - ['H', 'ಃ'], - ['0', '೦'], - ['1', '೧'], - ['2', '೨'], - ['3', '೩'], - ['4', '೪'], - ['5', '೫'], - ['6', '೬'], - ['7', '೭'], - ['8', '೮'], - ['9', '೯']] - }; - $.ime.register( knKGP ); + var knKGP = { + id: 'kn-kgp', + name: 'ಕಗಪ/ನುಡಿ', + description: 'Kannada kgp/nudi/KP Rao layout', + date: '2012-11-09', + URL: 'http://github.com/wikimedia/jquery.ime', + author: 'Aravinda VK', + license: 'GPLv3,MIT', + version: '1.0', + contextLength: 4, + maxKeyLength: 2, + patterns: [ + ['([ಕ-ಹೞ]಼?)f', '$1್'], + ['([ಕ-ಹೞ]಼?್)f', '$1'], + ['\\\\([A-Za-z\\>_~\\.0-9])', '\\\\', '$1'], + ['([ಕ-ಹೞ]಼?)A', '$1ಾ'], + ['([ಕ-ಹೞ]಼?)i', '$1ಿ'], + ['([ಕ-ಹೞ]಼?)I', '$1ೀ'], + ['([ಕ-ಹೞ]಼?)u', '$1ು'], + ['([ಕ-ಹೞ]಼?)U', '$1ೂ'], + ['([ಕ-ಹೞ]಼?)R', '$1ೃ'], + ['([ಕ-ಹೞ]಼?)ೃX', '$1ೄ'], + ['([ಕ-ಹೞ]಼?)e', '$1ೆ'], + ['([ಕ-ಹೞ]಼?)E', '$1ೇ'], + ['([ಕ-ಹೞ]಼?)Y', '$1ೈ'], + ['([ಕ-ಹೞ]಼?)o', '$1ೊ'], + ['([ಕ-ಹೞ]಼?)O', '$1ೋ'], + ['([ಕ-ಹೞ]಼?)V', '$1ೌ'], + ['ಸX', 'ಽ'], + ['([ಕ-ಹೞ]಼?\u200D)f', '$1್'], + ['(\u200D)F', '\u200C'], // 0x200C Zero width non-joiner + ['F', '\u200D'], // 0x200D Zero width joiner + ['k', 'ಕ'], + ['K', 'ಖ'], + ['g', 'ಗ'], + ['G', 'ಘ'], + ['Z', 'ಙ'], + ['c', 'ಚ'], + ['C', 'ಛ'], + ['j', 'ಜ'], + ['ಜX', 'ಜ಼'], + ['J', 'ಝ'], + ['z', 'ಞ'], + ['q', 'ಟ'], + ['Q', 'ಠ'], + ['w', 'ಡ'], + ['W', 'ಢ'], + ['N', 'ಣ'], + ['t', 'ತ'], + ['T', 'ಥ'], + ['d', 'ದ'], + ['D', 'ಧ'], + ['n', 'ನ'], + ['p', 'ಪ'], + ['P', 'ಫ'], + ['ಫX', 'ಫ಼'], + ['b', 'ಬ'], + ['B', 'ಭ'], + ['m', 'ಮ'], + ['y', 'ಯ'], + ['r', 'ರ'], + ['ರX', 'ಱ'], + ['l', 'ಲ'], + ['v', 'ವ'], + ['S', 'ಶ'], + ['x', 'ಷ'], + ['s', 'ಸ'], + ['h', 'ಹ'], + ['L', 'ಳ'], + ['ಳX', 'ೞ'], + ['a', 'ಅ'], + ['A', 'ಆ'], + ['i', 'ಇ'], + ['I', 'ಈ'], + ['u', 'ಉ'], + ['U', 'ಊ'], + ['R', 'ಋ'], + ['ಋX', 'ೠ'], + ['e', 'ಎ'], + ['E', 'ಏ'], + ['Y', 'ಐ'], + ['o', 'ಒ'], + ['O', 'ಓ'], + ['V', 'ಔ'], + ['M', 'ಂ'], + ['H', 'ಃ'], + ['0', '೦'], + ['1', '೧'], + ['2', '೨'], + ['3', '೩'], + ['4', '೪'], + ['5', '೫'], + ['6', '೬'], + ['7', '೭'], + ['8', '೮'], + ['9', '೯'] + ] + }; - }( jQuery ) ); + $.ime.register( knKGP ); +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/kn/kn-transliteration.js b/lib/jquery.ime/rules/kn/kn-transliteration.js index 247fbb5b..ced94338 100644 --- a/lib/jquery.ime/rules/kn/kn-transliteration.js +++ b/lib/jquery.ime/rules/kn/kn-transliteration.js @@ -66,7 +66,6 @@ ['ಸ್h', 'ಶ್'], ['ಶ್h', 'ಷ್'], - ['ಋa', 'ರ'], ['ಋA', 'ರಾ'], ['ಋi', 'ರಿ'], @@ -150,8 +149,6 @@ ['9', '೯'], ['//', 'ಽ']] }; + $.ime.register( knTransliteration ); - }( jQuery ) ); - - diff --git a/lib/jquery.ime/rules/ks/ks-inscript.js b/lib/jquery.ime/rules/ks/ks-inscript.js index 2bf30a51..06bcffe6 100644 --- a/lib/jquery.ime/rules/ks/ks-inscript.js +++ b/lib/jquery.ime/rules/ks/ks-inscript.js @@ -12,7 +12,7 @@ contextLength: 1, maxKeyLength: 3, patterns: [ - ['्d', '्‌'], + ['्d', '्\u200c'], ['ग_', 'ॻ'], ['ज_', 'ॼ'], ['ड_', 'ॾ'], @@ -126,5 +126,4 @@ }; $.ime.register( ksInScript ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ks/ks-kbd.js b/lib/jquery.ime/rules/ks/ks-kbd.js index ab4987ef..4f01b12a 100644 --- a/lib/jquery.ime/rules/ks/ks-kbd.js +++ b/lib/jquery.ime/rules/ks/ks-kbd.js @@ -41,7 +41,7 @@ ['r', 'ر'], ['T', 'ٹ'], ['t', 'ت'], - ['Y', '؁'], + ['Y', '\u0601'], ['y', 'ے'], ['U', '،'], ['u', 'ء'], @@ -109,5 +109,4 @@ }; $.ime.register( ksKbd ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ku/ku-h.js b/lib/jquery.ime/rules/ku/ku-h.js new file mode 100644 index 00000000..f91b4a1b --- /dev/null +++ b/lib/jquery.ime/rules/ku/ku-h.js @@ -0,0 +1,48 @@ +( function ( $ ) { + 'use strict'; + + var kuH = { + id: 'ku-h', + name: 'Ku h', + description: 'writing Kurdish-letters adding h\'s', + date: '2013-06-26', + URL: 'http://github.com/wikimedia/jquery.ime', + author: 'Ghybu', + license: 'GPLv3', + version: '1.0', + contextLength: 1, + patterns: [ + ['çh', 'h', 'ch'], + ['şh', 'h', 'sh'], + ['ḧh', 'h', 'hh'], + ['ẍh', 'h', 'xh'], + ['êe', 'e', 'ee'], + ['îi', 'i', 'ii'], + ['ûu', 'u', 'uu'], + ['Ç(H|h)', '(H|h)', 'C$1'], + ['Ş(H|h)', '(H|h)', 'S$1'], + ['Ḧ(H|h)', '(H|h)', 'H$1'], + ['Ẍ(H|h)', '(H|h)', 'X$1'], + ['Ê(E|e)', '(E|e)', 'E$1'], + ['Î(I|i)', '(I|i)', 'I$1'], + ['Û(U|u)', '(U|u)', 'U$1'], + + ['ch', 'ç'], + ['sh', 'ş'], + ['hh', 'ḧ'], + ['xh', 'ẍ'], + ['ee', 'ê'], + ['ii', 'î'], + ['uu', 'û'], + ['C(H|h)', 'Ç'], + ['S(H|h)', 'Ş'], + ['H(H|h)', 'Ḧ'], + ['X(H|h)', 'Ẍ'], + ['E(E|e)', 'Ê'], + ['I(I|i)', 'Î'], + ['U(U|u)', 'Û']] + }; + + $.ime.register( kuH ); + +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/ku/ku-tr.js b/lib/jquery.ime/rules/ku/ku-tr.js new file mode 100644 index 00000000..d604bc9d --- /dev/null +++ b/lib/jquery.ime/rules/ku/ku-tr.js @@ -0,0 +1,33 @@ +( function ( $ ) { + 'use strict'; + + var kuTr = { + id: 'ku-tr', + name: 'Ku tr', + description: 'writing Kurdish-letters using the TR keyboard', + date: '2013-06-26', + URL: 'http://github.com/wikimedia/jquery.ime', + author: 'Ghybu', + license: 'GPLv3', + version: '1.0', + contextLength: 1, + patterns: [ + ['ḧh', 'h', 'hh'], + ['Ḧ(H|h)', '(H|h)', 'H$1'], + + ['ğ', 'ẍ'], + ['ı', 'i'], + ['i', 'î'], + ['ö', 'ê'], + ['ü', 'û'], + ['hh', 'ḧ'], + ['Ğ', 'Ẍ'], + ['İ', 'Î'], + ['Ö', 'Ê'], + ['Ü', 'Û'], + ['H(H|h)', 'Ḧ']] + }; + + $.ime.register( kuTr ); + +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/ky/ky-cyrl-alt.js b/lib/jquery.ime/rules/ky/ky-cyrl-alt.js new file mode 100644 index 00000000..3a9850a7 --- /dev/null +++ b/lib/jquery.ime/rules/ky/ky-cyrl-alt.js @@ -0,0 +1,25 @@ +( function ( $ ) { + 'use strict'; + + var kyCyrlAlt = { + id: 'ky-cyrl-alt', + name: 'Кыргыз Alt', + description: 'Кыргыз Alt', + date: '2013-08-10', + URL: 'http://github.com/wikimedia/jquery.ime', + author: 'Amir (Алексей) Aharoni', + license: 'GPLv3', + version: '1.0', + patterns: [], + patterns_x: [ + ['н', 'ң'], + ['Н', 'Ң'], + ['о', 'ө'], + ['О', 'Ө'], + ['у', 'ү'], + ['У', 'Ү'] + ] + }; + + $.ime.register( kyCyrlAlt ); +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/lo/lo-kbd.js b/lib/jquery.ime/rules/lo/lo-kbd.js index 093bc82f..081b38b3 100644 --- a/lib/jquery.ime/rules/lo/lo-kbd.js +++ b/lib/jquery.ime/rules/lo/lo-kbd.js @@ -120,4 +120,3 @@ $.ime.register( loKbd ); }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/mai/mai-inscript.js b/lib/jquery.ime/rules/mai/mai-inscript.js index 01b568c2..849f3886 100644 --- a/lib/jquery.ime/rules/mai/mai-inscript.js +++ b/lib/jquery.ime/rules/mai/mai-inscript.js @@ -19,5 +19,4 @@ }; $.ime.register( maithiliInScript ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/mai/mai-inscript2.js b/lib/jquery.ime/rules/mai/mai-inscript2.js index 0e78a572..e228e9e9 100644 --- a/lib/jquery.ime/rules/mai/mai-inscript2.js +++ b/lib/jquery.ime/rules/mai/mai-inscript2.js @@ -22,5 +22,4 @@ }; $.ime.register( maithiliInScript2 ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/mh/mh.js b/lib/jquery.ime/rules/mh/mh.js index 5ff1227b..108dd032 100644 --- a/lib/jquery.ime/rules/mh/mh.js +++ b/lib/jquery.ime/rules/mh/mh.js @@ -40,5 +40,4 @@ }; $.ime.register( mh ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ml/ml-inscript.js b/lib/jquery.ime/rules/ml/ml-inscript.js index 7f181d12..1672f20f 100644 --- a/lib/jquery.ime/rules/ml/ml-inscript.js +++ b/lib/jquery.ime/rules/ml/ml-inscript.js @@ -87,5 +87,4 @@ }; $.ime.register( inscript ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ml/ml-inscript2.js b/lib/jquery.ime/rules/ml/ml-inscript2.js index 6bf67923..9c609485 100644 --- a/lib/jquery.ime/rules/ml/ml-inscript2.js +++ b/lib/jquery.ime/rules/ml/ml-inscript2.js @@ -101,9 +101,9 @@ ['/', 'യ'] ], patterns_x: [ - ['1', '‍'], + ['1', '\u200d'], ['\\!', '൰'], - ['2', '‌'], + ['2', '\u200c'], ['\\@', '൱'], ['\\#', '൲'], ['\\$', '൳'], diff --git a/lib/jquery.ime/rules/ml/ml-transliteration.js b/lib/jquery.ime/rules/ml/ml-transliteration.js index fd62ea14..ee0f803f 100644 --- a/lib/jquery.ime/rules/ml/ml-transliteration.js +++ b/lib/jquery.ime/rules/ml/ml-transliteration.js @@ -1,5 +1,6 @@ ( function ( $ ) { 'use strict'; + var mltransliteration = { id: 'ml-transliteration', name: 'ലിപ്യന്തരണം', @@ -334,5 +335,4 @@ }; $.ime.register( mltransliteration ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/mn/mn-cyrl.js b/lib/jquery.ime/rules/mn/mn-cyrl.js index 65f78cb0..50120b8c 100644 --- a/lib/jquery.ime/rules/mn/mn-cyrl.js +++ b/lib/jquery.ime/rules/mn/mn-cyrl.js @@ -115,5 +115,4 @@ }; $.ime.register( mncyrl ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/mni/mni-inscript2.js b/lib/jquery.ime/rules/mni/mni-inscript2.js index a80b3ba0..2fb463e0 100644 --- a/lib/jquery.ime/rules/mni/mni-inscript2.js +++ b/lib/jquery.ime/rules/mni/mni-inscript2.js @@ -3,7 +3,7 @@ var mniInScript2 = { id: 'mni-inscript2', - name: 'ইন্‌স্ক্ৰিপ্ত ২', + name: 'ইনস্ক্ৰিপ্ট ২', description: 'Enhanced InScript keyboard for Manipuri language using Bengali script', date: '2013-02-13', URL: 'http://github.com/wikimedia/jquery.ime', @@ -96,9 +96,9 @@ ], patterns_x: [ ['\\!', '৴'], - ['1', '‍'], + ['1', '\u200d'], ['\\@', '৵'], - ['2', '‌'], + ['2', '\u200c'], ['\\#', '৶'], ['\\$', '৷'], ['4', '₹'], @@ -122,5 +122,4 @@ }; $.ime.register( mniInScript2 ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/mr/mr-inscript.js b/lib/jquery.ime/rules/mr/mr-inscript.js index 7acbc4a3..fa53aed3 100644 --- a/lib/jquery.ime/rules/mr/mr-inscript.js +++ b/lib/jquery.ime/rules/mr/mr-inscript.js @@ -110,6 +110,6 @@ [',', '\u0970'], ['\\$', '\u20B9']] }; - $.ime.register( mrInScript ); + $.ime.register( mrInScript ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/mr/mr-inscript2.js b/lib/jquery.ime/rules/mr/mr-inscript2.js index 5b0d67a8..9c2dde86 100644 --- a/lib/jquery.ime/rules/mr/mr-inscript2.js +++ b/lib/jquery.ime/rules/mr/mr-inscript2.js @@ -116,6 +116,6 @@ ['\\.', '॥'] ] }; - $.ime.register( mrInScript2 ); + $.ime.register( mrInScript2 ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/mr/mr-phonetic.js b/lib/jquery.ime/rules/mr/mr-phonetic.js index c009d468..975a7fea 100644 --- a/lib/jquery.ime/rules/mr/mr-phonetic.js +++ b/lib/jquery.ime/rules/mr/mr-phonetic.js @@ -4,12 +4,13 @@ var mrPhonetic = { id: 'mr-phonetic', name: 'phonetic', - description: 'Phonetic keyboard for Marathi langauge', + description: 'Phonetic keyboard for Marathi language', date: '2013-02-09', author: 'Parag Nemade', license: 'GPLv3', version: '1.0', patterns: [ + ['्f', '्\u200c'], ['~', 'ऎ'], ['`', 'ॆ'], ['!', 'ऍ'], @@ -101,10 +102,9 @@ ['/', 'ए'], ['\\^', 'ज्ञ'], ['X', 'क्ष'], - ['\\*', 'श्र'], - ['ff', '्‌'] + ['\\*', 'श्र'] ] }; - $.ime.register( mrPhonetic ); + $.ime.register( mrPhonetic ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/mr/mr-transliteration.js b/lib/jquery.ime/rules/mr/mr-transliteration.js index b53b5bc1..db772072 100644 --- a/lib/jquery.ime/rules/mr/mr-transliteration.js +++ b/lib/jquery.ime/rules/mr/mr-transliteration.js @@ -142,7 +142,6 @@ ['\\`', '़'], ['(\u200C)*_', '\u200c']] }; + $.ime.register( mrTransliteration ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/my/my-xkb.js b/lib/jquery.ime/rules/my/my-xkb.js index 78a2dfbe..0eea9f91 100644 --- a/lib/jquery.ime/rules/my/my-xkb.js +++ b/lib/jquery.ime/rules/my/my-xkb.js @@ -204,6 +204,6 @@ ['\\\\', '\\'], ['\\|', '|']] }; - $.ime.register( myXkb ); + $.ime.register( myXkb ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/no/no-normforms.js b/lib/jquery.ime/rules/nb/nb-normforms.js similarity index 95% rename from lib/jquery.ime/rules/no/no-normforms.js rename to lib/jquery.ime/rules/nb/nb-normforms.js index 005602ba..d11751a4 100644 --- a/lib/jquery.ime/rules/no/no-normforms.js +++ b/lib/jquery.ime/rules/nb/nb-normforms.js @@ -2,8 +2,8 @@ 'use strict'; var defs = { - id: 'no-normforms', - name: 'Norsk', + id: 'nb-normforms', + name: 'Norsk normal transliterasjon', description: 'Norwegian input method with most common form transliterated', date: '2012-12-04', URL: 'http://www.evertype.com/alphabets/bokmaal-norwegian.pdf', @@ -47,5 +47,4 @@ }; $.ime.register( defs ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/no/no-tildeforms.js b/lib/jquery.ime/rules/nb/nb-tildeforms.js similarity index 95% rename from lib/jquery.ime/rules/no/no-tildeforms.js rename to lib/jquery.ime/rules/nb/nb-tildeforms.js index ed2885d1..83bdd181 100644 --- a/lib/jquery.ime/rules/no/no-tildeforms.js +++ b/lib/jquery.ime/rules/nb/nb-tildeforms.js @@ -2,8 +2,8 @@ 'use strict'; var defs = { - id: 'no-tildeforms', - name: 'Norsk', + id: 'nb-tildeforms', + name: 'Norsk tildemerket transliterasjon', description: 'Norwegian input method with initial tilde triggering transliteration', date: '2012-12-04', URL: 'http://www.evertype.com/alphabets/bokmaal-norwegian.pdf', @@ -32,5 +32,4 @@ }; $.ime.register( defs ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ne/ne-inscript.js b/lib/jquery.ime/rules/ne/ne-inscript.js index c8819447..1b3d0a7f 100644 --- a/lib/jquery.ime/rules/ne/ne-inscript.js +++ b/lib/jquery.ime/rules/ne/ne-inscript.js @@ -108,6 +108,6 @@ ['\\@', '','ॅ'], ['4', '₹']] }; - $.ime.register( neInScript ); + $.ime.register( neInScript ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ne/ne-inscript2.js b/lib/jquery.ime/rules/ne/ne-inscript2.js index 412017e2..1d1d021f 100644 --- a/lib/jquery.ime/rules/ne/ne-inscript2.js +++ b/lib/jquery.ime/rules/ne/ne-inscript2.js @@ -111,6 +111,6 @@ ['\\>', 'ऽ'], ['\\.', '॥']] }; - $.ime.register( neInScript2 ); + $.ime.register( neInScript2 ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ne/ne-rom.js b/lib/jquery.ime/rules/ne/ne-rom.js index 4c1c8f22..f169dd32 100644 --- a/lib/jquery.ime/rules/ne/ne-rom.js +++ b/lib/jquery.ime/rules/ne/ne-rom.js @@ -103,5 +103,4 @@ }; $.ime.register( neRom ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ne/ne-trad.js b/lib/jquery.ime/rules/ne/ne-trad.js index 6ca41a2a..76af9ea9 100644 --- a/lib/jquery.ime/rules/ne/ne-trad.js +++ b/lib/jquery.ime/rules/ne/ne-trad.js @@ -101,6 +101,6 @@ ['\\[', 'र्'], ['q', 'त्र']] }; - $.ime.register( neTrad ); + $.ime.register( neTrad ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ne/ne-transliteration.js b/lib/jquery.ime/rules/ne/ne-transliteration.js index c3cabaef..3c08b107 100644 --- a/lib/jquery.ime/rules/ne/ne-transliteration.js +++ b/lib/jquery.ime/rules/ne/ne-transliteration.js @@ -160,7 +160,6 @@ ['//','ऽ'], ['\\`','्']] }; + $.ime.register( neTransliteration ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/or/or-inscript.js b/lib/jquery.ime/rules/or/or-inscript.js index d533978a..b6ea0218 100644 --- a/lib/jquery.ime/rules/or/or-inscript.js +++ b/lib/jquery.ime/rules/or/or-inscript.js @@ -103,5 +103,4 @@ }; $.ime.register( orInScript ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/or/or-inscript2.js b/lib/jquery.ime/rules/or/or-inscript2.js index 12a58e57..fcc2fec3 100644 --- a/lib/jquery.ime/rules/or/or-inscript2.js +++ b/lib/jquery.ime/rules/or/or-inscript2.js @@ -95,8 +95,8 @@ ['\\*', 'ଶ୍ର'] ], patterns_x: [ - ['1', '‍'], - ['2', '‌'], + ['1', '\u200d'], + ['2', '\u200c'], ['4', '₹'], ['\\+', 'ୠ'], ['\\=', 'ୄ'], @@ -113,5 +113,4 @@ }; $.ime.register( orInScript2 ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/or/or-lekhani.js b/lib/jquery.ime/rules/or/or-lekhani.js index dbdc3f7c..9cea79ca 100644 --- a/lib/jquery.ime/rules/or/or-lekhani.js +++ b/lib/jquery.ime/rules/or/or-lekhani.js @@ -94,10 +94,8 @@ ['ତt', 'ତ୍ତ'], // tt ['ଲl', 'ଲ୍ଲ'], // ll ['ପp', 'ପ୍ପ'], //pp - [ '\\[', '\u200c' ], [ '_', '\u200c' ], - ['ଆ\\\\', '\u0B3E'], // aa sign ['ଇ\\\\', '\u0B3F'], // i sign ['ଈ\\\\', '\u0B40'],// I sign diff --git a/lib/jquery.ime/rules/or/or-phonetic.js b/lib/jquery.ime/rules/or/or-phonetic.js index 5ec9e018..3861ffd2 100644 --- a/lib/jquery.ime/rules/or/or-phonetic.js +++ b/lib/jquery.ime/rules/or/or-phonetic.js @@ -107,5 +107,4 @@ }; $.ime.register( orPhonetic ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/or/or-transliteration.js b/lib/jquery.ime/rules/or/or-transliteration.js index 541535fb..866a59d0 100644 --- a/lib/jquery.ime/rules/or/or-transliteration.js +++ b/lib/jquery.ime/rules/or/or-transliteration.js @@ -3,7 +3,8 @@ var orTransliteration = { id: 'or-transliteration', - name: 'ଟ୍ରାନ୍ସଲିଟରେସନ', + name: 'ଟ୍ରାନ୍ସଲିଟରେସନ', + description: 'Odia Transliteration', date: '2012-10-14', URL: 'http://github.com/wikimedia/jquery.ime', @@ -143,5 +144,4 @@ }; $.ime.register( orTransliteration ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/pa/pa-inscript.js b/lib/jquery.ime/rules/pa/pa-inscript.js index 252d626f..bd503494 100644 --- a/lib/jquery.ime/rules/pa/pa-inscript.js +++ b/lib/jquery.ime/rules/pa/pa-inscript.js @@ -92,6 +92,6 @@ ['/', 'ਯ']] }; - $.ime.register( paInScript ); + $.ime.register( paInScript ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/pa/pa-inscript2.js b/lib/jquery.ime/rules/pa/pa-inscript2.js index 1a398bc9..2c49a06b 100644 --- a/lib/jquery.ime/rules/pa/pa-inscript2.js +++ b/lib/jquery.ime/rules/pa/pa-inscript2.js @@ -87,8 +87,8 @@ ['/', 'ਯ'] ], patterns_x: [ - ['1', '‍'], - ['2', '‌'], + ['1', '\u200d'], + ['2', '\u200c'], ['4', '₹'], ['i', 'ਗ਼'], ['p', 'ਜ਼'], @@ -106,6 +106,6 @@ ['/', 'ੵ'] ] }; - $.ime.register( paInScript2 ); + $.ime.register( paInScript2 ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/pa/pa-phonetic.js b/lib/jquery.ime/rules/pa/pa-phonetic.js index 602ca599..e97f558b 100644 --- a/lib/jquery.ime/rules/pa/pa-phonetic.js +++ b/lib/jquery.ime/rules/pa/pa-phonetic.js @@ -94,7 +94,6 @@ ['H', '੍ਹ'], ['W', 'ਾਂ']] }; + $.ime.register( paPhonetic ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/pa/pa-transliteration.js b/lib/jquery.ime/rules/pa/pa-transliteration.js index e47b8357..af5b4fc6 100644 --- a/lib/jquery.ime/rules/pa/pa-transliteration.js +++ b/lib/jquery.ime/rules/pa/pa-transliteration.js @@ -114,7 +114,6 @@ ['।\\.', '॥'], // Double danda, must be before single danda ['\\.', '।']] // Danda }; + $.ime.register( paTransliteration ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/ru/ru-jcuken.js b/lib/jquery.ime/rules/ru/ru-jcuken.js index e8feec2f..5206cba0 100644 --- a/lib/jquery.ime/rules/ru/ru-jcuken.js +++ b/lib/jquery.ime/rules/ru/ru-jcuken.js @@ -91,6 +91,6 @@ ['&', '?']] // 7 // '*', '(' and ')' are the same // 8, 9, 0 }; - $.ime.register( ruJcuken ); + $.ime.register( ruJcuken ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ru/ru-kbd.js b/lib/jquery.ime/rules/ru/ru-kbd.js index 0217fe0f..f2d2bc0b 100644 --- a/lib/jquery.ime/rules/ru/ru-kbd.js +++ b/lib/jquery.ime/rules/ru/ru-kbd.js @@ -95,6 +95,6 @@ ['\\?', ','] ] }; - $.ime.register( ruKbd ); + $.ime.register( ruKbd ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ru/ru-phonetic.js b/lib/jquery.ime/rules/ru/ru-phonetic.js index 5c37b04d..c99e964d 100644 --- a/lib/jquery.ime/rules/ru/ru-phonetic.js +++ b/lib/jquery.ime/rules/ru/ru-phonetic.js @@ -78,7 +78,6 @@ ['m', 'м'], ['M', 'М']] }; + $.ime.register( ruPhonetic ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/ru/ru-yawerty.js b/lib/jquery.ime/rules/ru/ru-yawerty.js index f48ebf29..5ba0c775 100644 --- a/lib/jquery.ime/rules/ru/ru-yawerty.js +++ b/lib/jquery.ime/rules/ru/ru-yawerty.js @@ -104,7 +104,6 @@ ['N', 'Н'], ['M', 'М']] }; + $.ime.register( ruYawerty ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/sa/sa-iast.js b/lib/jquery.ime/rules/sa/sa-iast.js index 9a22b413..e8e919fa 100644 --- a/lib/jquery.ime/rules/sa/sa-iast.js +++ b/lib/jquery.ime/rules/sa/sa-iast.js @@ -54,6 +54,6 @@ ['r̥r', 'r̥̄'] ] }; - $.ime.register( saIast ); + $.ime.register( saIast ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/sa/sa-inscript.js b/lib/jquery.ime/rules/sa/sa-inscript.js index f8c70039..b919f951 100644 --- a/lib/jquery.ime/rules/sa/sa-inscript.js +++ b/lib/jquery.ime/rules/sa/sa-inscript.js @@ -108,6 +108,6 @@ ['4', '₹']] }; - $.ime.register( saInScript ); + $.ime.register( saInScript ); }( jQuery ) ); diff --git a/lib/jquery.ime/rules/sa/sa-transliteration.js b/lib/jquery.ime/rules/sa/sa-transliteration.js index a0360d33..fda8eaba 100644 --- a/lib/jquery.ime/rules/sa/sa-transliteration.js +++ b/lib/jquery.ime/rules/sa/sa-transliteration.js @@ -160,7 +160,6 @@ ['\\`','़'], ['(\u200C)*_', '\u200c']] }; + $.ime.register( saTransliteration ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/sah/sah-transliteration.js b/lib/jquery.ime/rules/sah/sah-transliteration.js index a8d3dbb9..235ac3c3 100644 --- a/lib/jquery.ime/rules/sah/sah-transliteration.js +++ b/lib/jquery.ime/rules/sah/sah-transliteration.js @@ -98,7 +98,6 @@ ['9', ';'], // 9 ['0', ':']] // 0 }; + $.ime.register( sahTransliteration ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/si/si-singlish.js b/lib/jquery.ime/rules/si/si-singlish.js index 8b4467e6..8ba93b1d 100644 --- a/lib/jquery.ime/rules/si/si-singlish.js +++ b/lib/jquery.ime/rules/si/si-singlish.js @@ -105,7 +105,6 @@ ['p', 'ප්'], ['L', 'ළ්']] }; + $.ime.register( siSinglish ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/si/si-wijesekara.js b/lib/jquery.ime/rules/si/si-wijesekara.js index 2cdd4095..32f2d852 100644 --- a/lib/jquery.ime/rules/si/si-wijesekara.js +++ b/lib/jquery.ime/rules/si/si-wijesekara.js @@ -100,7 +100,6 @@ ['x', 'ඦ'], [',', 'ඏ']] }; + $.ime.register( siWijesekara ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/sk/sk-kbd.js b/lib/jquery.ime/rules/sk/sk-kbd.js index 3eef7c2e..a8278c04 100644 --- a/lib/jquery.ime/rules/sk/sk-kbd.js +++ b/lib/jquery.ime/rules/sk/sk-kbd.js @@ -100,7 +100,6 @@ ['=', '¨'] ] }; + $.ime.register( skKbd ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/sv/sv-normforms.js b/lib/jquery.ime/rules/sv/sv-normforms.js index aed223da..0f111d9e 100644 --- a/lib/jquery.ime/rules/sv/sv-normforms.js +++ b/lib/jquery.ime/rules/sv/sv-normforms.js @@ -47,5 +47,4 @@ }; $.ime.register( defs ); - -}( jQuery ) ); \ No newline at end of file +}( jQuery ) ); diff --git a/lib/jquery.ime/rules/ta/ta-99.js b/lib/jquery.ime/rules/ta/ta-99.js index 3ce35f12..c22dfab8 100644 --- a/lib/jquery.ime/rules/ta/ta-99.js +++ b/lib/jquery.ime/rules/ta/ta-99.js @@ -190,5 +190,4 @@ }; $.ime.register( ta99 ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ta/ta-bamini.js b/lib/jquery.ime/rules/ta/ta-bamini.js index c527a8c6..500e729d 100644 --- a/lib/jquery.ime/rules/ta/ta-bamini.js +++ b/lib/jquery.ime/rules/ta/ta-bamini.js @@ -87,5 +87,4 @@ [ '([ஜஷஸஹ])\\_', '$1ூ' ] ] }; $.ime.register( taBamini ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ta/ta-inscript.js b/lib/jquery.ime/rules/ta/ta-inscript.js index 8d157124..f3a3ee91 100644 --- a/lib/jquery.ime/rules/ta/ta-inscript.js +++ b/lib/jquery.ime/rules/ta/ta-inscript.js @@ -100,5 +100,4 @@ [ '4', '₹' ] ] }; $.ime.register( taInScript ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/ta/ta-inscript2.js b/lib/jquery.ime/rules/ta/ta-inscript2.js index 64279a99..c616470d 100644 --- a/lib/jquery.ime/rules/ta/ta-inscript2.js +++ b/lib/jquery.ime/rules/ta/ta-inscript2.js @@ -84,8 +84,8 @@ ['/', 'ய'] ], patterns_x: [ - ['1', '‍'], - ['2', '‌'], + ['1', '\u200d'], + ['2', '\u200c'], ['4', '₹'], ['0', '௰'], ['\\-', '௱'], diff --git a/lib/jquery.ime/rules/ta/ta-transliteration.js b/lib/jquery.ime/rules/ta/ta-transliteration.js index b9566c9e..a000d5af 100644 --- a/lib/jquery.ime/rules/ta/ta-transliteration.js +++ b/lib/jquery.ime/rules/ta/ta-transliteration.js @@ -117,5 +117,4 @@ }; $.ime.register( taTransliteration ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/te/te-inscript.js b/lib/jquery.ime/rules/te/te-inscript.js index 4ef59ba1..4c663717 100644 --- a/lib/jquery.ime/rules/te/te-inscript.js +++ b/lib/jquery.ime/rules/te/te-inscript.js @@ -3,7 +3,7 @@ var teInScript = { id: 'te-inscript', - name: 'ఇన్‍స్క్రిప్ట్', + name: 'ఇన్\u200dస్క్రిప్ట్', description: 'Inscript keyboard for Telugu script', date: '2012-10-16', author: 'Veeven', @@ -119,5 +119,4 @@ ['\\+', 'ౠ']] }; $.ime.register( teInScript ); - }( jQuery ) ); diff --git a/lib/jquery.ime/rules/te/te-inscript2.js b/lib/jquery.ime/rules/te/te-inscript2.js index a312e1c5..4cb75116 100644 --- a/lib/jquery.ime/rules/te/te-inscript2.js +++ b/lib/jquery.ime/rules/te/te-inscript2.js @@ -3,7 +3,7 @@ var teInScript2 = { id: 'te-inscript2', - name: 'ఇన్‍స్క్రిప్ట్ 2', + name: 'ఇన్\u200dస్క్రిప్ట్ 2', description: 'Enhanced InScript keyboard for Telugu script', date: '2013-01-16', author: 'Parag Nemade', @@ -103,8 +103,8 @@ ['4', '₹'], ['\\%', '౻'], ['\\^', '౾'], - ['1', '‍'], - ['2', '‌'], + ['1', '\u200d'], + ['2', '\u200c'], ['0', '౸'], ['\\-', '౿'], ['\\+', 'ౠ'], diff --git a/lib/jquery.ime/rules/te/te-transliteration.js b/lib/jquery.ime/rules/te/te-transliteration.js index 3780352f..7fc547ed 100644 --- a/lib/jquery.ime/rules/te/te-transliteration.js +++ b/lib/jquery.ime/rules/te/te-transliteration.js @@ -217,6 +217,4 @@ ['~\\$', '₹']] // rupee }; $.ime.register( teTransliteration ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/udm/udm-alt.js b/lib/jquery.ime/rules/udm/udm-alt.js index 71a1c29f..cd330101 100644 --- a/lib/jquery.ime/rules/udm/udm-alt.js +++ b/lib/jquery.ime/rules/udm/udm-alt.js @@ -38,4 +38,3 @@ }; $.ime.register( udmAlt ); }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/ug/ug-kbd.js b/lib/jquery.ime/rules/ug/ug-kbd.js index 3dd8b699..9bcdaedf 100644 --- a/lib/jquery.ime/rules/ug/ug-kbd.js +++ b/lib/jquery.ime/rules/ug/ug-kbd.js @@ -75,6 +75,4 @@ ] }; $.ime.register( ugKbd ); - }( jQuery ) ); - diff --git a/lib/jquery.ime/rules/ur/ur-phonetic.js b/lib/jquery.ime/rules/ur/ur-phonetic.js index 2c3d3425..67dccb27 100644 --- a/lib/jquery.ime/rules/ur/ur-phonetic.js +++ b/lib/jquery.ime/rules/ur/ur-phonetic.js @@ -6,17 +6,17 @@ name: 'صوتی', description: 'Phonetic keyboard for Urdu script', date: '2013-02-18', + URL: 'http://cvs.savannah.gnu.org/viewvc/m17n-contrib/im/ur-phonetic.mim?root=m17n&view=markup', author: 'Parag Nemade', license: 'GPLv3', version: '1.0', patterns: [ ['!', '!'], ['1', '۱'], - ['\\@', ''], ['2', '۲'], ['\\#', '/'], ['3', '۳'], - ['\\$', 'ئ'], + /* Yeh with hamza above */ ['\\$', 'ئ'], ['4', '۴'], ['5', '۵'], ['6', '۶'], @@ -27,9 +27,9 @@ ['\\)', '('], ['0', '۰'], ['\\_" "ّ'], - ['\\-', 'أ'], - ['\\+', 'آ'], - ['\\=', 'ؤ'], + /* Alef with hamza above */ ['\\-', 'أ'], + /* Alef with madda above */ ['\\+', 'آ'], + /* Waw with hamza above */ ['\\=', 'ؤ'], ['Q', 'ْ'], ['q', 'ق'], ['W', 'ﷺ'], @@ -40,13 +40,13 @@ ['r', 'ر'], ['T', 'ٹ'], ['t', 'ت'], - ['Y', '؁'], + ['Y', '\u0601'], ['y', 'ے'], ['U', '،'], ['u', 'ء'], ['I', 'ٰ'], ['i', 'ی'], - ['O', 'ۃ'], + ['O', 'ۃ'], // Teh marbuta goal ['o', 'ہ'], ['P', 'ُ'], ['p', 'پ'], @@ -70,10 +70,10 @@ ['j', 'ج'], ['K', 'خ'], ['k', 'ک'], - ['L', 'ؓ'], + ['L', '\u0613'], ['l', 'ل'], [':', ':'], - [';', '؛'], + /* Arabic semicolon */ [';', '؛'], ['\"', '؎'], ['\'', 'ٰ'], ['\\|', 'ؔ'], @@ -97,10 +97,8 @@ ['\\<', 'ِ'], [',', '،'], ['\\>', 'َ'], - ['\\.', '۔'], - ['\\?', '؟'], - ['////', ''], - ['\\%', ''], + /* Arabic full stop */ ['\\.', '۔'], + /* Arabic question mark */ ['\\?', '؟'], ['\\^', 'ۖ'], ['\\&', 'ٔ'], ['\\*', 'ٌ']] diff --git a/lib/jquery.ime/rules/ur/ur-transliteration.js b/lib/jquery.ime/rules/ur/ur-transliteration.js index 5fa6b945..593a5f3c 100644 --- a/lib/jquery.ime/rules/ur/ur-transliteration.js +++ b/lib/jquery.ime/rules/ur/ur-transliteration.js @@ -94,6 +94,4 @@ ['\\)', ')']] }; $.ime.register( urTransliteration ); - }( jQuery ) ); - diff --git a/lib/rangy/rangy-core.js b/lib/rangy/rangy-core.js new file mode 100644 index 00000000..8cda5f68 --- /dev/null +++ b/lib/rangy/rangy-core.js @@ -0,0 +1,3224 @@ +/** + * @license Rangy, a cross-browser JavaScript range and selection library + * http://code.google.com/p/rangy/ + * + * Copyright 2012, Tim Down + * Licensed under the MIT license. + * Version: 1.2.3 + * Build date: 26 February 2012 + */ +window['rangy'] = (function() { + + + var OBJECT = "object", FUNCTION = "function", UNDEFINED = "undefined"; + + var domRangeProperties = ["startContainer", "startOffset", "endContainer", "endOffset", "collapsed", + "commonAncestorContainer", "START_TO_START", "START_TO_END", "END_TO_START", "END_TO_END"]; + + var domRangeMethods = ["setStart", "setStartBefore", "setStartAfter", "setEnd", "setEndBefore", + "setEndAfter", "collapse", "selectNode", "selectNodeContents", "compareBoundaryPoints", "deleteContents", + "extractContents", "cloneContents", "insertNode", "surroundContents", "cloneRange", "toString", "detach"]; + + var textRangeProperties = ["boundingHeight", "boundingLeft", "boundingTop", "boundingWidth", "htmlText", "text"]; + + // Subset of TextRange's full set of methods that we're interested in + var textRangeMethods = ["collapse", "compareEndPoints", "duplicate", "getBookmark", "moveToBookmark", + "moveToElementText", "parentElement", "pasteHTML", "select", "setEndPoint", "getBoundingClientRect"]; + + /*----------------------------------------------------------------------------------------------------------------*/ + + // Trio of functions taken from Peter Michaux's article: + // http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting + function isHostMethod(o, p) { + var t = typeof o[p]; + return t == FUNCTION || (!!(t == OBJECT && o[p])) || t == "unknown"; + } + + function isHostObject(o, p) { + return !!(typeof o[p] == OBJECT && o[p]); + } + + function isHostProperty(o, p) { + return typeof o[p] != UNDEFINED; + } + + // Creates a convenience function to save verbose repeated calls to tests functions + function createMultiplePropertyTest(testFunc) { + return function(o, props) { + var i = props.length; + while (i--) { + if (!testFunc(o, props[i])) { + return false; + } + } + return true; + }; + } + + // Next trio of functions are a convenience to save verbose repeated calls to previous two functions + var areHostMethods = createMultiplePropertyTest(isHostMethod); + var areHostObjects = createMultiplePropertyTest(isHostObject); + var areHostProperties = createMultiplePropertyTest(isHostProperty); + + function isTextRange(range) { + return range && areHostMethods(range, textRangeMethods) && areHostProperties(range, textRangeProperties); + } + + var api = { + version: "1.2.3", + initialized: false, + supported: true, + + util: { + isHostMethod: isHostMethod, + isHostObject: isHostObject, + isHostProperty: isHostProperty, + areHostMethods: areHostMethods, + areHostObjects: areHostObjects, + areHostProperties: areHostProperties, + isTextRange: isTextRange + }, + + features: {}, + + modules: {}, + config: { + alertOnWarn: false, + preferTextRange: false + } + }; + + function fail(reason) { + window.alert("Rangy not supported in your browser. Reason: " + reason); + api.initialized = true; + api.supported = false; + } + + api.fail = fail; + + function warn(msg) { + var warningMessage = "Rangy warning: " + msg; + if (api.config.alertOnWarn) { + window.alert(warningMessage); + } else if (typeof window.console != UNDEFINED && typeof window.console.log != UNDEFINED) { + window.console.log(warningMessage); + } + } + + api.warn = warn; + + if ({}.hasOwnProperty) { + api.util.extend = function(o, props) { + for (var i in props) { + if (props.hasOwnProperty(i)) { + o[i] = props[i]; + } + } + }; + } else { + fail("hasOwnProperty not supported"); + } + + var initListeners = []; + var moduleInitializers = []; + + // Initialization + function init() { + if (api.initialized) { + return; + } + var testRange; + var implementsDomRange = false, implementsTextRange = false; + + // First, perform basic feature tests + + if (isHostMethod(document, "createRange")) { + testRange = document.createRange(); + if (areHostMethods(testRange, domRangeMethods) && areHostProperties(testRange, domRangeProperties)) { + implementsDomRange = true; + } + testRange.detach(); + } + + var body = isHostObject(document, "body") ? document.body : document.getElementsByTagName("body")[0]; + + if (body && isHostMethod(body, "createTextRange")) { + testRange = body.createTextRange(); + if (isTextRange(testRange)) { + implementsTextRange = true; + } + } + + if (!implementsDomRange && !implementsTextRange) { + fail("Neither Range nor TextRange are implemented"); + } + + api.initialized = true; + api.features = { + implementsDomRange: implementsDomRange, + implementsTextRange: implementsTextRange + }; + + // Initialize modules and call init listeners + var allListeners = moduleInitializers.concat(initListeners); + for (var i = 0, len = allListeners.length; i < len; ++i) { + try { + allListeners[i](api); + } catch (ex) { + if (isHostObject(window, "console") && isHostMethod(window.console, "log")) { + window.console.log("Init listener threw an exception. Continuing.", ex); + } + + } + } + } + + // Allow external scripts to initialize this library in case it's loaded after the document has loaded + api.init = init; + + // Execute listener immediately if already initialized + api.addInitListener = function(listener) { + if (api.initialized) { + listener(api); + } else { + initListeners.push(listener); + } + }; + + var createMissingNativeApiListeners = []; + + api.addCreateMissingNativeApiListener = function(listener) { + createMissingNativeApiListeners.push(listener); + }; + + function createMissingNativeApi(win) { + win = win || window; + init(); + + // Notify listeners + for (var i = 0, len = createMissingNativeApiListeners.length; i < len; ++i) { + createMissingNativeApiListeners[i](win); + } + } + + api.createMissingNativeApi = createMissingNativeApi; + + /** + * @constructor + */ + function Module(name) { + this.name = name; + this.initialized = false; + this.supported = false; + } + + Module.prototype.fail = function(reason) { + this.initialized = true; + this.supported = false; + + throw new Error("Module '" + this.name + "' failed to load: " + reason); + }; + + Module.prototype.warn = function(msg) { + api.warn("Module " + this.name + ": " + msg); + }; + + Module.prototype.createError = function(msg) { + return new Error("Error in Rangy " + this.name + " module: " + msg); + }; + + api.createModule = function(name, initFunc) { + var module = new Module(name); + api.modules[name] = module; + + moduleInitializers.push(function(api) { + initFunc(api, module); + module.initialized = true; + module.supported = true; + }); + }; + + api.requireModules = function(modules) { + for (var i = 0, len = modules.length, module, moduleName; i < len; ++i) { + moduleName = modules[i]; + module = api.modules[moduleName]; + if (!module || !(module instanceof Module)) { + throw new Error("Module '" + moduleName + "' not found"); + } + if (!module.supported) { + throw new Error("Module '" + moduleName + "' not supported"); + } + } + }; + + /*----------------------------------------------------------------------------------------------------------------*/ + + // Wait for document to load before running tests + + var docReady = false; + + var loadHandler = function(e) { + + if (!docReady) { + docReady = true; + if (!api.initialized) { + init(); + } + } + }; + + // Test whether we have window and document objects that we will need + if (typeof window == UNDEFINED) { + fail("No window found"); + return; + } + if (typeof document == UNDEFINED) { + fail("No document found"); + return; + } + + if (isHostMethod(document, "addEventListener")) { + document.addEventListener("DOMContentLoaded", loadHandler, false); + } + + // Add a fallback in case the DOMContentLoaded event isn't supported + if (isHostMethod(window, "addEventListener")) { + window.addEventListener("load", loadHandler, false); + } else if (isHostMethod(window, "attachEvent")) { + window.attachEvent("onload", loadHandler); + } else { + fail("Window does not have required addEventListener or attachEvent method"); + } + + return api; +})(); +rangy.createModule("DomUtil", function(api, module) { + + var UNDEF = "undefined"; + var util = api.util; + + // Perform feature tests + if (!util.areHostMethods(document, ["createDocumentFragment", "createElement", "createTextNode"])) { + module.fail("document missing a Node creation method"); + } + + if (!util.isHostMethod(document, "getElementsByTagName")) { + module.fail("document missing getElementsByTagName method"); + } + + var el = document.createElement("div"); + if (!util.areHostMethods(el, ["insertBefore", "appendChild", "cloneNode"] || + !util.areHostObjects(el, ["previousSibling", "nextSibling", "childNodes", "parentNode"]))) { + module.fail("Incomplete Element implementation"); + } + + // innerHTML is required for Range's createContextualFragment method + if (!util.isHostProperty(el, "innerHTML")) { + module.fail("Element is missing innerHTML property"); + } + + var textNode = document.createTextNode("test"); + if (!util.areHostMethods(textNode, ["splitText", "deleteData", "insertData", "appendData", "cloneNode"] || + !util.areHostObjects(el, ["previousSibling", "nextSibling", "childNodes", "parentNode"]) || + !util.areHostProperties(textNode, ["data"]))) { + module.fail("Incomplete Text Node implementation"); + } + + /*----------------------------------------------------------------------------------------------------------------*/ + + // Removed use of indexOf because of a bizarre bug in Opera that is thrown in one of the Acid3 tests. I haven't been + // able to replicate it outside of the test. The bug is that indexOf returns -1 when called on an Array that + // contains just the document as a single element and the value searched for is the document. + var arrayContains = /*Array.prototype.indexOf ? + function(arr, val) { + return arr.indexOf(val) > -1; + }:*/ + + function(arr, val) { + var i = arr.length; + while (i--) { + if (arr[i] === val) { + return true; + } + } + return false; + }; + + // Opera 11 puts HTML elements in the null namespace, it seems, and IE 7 has undefined namespaceURI + function isHtmlNamespace(node) { + var ns; + return typeof node.namespaceURI == UNDEF || ((ns = node.namespaceURI) === null || ns == "http://www.w3.org/1999/xhtml"); + } + + function parentElement(node) { + var parent = node.parentNode; + return (parent.nodeType == 1) ? parent : null; + } + + function getNodeIndex(node) { + var i = 0; + while( (node = node.previousSibling) ) { + i++; + } + return i; + } + + function getNodeLength(node) { + var childNodes; + return isCharacterDataNode(node) ? node.length : ((childNodes = node.childNodes) ? childNodes.length : 0); + } + + function getCommonAncestor(node1, node2) { + var ancestors = [], n; + for (n = node1; n; n = n.parentNode) { + ancestors.push(n); + } + + for (n = node2; n; n = n.parentNode) { + if (arrayContains(ancestors, n)) { + return n; + } + } + + return null; + } + + function isAncestorOf(ancestor, descendant, selfIsAncestor) { + var n = selfIsAncestor ? descendant : descendant.parentNode; + while (n) { + if (n === ancestor) { + return true; + } else { + n = n.parentNode; + } + } + return false; + } + + function getClosestAncestorIn(node, ancestor, selfIsAncestor) { + var p, n = selfIsAncestor ? node : node.parentNode; + while (n) { + p = n.parentNode; + if (p === ancestor) { + return n; + } + n = p; + } + return null; + } + + function isCharacterDataNode(node) { + var t = node.nodeType; + return t == 3 || t == 4 || t == 8 ; // Text, CDataSection or Comment + } + + function insertAfter(node, precedingNode) { + var nextNode = precedingNode.nextSibling, parent = precedingNode.parentNode; + if (nextNode) { + parent.insertBefore(node, nextNode); + } else { + parent.appendChild(node); + } + return node; + } + + // Note that we cannot use splitText() because it is bugridden in IE 9. + function splitDataNode(node, index) { + var newNode = node.cloneNode(false); + newNode.deleteData(0, index); + node.deleteData(index, node.length - index); + insertAfter(newNode, node); + return newNode; + } + + function getDocument(node) { + if (node.nodeType == 9) { + return node; + } else if (typeof node.ownerDocument != UNDEF) { + return node.ownerDocument; + } else if (typeof node.document != UNDEF) { + return node.document; + } else if (node.parentNode) { + return getDocument(node.parentNode); + } else { + throw new Error("getDocument: no document found for node"); + } + } + + function getWindow(node) { + var doc = getDocument(node); + if (typeof doc.defaultView != UNDEF) { + return doc.defaultView; + } else if (typeof doc.parentWindow != UNDEF) { + return doc.parentWindow; + } else { + throw new Error("Cannot get a window object for node"); + } + } + + function getIframeDocument(iframeEl) { + if (typeof iframeEl.contentDocument != UNDEF) { + return iframeEl.contentDocument; + } else if (typeof iframeEl.contentWindow != UNDEF) { + return iframeEl.contentWindow.document; + } else { + throw new Error("getIframeWindow: No Document object found for iframe element"); + } + } + + function getIframeWindow(iframeEl) { + if (typeof iframeEl.contentWindow != UNDEF) { + return iframeEl.contentWindow; + } else if (typeof iframeEl.contentDocument != UNDEF) { + return iframeEl.contentDocument.defaultView; + } else { + throw new Error("getIframeWindow: No Window object found for iframe element"); + } + } + + function getBody(doc) { + return util.isHostObject(doc, "body") ? doc.body : doc.getElementsByTagName("body")[0]; + } + + function getRootContainer(node) { + var parent; + while ( (parent = node.parentNode) ) { + node = parent; + } + return node; + } + + function comparePoints(nodeA, offsetA, nodeB, offsetB) { + // See http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Comparing + var nodeC, root, childA, childB, n; + if (nodeA == nodeB) { + + // Case 1: nodes are the same + return offsetA === offsetB ? 0 : (offsetA < offsetB) ? -1 : 1; + } else if ( (nodeC = getClosestAncestorIn(nodeB, nodeA, true)) ) { + + // Case 2: node C (container B or an ancestor) is a child node of A + return offsetA <= getNodeIndex(nodeC) ? -1 : 1; + } else if ( (nodeC = getClosestAncestorIn(nodeA, nodeB, true)) ) { + + // Case 3: node C (container A or an ancestor) is a child node of B + return getNodeIndex(nodeC) < offsetB ? -1 : 1; + } else { + + // Case 4: containers are siblings or descendants of siblings + root = getCommonAncestor(nodeA, nodeB); + childA = (nodeA === root) ? root : getClosestAncestorIn(nodeA, root, true); + childB = (nodeB === root) ? root : getClosestAncestorIn(nodeB, root, true); + + if (childA === childB) { + // This shouldn't be possible + + throw new Error("comparePoints got to case 4 and childA and childB are the same!"); + } else { + n = root.firstChild; + while (n) { + if (n === childA) { + return -1; + } else if (n === childB) { + return 1; + } + n = n.nextSibling; + } + throw new Error("Should not be here!"); + } + } + } + + function fragmentFromNodeChildren(node) { + var fragment = getDocument(node).createDocumentFragment(), child; + while ( (child = node.firstChild) ) { + fragment.appendChild(child); + } + return fragment; + } + + function inspectNode(node) { + if (!node) { + return "[No node]"; + } + if (isCharacterDataNode(node)) { + return '"' + node.data + '"'; + } else if (node.nodeType == 1) { + var idAttr = node.id ? ' id="' + node.id + '"' : ""; + return "<" + node.nodeName + idAttr + ">[" + node.childNodes.length + "]"; + } else { + return node.nodeName; + } + } + + /** + * @constructor + */ + function NodeIterator(root) { + this.root = root; + this._next = root; + } + + NodeIterator.prototype = { + _current: null, + + hasNext: function() { + return !!this._next; + }, + + next: function() { + var n = this._current = this._next; + var child, next; + if (this._current) { + child = n.firstChild; + if (child) { + this._next = child; + } else { + next = null; + while ((n !== this.root) && !(next = n.nextSibling)) { + n = n.parentNode; + } + this._next = next; + } + } + return this._current; + }, + + detach: function() { + this._current = this._next = this.root = null; + } + }; + + function createIterator(root) { + return new NodeIterator(root); + } + + /** + * @constructor + */ + function DomPosition(node, offset) { + this.node = node; + this.offset = offset; + } + + DomPosition.prototype = { + equals: function(pos) { + return this.node === pos.node & this.offset == pos.offset; + }, + + inspect: function() { + return "[DomPosition(" + inspectNode(this.node) + ":" + this.offset + ")]"; + } + }; + + /** + * @constructor + */ + function DOMException(codeName) { + this.code = this[codeName]; + this.codeName = codeName; + this.message = "DOMException: " + this.codeName; + } + + DOMException.prototype = { + INDEX_SIZE_ERR: 1, + HIERARCHY_REQUEST_ERR: 3, + WRONG_DOCUMENT_ERR: 4, + NO_MODIFICATION_ALLOWED_ERR: 7, + NOT_FOUND_ERR: 8, + NOT_SUPPORTED_ERR: 9, + INVALID_STATE_ERR: 11 + }; + + DOMException.prototype.toString = function() { + return this.message; + }; + + api.dom = { + arrayContains: arrayContains, + isHtmlNamespace: isHtmlNamespace, + parentElement: parentElement, + getNodeIndex: getNodeIndex, + getNodeLength: getNodeLength, + getCommonAncestor: getCommonAncestor, + isAncestorOf: isAncestorOf, + getClosestAncestorIn: getClosestAncestorIn, + isCharacterDataNode: isCharacterDataNode, + insertAfter: insertAfter, + splitDataNode: splitDataNode, + getDocument: getDocument, + getWindow: getWindow, + getIframeWindow: getIframeWindow, + getIframeDocument: getIframeDocument, + getBody: getBody, + getRootContainer: getRootContainer, + comparePoints: comparePoints, + inspectNode: inspectNode, + fragmentFromNodeChildren: fragmentFromNodeChildren, + createIterator: createIterator, + DomPosition: DomPosition + }; + + api.DOMException = DOMException; +});rangy.createModule("DomRange", function(api, module) { + api.requireModules( ["DomUtil"] ); + + + var dom = api.dom; + var DomPosition = dom.DomPosition; + var DOMException = api.DOMException; + + /*----------------------------------------------------------------------------------------------------------------*/ + + // Utility functions + + function isNonTextPartiallySelected(node, range) { + return (node.nodeType != 3) && + (dom.isAncestorOf(node, range.startContainer, true) || dom.isAncestorOf(node, range.endContainer, true)); + } + + function getRangeDocument(range) { + return dom.getDocument(range.startContainer); + } + + function dispatchEvent(range, type, args) { + var listeners = range._listeners[type]; + if (listeners) { + for (var i = 0, len = listeners.length; i < len; ++i) { + listeners[i].call(range, {target: range, args: args}); + } + } + } + + function getBoundaryBeforeNode(node) { + return new DomPosition(node.parentNode, dom.getNodeIndex(node)); + } + + function getBoundaryAfterNode(node) { + return new DomPosition(node.parentNode, dom.getNodeIndex(node) + 1); + } + + function insertNodeAtPosition(node, n, o) { + var firstNodeInserted = node.nodeType == 11 ? node.firstChild : node; + if (dom.isCharacterDataNode(n)) { + if (o == n.length) { + dom.insertAfter(node, n); + } else { + n.parentNode.insertBefore(node, o == 0 ? n : dom.splitDataNode(n, o)); + } + } else if (o >= n.childNodes.length) { + n.appendChild(node); + } else { + n.insertBefore(node, n.childNodes[o]); + } + return firstNodeInserted; + } + + function cloneSubtree(iterator) { + var partiallySelected; + for (var node, frag = getRangeDocument(iterator.range).createDocumentFragment(), subIterator; node = iterator.next(); ) { + partiallySelected = iterator.isPartiallySelectedSubtree(); + + node = node.cloneNode(!partiallySelected); + if (partiallySelected) { + subIterator = iterator.getSubtreeIterator(); + node.appendChild(cloneSubtree(subIterator)); + subIterator.detach(true); + } + + if (node.nodeType == 10) { // DocumentType + throw new DOMException("HIERARCHY_REQUEST_ERR"); + } + frag.appendChild(node); + } + return frag; + } + + function iterateSubtree(rangeIterator, func, iteratorState) { + var it, n; + iteratorState = iteratorState || { stop: false }; + for (var node, subRangeIterator; node = rangeIterator.next(); ) { + //log.debug("iterateSubtree, partially selected: " + rangeIterator.isPartiallySelectedSubtree(), nodeToString(node)); + if (rangeIterator.isPartiallySelectedSubtree()) { + // The node is partially selected by the Range, so we can use a new RangeIterator on the portion of the + // node selected by the Range. + if (func(node) === false) { + iteratorState.stop = true; + return; + } else { + subRangeIterator = rangeIterator.getSubtreeIterator(); + iterateSubtree(subRangeIterator, func, iteratorState); + subRangeIterator.detach(true); + if (iteratorState.stop) { + return; + } + } + } else { + // The whole node is selected, so we can use efficient DOM iteration to iterate over the node and its + // descendant + it = dom.createIterator(node); + while ( (n = it.next()) ) { + if (func(n) === false) { + iteratorState.stop = true; + return; + } + } + } + } + } + + function deleteSubtree(iterator) { + var subIterator; + while (iterator.next()) { + if (iterator.isPartiallySelectedSubtree()) { + subIterator = iterator.getSubtreeIterator(); + deleteSubtree(subIterator); + subIterator.detach(true); + } else { + iterator.remove(); + } + } + } + + function extractSubtree(iterator) { + + for (var node, frag = getRangeDocument(iterator.range).createDocumentFragment(), subIterator; node = iterator.next(); ) { + + + if (iterator.isPartiallySelectedSubtree()) { + node = node.cloneNode(false); + subIterator = iterator.getSubtreeIterator(); + node.appendChild(extractSubtree(subIterator)); + subIterator.detach(true); + } else { + iterator.remove(); + } + if (node.nodeType == 10) { // DocumentType + throw new DOMException("HIERARCHY_REQUEST_ERR"); + } + frag.appendChild(node); + } + return frag; + } + + function getNodesInRange(range, nodeTypes, filter) { + //log.info("getNodesInRange, " + nodeTypes.join(",")); + var filterNodeTypes = !!(nodeTypes && nodeTypes.length), regex; + var filterExists = !!filter; + if (filterNodeTypes) { + regex = new RegExp("^(" + nodeTypes.join("|") + ")$"); + } + + var nodes = []; + iterateSubtree(new RangeIterator(range, false), function(node) { + if ((!filterNodeTypes || regex.test(node.nodeType)) && (!filterExists || filter(node))) { + nodes.push(node); + } + }); + return nodes; + } + + function inspect(range) { + var name = (typeof range.getName == "undefined") ? "Range" : range.getName(); + return "[" + name + "(" + dom.inspectNode(range.startContainer) + ":" + range.startOffset + ", " + + dom.inspectNode(range.endContainer) + ":" + range.endOffset + ")]"; + } + + /*----------------------------------------------------------------------------------------------------------------*/ + + // RangeIterator code partially borrows from IERange by Tim Ryan (http://github.com/timcameronryan/IERange) + + /** + * @constructor + */ + function RangeIterator(range, clonePartiallySelectedTextNodes) { + this.range = range; + this.clonePartiallySelectedTextNodes = clonePartiallySelectedTextNodes; + + + + if (!range.collapsed) { + this.sc = range.startContainer; + this.so = range.startOffset; + this.ec = range.endContainer; + this.eo = range.endOffset; + var root = range.commonAncestorContainer; + + if (this.sc === this.ec && dom.isCharacterDataNode(this.sc)) { + this.isSingleCharacterDataNode = true; + this._first = this._last = this._next = this.sc; + } else { + this._first = this._next = (this.sc === root && !dom.isCharacterDataNode(this.sc)) ? + this.sc.childNodes[this.so] : dom.getClosestAncestorIn(this.sc, root, true); + this._last = (this.ec === root && !dom.isCharacterDataNode(this.ec)) ? + this.ec.childNodes[this.eo - 1] : dom.getClosestAncestorIn(this.ec, root, true); + } + + } + } + + RangeIterator.prototype = { + _current: null, + _next: null, + _first: null, + _last: null, + isSingleCharacterDataNode: false, + + reset: function() { + this._current = null; + this._next = this._first; + }, + + hasNext: function() { + return !!this._next; + }, + + next: function() { + // Move to next node + var current = this._current = this._next; + if (current) { + this._next = (current !== this._last) ? current.nextSibling : null; + + // Check for partially selected text nodes + if (dom.isCharacterDataNode(current) && this.clonePartiallySelectedTextNodes) { + if (current === this.ec) { + + (current = current.cloneNode(true)).deleteData(this.eo, current.length - this.eo); + } + if (this._current === this.sc) { + + (current = current.cloneNode(true)).deleteData(0, this.so); + } + } + } + + return current; + }, + + remove: function() { + var current = this._current, start, end; + + if (dom.isCharacterDataNode(current) && (current === this.sc || current === this.ec)) { + start = (current === this.sc) ? this.so : 0; + end = (current === this.ec) ? this.eo : current.length; + if (start != end) { + current.deleteData(start, end - start); + } + } else { + if (current.parentNode) { + current.parentNode.removeChild(current); + } else { + + } + } + }, + + // Checks if the current node is partially selected + isPartiallySelectedSubtree: function() { + var current = this._current; + return isNonTextPartiallySelected(current, this.range); + }, + + getSubtreeIterator: function() { + var subRange; + if (this.isSingleCharacterDataNode) { + subRange = this.range.cloneRange(); + subRange.collapse(); + } else { + subRange = new Range(getRangeDocument(this.range)); + var current = this._current; + var startContainer = current, startOffset = 0, endContainer = current, endOffset = dom.getNodeLength(current); + + if (dom.isAncestorOf(current, this.sc, true)) { + startContainer = this.sc; + startOffset = this.so; + } + if (dom.isAncestorOf(current, this.ec, true)) { + endContainer = this.ec; + endOffset = this.eo; + } + + updateBoundaries(subRange, startContainer, startOffset, endContainer, endOffset); + } + return new RangeIterator(subRange, this.clonePartiallySelectedTextNodes); + }, + + detach: function(detachRange) { + if (detachRange) { + this.range.detach(); + } + this.range = this._current = this._next = this._first = this._last = this.sc = this.so = this.ec = this.eo = null; + } + }; + + /*----------------------------------------------------------------------------------------------------------------*/ + + // Exceptions + + /** + * @constructor + */ + function RangeException(codeName) { + this.code = this[codeName]; + this.codeName = codeName; + this.message = "RangeException: " + this.codeName; + } + + RangeException.prototype = { + BAD_BOUNDARYPOINTS_ERR: 1, + INVALID_NODE_TYPE_ERR: 2 + }; + + RangeException.prototype.toString = function() { + return this.message; + }; + + /*----------------------------------------------------------------------------------------------------------------*/ + + /** + * Currently iterates through all nodes in the range on creation until I think of a decent way to do it + * TODO: Look into making this a proper iterator, not requiring preloading everything first + * @constructor + */ + function RangeNodeIterator(range, nodeTypes, filter) { + this.nodes = getNodesInRange(range, nodeTypes, filter); + this._next = this.nodes[0]; + this._position = 0; + } + + RangeNodeIterator.prototype = { + _current: null, + + hasNext: function() { + return !!this._next; + }, + + next: function() { + this._current = this._next; + this._next = this.nodes[ ++this._position ]; + return this._current; + }, + + detach: function() { + this._current = this._next = this.nodes = null; + } + }; + + var beforeAfterNodeTypes = [1, 3, 4, 5, 7, 8, 10]; + var rootContainerNodeTypes = [2, 9, 11]; + var readonlyNodeTypes = [5, 6, 10, 12]; + var insertableNodeTypes = [1, 3, 4, 5, 7, 8, 10, 11]; + var surroundNodeTypes = [1, 3, 4, 5, 7, 8]; + + function createAncestorFinder(nodeTypes) { + return function(node, selfIsAncestor) { + var t, n = selfIsAncestor ? node : node.parentNode; + while (n) { + t = n.nodeType; + if (dom.arrayContains(nodeTypes, t)) { + return n; + } + n = n.parentNode; + } + return null; + }; + } + + var getRootContainer = dom.getRootContainer; + var getDocumentOrFragmentContainer = createAncestorFinder( [9, 11] ); + var getReadonlyAncestor = createAncestorFinder(readonlyNodeTypes); + var getDocTypeNotationEntityAncestor = createAncestorFinder( [6, 10, 12] ); + + function assertNoDocTypeNotationEntityAncestor(node, allowSelf) { + if (getDocTypeNotationEntityAncestor(node, allowSelf)) { + throw new RangeException("INVALID_NODE_TYPE_ERR"); + } + } + + function assertNotDetached(range) { + if (!range.startContainer) { + throw new DOMException("INVALID_STATE_ERR"); + } + } + + function assertValidNodeType(node, invalidTypes) { + if (!dom.arrayContains(invalidTypes, node.nodeType)) { + throw new RangeException("INVALID_NODE_TYPE_ERR"); + } + } + + function assertValidOffset(node, offset) { + if (offset < 0 || offset > (dom.isCharacterDataNode(node) ? node.length : node.childNodes.length)) { + throw new DOMException("INDEX_SIZE_ERR"); + } + } + + function assertSameDocumentOrFragment(node1, node2) { + if (getDocumentOrFragmentContainer(node1, true) !== getDocumentOrFragmentContainer(node2, true)) { + throw new DOMException("WRONG_DOCUMENT_ERR"); + } + } + + function assertNodeNotReadOnly(node) { + if (getReadonlyAncestor(node, true)) { + throw new DOMException("NO_MODIFICATION_ALLOWED_ERR"); + } + } + + function assertNode(node, codeName) { + if (!node) { + throw new DOMException(codeName); + } + } + + function isOrphan(node) { + return !dom.arrayContains(rootContainerNodeTypes, node.nodeType) && !getDocumentOrFragmentContainer(node, true); + } + + function isValidOffset(node, offset) { + return offset <= (dom.isCharacterDataNode(node) ? node.length : node.childNodes.length); + } + + function isRangeValid(range) { + return (!!range.startContainer && !!range.endContainer + && !isOrphan(range.startContainer) + && !isOrphan(range.endContainer) + && isValidOffset(range.startContainer, range.startOffset) + && isValidOffset(range.endContainer, range.endOffset)); + } + + function assertRangeValid(range) { + assertNotDetached(range); + if (!isRangeValid(range)) { + throw new Error("Range error: Range is no longer valid after DOM mutation (" + range.inspect() + ")"); + } + } + + /*----------------------------------------------------------------------------------------------------------------*/ + + // Test the browser's innerHTML support to decide how to implement createContextualFragment + var styleEl = document.createElement("style"); + var htmlParsingConforms = false; + try { + styleEl.innerHTML = "x"; + htmlParsingConforms = (styleEl.firstChild.nodeType == 3); // Opera incorrectly creates an element node + } catch (e) { + // IE 6 and 7 throw + } + + api.features.htmlParsingConforms = htmlParsingConforms; + + var createContextualFragment = htmlParsingConforms ? + + // Implementation as per HTML parsing spec, trusting in the browser's implementation of innerHTML. See + // discussion and base code for this implementation at issue 67. + // Spec: http://html5.org/specs/dom-parsing.html#extensions-to-the-range-interface + // Thanks to Aleks Williams. + function(fragmentStr) { + // "Let node the context object's start's node." + var node = this.startContainer; + var doc = dom.getDocument(node); + + // "If the context object's start's node is null, raise an INVALID_STATE_ERR + // exception and abort these steps." + if (!node) { + throw new DOMException("INVALID_STATE_ERR"); + } + + // "Let element be as follows, depending on node's interface:" + // Document, Document Fragment: null + var el = null; + + // "Element: node" + if (node.nodeType == 1) { + el = node; + + // "Text, Comment: node's parentElement" + } else if (dom.isCharacterDataNode(node)) { + el = dom.parentElement(node); + } + + // "If either element is null or element's ownerDocument is an HTML document + // and element's local name is "html" and element's namespace is the HTML + // namespace" + if (el === null || ( + el.nodeName == "HTML" + && dom.isHtmlNamespace(dom.getDocument(el).documentElement) + && dom.isHtmlNamespace(el) + )) { + + // "let element be a new Element with "body" as its local name and the HTML + // namespace as its namespace."" + el = doc.createElement("body"); + } else { + el = el.cloneNode(false); + } + + // "If the node's document is an HTML document: Invoke the HTML fragment parsing algorithm." + // "If the node's document is an XML document: Invoke the XML fragment parsing algorithm." + // "In either case, the algorithm must be invoked with fragment as the input + // and element as the context element." + el.innerHTML = fragmentStr; + + // "If this raises an exception, then abort these steps. Otherwise, let new + // children be the nodes returned." + + // "Let fragment be a new DocumentFragment." + // "Append all new children to fragment." + // "Return fragment." + return dom.fragmentFromNodeChildren(el); + } : + + // In this case, innerHTML cannot be trusted, so fall back to a simpler, non-conformant implementation that + // previous versions of Rangy used (with the exception of using a body element rather than a div) + function(fragmentStr) { + assertNotDetached(this); + var doc = getRangeDocument(this); + var el = doc.createElement("body"); + el.innerHTML = fragmentStr; + + return dom.fragmentFromNodeChildren(el); + }; + + /*----------------------------------------------------------------------------------------------------------------*/ + + var rangeProperties = ["startContainer", "startOffset", "endContainer", "endOffset", "collapsed", + "commonAncestorContainer"]; + + var s2s = 0, s2e = 1, e2e = 2, e2s = 3; + var n_b = 0, n_a = 1, n_b_a = 2, n_i = 3; + + function RangePrototype() {} + + RangePrototype.prototype = { + attachListener: function(type, listener) { + this._listeners[type].push(listener); + }, + + compareBoundaryPoints: function(how, range) { + assertRangeValid(this); + assertSameDocumentOrFragment(this.startContainer, range.startContainer); + + var nodeA, offsetA, nodeB, offsetB; + var prefixA = (how == e2s || how == s2s) ? "start" : "end"; + var prefixB = (how == s2e || how == s2s) ? "start" : "end"; + nodeA = this[prefixA + "Container"]; + offsetA = this[prefixA + "Offset"]; + nodeB = range[prefixB + "Container"]; + offsetB = range[prefixB + "Offset"]; + return dom.comparePoints(nodeA, offsetA, nodeB, offsetB); + }, + + insertNode: function(node) { + assertRangeValid(this); + assertValidNodeType(node, insertableNodeTypes); + assertNodeNotReadOnly(this.startContainer); + + if (dom.isAncestorOf(node, this.startContainer, true)) { + throw new DOMException("HIERARCHY_REQUEST_ERR"); + } + + // No check for whether the container of the start of the Range is of a type that does not allow + // children of the type of node: the browser's DOM implementation should do this for us when we attempt + // to add the node + + var firstNodeInserted = insertNodeAtPosition(node, this.startContainer, this.startOffset); + this.setStartBefore(firstNodeInserted); + }, + + cloneContents: function() { + assertRangeValid(this); + + var clone, frag; + if (this.collapsed) { + return getRangeDocument(this).createDocumentFragment(); + } else { + if (this.startContainer === this.endContainer && dom.isCharacterDataNode(this.startContainer)) { + clone = this.startContainer.cloneNode(true); + clone.data = clone.data.slice(this.startOffset, this.endOffset); + frag = getRangeDocument(this).createDocumentFragment(); + frag.appendChild(clone); + return frag; + } else { + var iterator = new RangeIterator(this, true); + clone = cloneSubtree(iterator); + iterator.detach(); + } + return clone; + } + }, + + canSurroundContents: function() { + assertRangeValid(this); + assertNodeNotReadOnly(this.startContainer); + assertNodeNotReadOnly(this.endContainer); + + // Check if the contents can be surrounded. Specifically, this means whether the range partially selects + // no non-text nodes. + var iterator = new RangeIterator(this, true); + var boundariesInvalid = (iterator._first && (isNonTextPartiallySelected(iterator._first, this)) || + (iterator._last && isNonTextPartiallySelected(iterator._last, this))); + iterator.detach(); + return !boundariesInvalid; + }, + + surroundContents: function(node) { + assertValidNodeType(node, surroundNodeTypes); + + if (!this.canSurroundContents()) { + throw new RangeException("BAD_BOUNDARYPOINTS_ERR"); + } + + // Extract the contents + var content = this.extractContents(); + + // Clear the children of the node + if (node.hasChildNodes()) { + while (node.lastChild) { + node.removeChild(node.lastChild); + } + } + + // Insert the new node and add the extracted contents + insertNodeAtPosition(node, this.startContainer, this.startOffset); + node.appendChild(content); + + this.selectNode(node); + }, + + cloneRange: function() { + assertRangeValid(this); + var range = new Range(getRangeDocument(this)); + var i = rangeProperties.length, prop; + while (i--) { + prop = rangeProperties[i]; + range[prop] = this[prop]; + } + return range; + }, + + toString: function() { + assertRangeValid(this); + var sc = this.startContainer; + if (sc === this.endContainer && dom.isCharacterDataNode(sc)) { + return (sc.nodeType == 3 || sc.nodeType == 4) ? sc.data.slice(this.startOffset, this.endOffset) : ""; + } else { + var textBits = [], iterator = new RangeIterator(this, true); + + iterateSubtree(iterator, function(node) { + // Accept only text or CDATA nodes, not comments + + if (node.nodeType == 3 || node.nodeType == 4) { + textBits.push(node.data); + } + }); + iterator.detach(); + return textBits.join(""); + } + }, + + // The methods below are all non-standard. The following batch were introduced by Mozilla but have since + // been removed from Mozilla. + + compareNode: function(node) { + assertRangeValid(this); + + var parent = node.parentNode; + var nodeIndex = dom.getNodeIndex(node); + + if (!parent) { + throw new DOMException("NOT_FOUND_ERR"); + } + + var startComparison = this.comparePoint(parent, nodeIndex), + endComparison = this.comparePoint(parent, nodeIndex + 1); + + if (startComparison < 0) { // Node starts before + return (endComparison > 0) ? n_b_a : n_b; + } else { + return (endComparison > 0) ? n_a : n_i; + } + }, + + comparePoint: function(node, offset) { + assertRangeValid(this); + assertNode(node, "HIERARCHY_REQUEST_ERR"); + assertSameDocumentOrFragment(node, this.startContainer); + + if (dom.comparePoints(node, offset, this.startContainer, this.startOffset) < 0) { + return -1; + } else if (dom.comparePoints(node, offset, this.endContainer, this.endOffset) > 0) { + return 1; + } + return 0; + }, + + createContextualFragment: createContextualFragment, + + toHtml: function() { + assertRangeValid(this); + var container = getRangeDocument(this).createElement("div"); + container.appendChild(this.cloneContents()); + return container.innerHTML; + }, + + // touchingIsIntersecting determines whether this method considers a node that borders a range intersects + // with it (as in WebKit) or not (as in Gecko pre-1.9, and the default) + intersectsNode: function(node, touchingIsIntersecting) { + assertRangeValid(this); + assertNode(node, "NOT_FOUND_ERR"); + if (dom.getDocument(node) !== getRangeDocument(this)) { + return false; + } + + var parent = node.parentNode, offset = dom.getNodeIndex(node); + assertNode(parent, "NOT_FOUND_ERR"); + + var startComparison = dom.comparePoints(parent, offset, this.endContainer, this.endOffset), + endComparison = dom.comparePoints(parent, offset + 1, this.startContainer, this.startOffset); + + return touchingIsIntersecting ? startComparison <= 0 && endComparison >= 0 : startComparison < 0 && endComparison > 0; + }, + + + isPointInRange: function(node, offset) { + assertRangeValid(this); + assertNode(node, "HIERARCHY_REQUEST_ERR"); + assertSameDocumentOrFragment(node, this.startContainer); + + return (dom.comparePoints(node, offset, this.startContainer, this.startOffset) >= 0) && + (dom.comparePoints(node, offset, this.endContainer, this.endOffset) <= 0); + }, + + // The methods below are non-standard and invented by me. + + // Sharing a boundary start-to-end or end-to-start does not count as intersection. + intersectsRange: function(range, touchingIsIntersecting) { + assertRangeValid(this); + + if (getRangeDocument(range) != getRangeDocument(this)) { + throw new DOMException("WRONG_DOCUMENT_ERR"); + } + + var startComparison = dom.comparePoints(this.startContainer, this.startOffset, range.endContainer, range.endOffset), + endComparison = dom.comparePoints(this.endContainer, this.endOffset, range.startContainer, range.startOffset); + + return touchingIsIntersecting ? startComparison <= 0 && endComparison >= 0 : startComparison < 0 && endComparison > 0; + }, + + intersection: function(range) { + if (this.intersectsRange(range)) { + var startComparison = dom.comparePoints(this.startContainer, this.startOffset, range.startContainer, range.startOffset), + endComparison = dom.comparePoints(this.endContainer, this.endOffset, range.endContainer, range.endOffset); + + var intersectionRange = this.cloneRange(); + + if (startComparison == -1) { + intersectionRange.setStart(range.startContainer, range.startOffset); + } + if (endComparison == 1) { + intersectionRange.setEnd(range.endContainer, range.endOffset); + } + return intersectionRange; + } + return null; + }, + + union: function(range) { + if (this.intersectsRange(range, true)) { + var unionRange = this.cloneRange(); + if (dom.comparePoints(range.startContainer, range.startOffset, this.startContainer, this.startOffset) == -1) { + unionRange.setStart(range.startContainer, range.startOffset); + } + if (dom.comparePoints(range.endContainer, range.endOffset, this.endContainer, this.endOffset) == 1) { + unionRange.setEnd(range.endContainer, range.endOffset); + } + return unionRange; + } else { + throw new RangeException("Ranges do not intersect"); + } + }, + + containsNode: function(node, allowPartial) { + if (allowPartial) { + return this.intersectsNode(node, false); + } else { + return this.compareNode(node) == n_i; + } + }, + + containsNodeContents: function(node) { + return this.comparePoint(node, 0) >= 0 && this.comparePoint(node, dom.getNodeLength(node)) <= 0; + }, + + containsRange: function(range) { + return this.intersection(range).equals(range); + }, + + containsNodeText: function(node) { + var nodeRange = this.cloneRange(); + nodeRange.selectNode(node); + var textNodes = nodeRange.getNodes([3]); + if (textNodes.length > 0) { + nodeRange.setStart(textNodes[0], 0); + var lastTextNode = textNodes.pop(); + nodeRange.setEnd(lastTextNode, lastTextNode.length); + var contains = this.containsRange(nodeRange); + nodeRange.detach(); + return contains; + } else { + return this.containsNodeContents(node); + } + }, + + createNodeIterator: function(nodeTypes, filter) { + assertRangeValid(this); + return new RangeNodeIterator(this, nodeTypes, filter); + }, + + getNodes: function(nodeTypes, filter) { + assertRangeValid(this); + return getNodesInRange(this, nodeTypes, filter); + }, + + getDocument: function() { + return getRangeDocument(this); + }, + + collapseBefore: function(node) { + assertNotDetached(this); + + this.setEndBefore(node); + this.collapse(false); + }, + + collapseAfter: function(node) { + assertNotDetached(this); + + this.setStartAfter(node); + this.collapse(true); + }, + + getName: function() { + return "DomRange"; + }, + + equals: function(range) { + return Range.rangesEqual(this, range); + }, + + isValid: function() { + return isRangeValid(this); + }, + + inspect: function() { + return inspect(this); + } + }; + + function copyComparisonConstantsToObject(obj) { + obj.START_TO_START = s2s; + obj.START_TO_END = s2e; + obj.END_TO_END = e2e; + obj.END_TO_START = e2s; + + obj.NODE_BEFORE = n_b; + obj.NODE_AFTER = n_a; + obj.NODE_BEFORE_AND_AFTER = n_b_a; + obj.NODE_INSIDE = n_i; + } + + function copyComparisonConstants(constructor) { + copyComparisonConstantsToObject(constructor); + copyComparisonConstantsToObject(constructor.prototype); + } + + function createRangeContentRemover(remover, boundaryUpdater) { + return function() { + assertRangeValid(this); + + var sc = this.startContainer, so = this.startOffset, root = this.commonAncestorContainer; + + var iterator = new RangeIterator(this, true); + + // Work out where to position the range after content removal + var node, boundary; + if (sc !== root) { + node = dom.getClosestAncestorIn(sc, root, true); + boundary = getBoundaryAfterNode(node); + sc = boundary.node; + so = boundary.offset; + } + + // Check none of the range is read-only + iterateSubtree(iterator, assertNodeNotReadOnly); + + iterator.reset(); + + // Remove the content + var returnValue = remover(iterator); + iterator.detach(); + + // Move to the new position + boundaryUpdater(this, sc, so, sc, so); + + return returnValue; + }; + } + + function createPrototypeRange(constructor, boundaryUpdater, detacher) { + function createBeforeAfterNodeSetter(isBefore, isStart) { + return function(node) { + assertNotDetached(this); + assertValidNodeType(node, beforeAfterNodeTypes); + assertValidNodeType(getRootContainer(node), rootContainerNodeTypes); + + var boundary = (isBefore ? getBoundaryBeforeNode : getBoundaryAfterNode)(node); + (isStart ? setRangeStart : setRangeEnd)(this, boundary.node, boundary.offset); + }; + } + + function setRangeStart(range, node, offset) { + var ec = range.endContainer, eo = range.endOffset; + if (node !== range.startContainer || offset !== range.startOffset) { + // Check the root containers of the range and the new boundary, and also check whether the new boundary + // is after the current end. In either case, collapse the range to the new position + if (getRootContainer(node) != getRootContainer(ec) || dom.comparePoints(node, offset, ec, eo) == 1) { + ec = node; + eo = offset; + } + boundaryUpdater(range, node, offset, ec, eo); + } + } + + function setRangeEnd(range, node, offset) { + var sc = range.startContainer, so = range.startOffset; + if (node !== range.endContainer || offset !== range.endOffset) { + // Check the root containers of the range and the new boundary, and also check whether the new boundary + // is after the current end. In either case, collapse the range to the new position + if (getRootContainer(node) != getRootContainer(sc) || dom.comparePoints(node, offset, sc, so) == -1) { + sc = node; + so = offset; + } + boundaryUpdater(range, sc, so, node, offset); + } + } + + function setRangeStartAndEnd(range, node, offset) { + if (node !== range.startContainer || offset !== range.startOffset || node !== range.endContainer || offset !== range.endOffset) { + boundaryUpdater(range, node, offset, node, offset); + } + } + + constructor.prototype = new RangePrototype(); + + api.util.extend(constructor.prototype, { + setStart: function(node, offset) { + assertNotDetached(this); + assertNoDocTypeNotationEntityAncestor(node, true); + assertValidOffset(node, offset); + + setRangeStart(this, node, offset); + }, + + setEnd: function(node, offset) { + assertNotDetached(this); + assertNoDocTypeNotationEntityAncestor(node, true); + assertValidOffset(node, offset); + + setRangeEnd(this, node, offset); + }, + + setStartBefore: createBeforeAfterNodeSetter(true, true), + setStartAfter: createBeforeAfterNodeSetter(false, true), + setEndBefore: createBeforeAfterNodeSetter(true, false), + setEndAfter: createBeforeAfterNodeSetter(false, false), + + collapse: function(isStart) { + assertRangeValid(this); + if (isStart) { + boundaryUpdater(this, this.startContainer, this.startOffset, this.startContainer, this.startOffset); + } else { + boundaryUpdater(this, this.endContainer, this.endOffset, this.endContainer, this.endOffset); + } + }, + + selectNodeContents: function(node) { + // This doesn't seem well specified: the spec talks only about selecting the node's contents, which + // could be taken to mean only its children. However, browsers implement this the same as selectNode for + // text nodes, so I shall do likewise + assertNotDetached(this); + assertNoDocTypeNotationEntityAncestor(node, true); + + boundaryUpdater(this, node, 0, node, dom.getNodeLength(node)); + }, + + selectNode: function(node) { + assertNotDetached(this); + assertNoDocTypeNotationEntityAncestor(node, false); + assertValidNodeType(node, beforeAfterNodeTypes); + + var start = getBoundaryBeforeNode(node), end = getBoundaryAfterNode(node); + boundaryUpdater(this, start.node, start.offset, end.node, end.offset); + }, + + extractContents: createRangeContentRemover(extractSubtree, boundaryUpdater), + + deleteContents: createRangeContentRemover(deleteSubtree, boundaryUpdater), + + canSurroundContents: function() { + assertRangeValid(this); + assertNodeNotReadOnly(this.startContainer); + assertNodeNotReadOnly(this.endContainer); + + // Check if the contents can be surrounded. Specifically, this means whether the range partially selects + // no non-text nodes. + var iterator = new RangeIterator(this, true); + var boundariesInvalid = (iterator._first && (isNonTextPartiallySelected(iterator._first, this)) || + (iterator._last && isNonTextPartiallySelected(iterator._last, this))); + iterator.detach(); + return !boundariesInvalid; + }, + + detach: function() { + detacher(this); + }, + + splitBoundaries: function() { + assertRangeValid(this); + + + var sc = this.startContainer, so = this.startOffset, ec = this.endContainer, eo = this.endOffset; + var startEndSame = (sc === ec); + + if (dom.isCharacterDataNode(ec) && eo > 0 && eo < ec.length) { + dom.splitDataNode(ec, eo); + + } + + if (dom.isCharacterDataNode(sc) && so > 0 && so < sc.length) { + + sc = dom.splitDataNode(sc, so); + if (startEndSame) { + eo -= so; + ec = sc; + } else if (ec == sc.parentNode && eo >= dom.getNodeIndex(sc)) { + eo++; + } + so = 0; + + } + boundaryUpdater(this, sc, so, ec, eo); + }, + + normalizeBoundaries: function() { + assertRangeValid(this); + + var sc = this.startContainer, so = this.startOffset, ec = this.endContainer, eo = this.endOffset; + + var mergeForward = function(node) { + var sibling = node.nextSibling; + if (sibling && sibling.nodeType == node.nodeType) { + ec = node; + eo = node.length; + node.appendData(sibling.data); + sibling.parentNode.removeChild(sibling); + } + }; + + var mergeBackward = function(node) { + var sibling = node.previousSibling; + if (sibling && sibling.nodeType == node.nodeType) { + sc = node; + var nodeLength = node.length; + so = sibling.length; + node.insertData(0, sibling.data); + sibling.parentNode.removeChild(sibling); + if (sc == ec) { + eo += so; + ec = sc; + } else if (ec == node.parentNode) { + var nodeIndex = dom.getNodeIndex(node); + if (eo == nodeIndex) { + ec = node; + eo = nodeLength; + } else if (eo > nodeIndex) { + eo--; + } + } + } + }; + + var normalizeStart = true; + + if (dom.isCharacterDataNode(ec)) { + if (ec.length == eo) { + mergeForward(ec); + } + } else { + if (eo > 0) { + var endNode = ec.childNodes[eo - 1]; + if (endNode && dom.isCharacterDataNode(endNode)) { + mergeForward(endNode); + } + } + normalizeStart = !this.collapsed; + } + + if (normalizeStart) { + if (dom.isCharacterDataNode(sc)) { + if (so == 0) { + mergeBackward(sc); + } + } else { + if (so < sc.childNodes.length) { + var startNode = sc.childNodes[so]; + if (startNode && dom.isCharacterDataNode(startNode)) { + mergeBackward(startNode); + } + } + } + } else { + sc = ec; + so = eo; + } + + boundaryUpdater(this, sc, so, ec, eo); + }, + + collapseToPoint: function(node, offset) { + assertNotDetached(this); + + assertNoDocTypeNotationEntityAncestor(node, true); + assertValidOffset(node, offset); + + setRangeStartAndEnd(this, node, offset); + } + }); + + copyComparisonConstants(constructor); + } + + /*----------------------------------------------------------------------------------------------------------------*/ + + // Updates commonAncestorContainer and collapsed after boundary change + function updateCollapsedAndCommonAncestor(range) { + range.collapsed = (range.startContainer === range.endContainer && range.startOffset === range.endOffset); + range.commonAncestorContainer = range.collapsed ? + range.startContainer : dom.getCommonAncestor(range.startContainer, range.endContainer); + } + + function updateBoundaries(range, startContainer, startOffset, endContainer, endOffset) { + var startMoved = (range.startContainer !== startContainer || range.startOffset !== startOffset); + var endMoved = (range.endContainer !== endContainer || range.endOffset !== endOffset); + + range.startContainer = startContainer; + range.startOffset = startOffset; + range.endContainer = endContainer; + range.endOffset = endOffset; + + updateCollapsedAndCommonAncestor(range); + dispatchEvent(range, "boundarychange", {startMoved: startMoved, endMoved: endMoved}); + } + + function detach(range) { + assertNotDetached(range); + range.startContainer = range.startOffset = range.endContainer = range.endOffset = null; + range.collapsed = range.commonAncestorContainer = null; + dispatchEvent(range, "detach", null); + range._listeners = null; + } + + /** + * @constructor + */ + function Range(doc) { + this.startContainer = doc; + this.startOffset = 0; + this.endContainer = doc; + this.endOffset = 0; + this._listeners = { + boundarychange: [], + detach: [] + }; + updateCollapsedAndCommonAncestor(this); + } + + createPrototypeRange(Range, updateBoundaries, detach); + + api.rangePrototype = RangePrototype.prototype; + + Range.rangeProperties = rangeProperties; + Range.RangeIterator = RangeIterator; + Range.copyComparisonConstants = copyComparisonConstants; + Range.createPrototypeRange = createPrototypeRange; + Range.inspect = inspect; + Range.getRangeDocument = getRangeDocument; + Range.rangesEqual = function(r1, r2) { + return r1.startContainer === r2.startContainer && + r1.startOffset === r2.startOffset && + r1.endContainer === r2.endContainer && + r1.endOffset === r2.endOffset; + }; + + api.DomRange = Range; + api.RangeException = RangeException; +});rangy.createModule("WrappedRange", function(api, module) { + api.requireModules( ["DomUtil", "DomRange"] ); + + /** + * @constructor + */ + var WrappedRange; + var dom = api.dom; + var DomPosition = dom.DomPosition; + var DomRange = api.DomRange; + + + + /*----------------------------------------------------------------------------------------------------------------*/ + + /* + This is a workaround for a bug where IE returns the wrong container element from the TextRange's parentElement() + method. For example, in the following (where pipes denote the selection boundaries): + +
  • | a
  • b |
+ + var range = document.selection.createRange(); + alert(range.parentElement().id); // Should alert "ul" but alerts "b" + + This method returns the common ancestor node of the following: + - the parentElement() of the textRange + - the parentElement() of the textRange after calling collapse(true) + - the parentElement() of the textRange after calling collapse(false) + */ + function getTextRangeContainerElement(textRange) { + var parentEl = textRange.parentElement(); + + var range = textRange.duplicate(); + range.collapse(true); + var startEl = range.parentElement(); + range = textRange.duplicate(); + range.collapse(false); + var endEl = range.parentElement(); + var startEndContainer = (startEl == endEl) ? startEl : dom.getCommonAncestor(startEl, endEl); + + return startEndContainer == parentEl ? startEndContainer : dom.getCommonAncestor(parentEl, startEndContainer); + } + + function textRangeIsCollapsed(textRange) { + return textRange.compareEndPoints("StartToEnd", textRange) == 0; + } + + // Gets the boundary of a TextRange expressed as a node and an offset within that node. This function started out as + // an improved version of code found in Tim Cameron Ryan's IERange (http://code.google.com/p/ierange/) but has + // grown, fixing problems with line breaks in preformatted text, adding workaround for IE TextRange bugs, handling + // for inputs and images, plus optimizations. + function getTextRangeBoundaryPosition(textRange, wholeRangeContainerElement, isStart, isCollapsed) { + var workingRange = textRange.duplicate(); + + workingRange.collapse(isStart); + var containerElement = workingRange.parentElement(); + + // Sometimes collapsing a TextRange that's at the start of a text node can move it into the previous node, so + // check for that + // TODO: Find out when. Workaround for wholeRangeContainerElement may break this + if (!dom.isAncestorOf(wholeRangeContainerElement, containerElement, true)) { + containerElement = wholeRangeContainerElement; + + } + + + + // Deal with nodes that cannot "contain rich HTML markup". In practice, this means form inputs, images and + // similar. See http://msdn.microsoft.com/en-us/library/aa703950%28VS.85%29.aspx + if (!containerElement.canHaveHTML) { + return new DomPosition(containerElement.parentNode, dom.getNodeIndex(containerElement)); + } + + var workingNode = dom.getDocument(containerElement).createElement("span"); + var comparison, workingComparisonType = isStart ? "StartToStart" : "StartToEnd"; + var previousNode, nextNode, boundaryPosition, boundaryNode; + + // Move the working range through the container's children, starting at the end and working backwards, until the + // working range reaches or goes past the boundary we're interested in + do { + containerElement.insertBefore(workingNode, workingNode.previousSibling); + workingRange.moveToElementText(workingNode); + } while ( (comparison = workingRange.compareEndPoints(workingComparisonType, textRange)) > 0 && + workingNode.previousSibling); + + // We've now reached or gone past the boundary of the text range we're interested in + // so have identified the node we want + boundaryNode = workingNode.nextSibling; + + if (comparison == -1 && boundaryNode && dom.isCharacterDataNode(boundaryNode)) { + // This is a character data node (text, comment, cdata). The working range is collapsed at the start of the + // node containing the text range's boundary, so we move the end of the working range to the boundary point + // and measure the length of its text to get the boundary's offset within the node. + workingRange.setEndPoint(isStart ? "EndToStart" : "EndToEnd", textRange); + + + var offset; + + if (/[\r\n]/.test(boundaryNode.data)) { + /* + For the particular case of a boundary within a text node containing line breaks (within a
 element,
+                for example), we need a slightly complicated approach to get the boundary's offset in IE. The facts:
+
+                - Each line break is represented as \r in the text node's data/nodeValue properties
+                - Each line break is represented as \r\n in the TextRange's 'text' property
+                - The 'text' property of the TextRange does not contain trailing line breaks
+
+                To get round the problem presented by the final fact above, we can use the fact that TextRange's
+                moveStart() and moveEnd() methods return the actual number of characters moved, which is not necessarily
+                the same as the number of characters it was instructed to move. The simplest approach is to use this to
+                store the characters moved when moving both the start and end of the range to the start of the document
+                body and subtracting the start offset from the end offset (the "move-negative-gazillion" method).
+                However, this is extremely slow when the document is large and the range is near the end of it. Clearly
+                doing the mirror image (i.e. moving the range boundaries to the end of the document) has the same
+                problem.
+
+                Another approach that works is to use moveStart() to move the start boundary of the range up to the end
+                boundary one character at a time and incrementing a counter with the value returned by the moveStart()
+                call. However, the check for whether the start boundary has reached the end boundary is expensive, so
+                this method is slow (although unlike "move-negative-gazillion" is largely unaffected by the location of
+                the range within the document).
+
+                The method below is a hybrid of the two methods above. It uses the fact that a string containing the
+                TextRange's 'text' property with each \r\n converted to a single \r character cannot be longer than the
+                text of the TextRange, so the start of the range is moved that length initially and then a character at
+                a time to make up for any trailing line breaks not contained in the 'text' property. This has good
+                performance in most situations compared to the previous two methods.
+                */
+                var tempRange = workingRange.duplicate();
+                var rangeLength = tempRange.text.replace(/\r\n/g, "\r").length;
+
+                offset = tempRange.moveStart("character", rangeLength);
+                while ( (comparison = tempRange.compareEndPoints("StartToEnd", tempRange)) == -1) {
+                    offset++;
+                    tempRange.moveStart("character", 1);
+                }
+            } else {
+                offset = workingRange.text.length;
+            }
+            boundaryPosition = new DomPosition(boundaryNode, offset);
+        } else {
+
+
+            // If the boundary immediately follows a character data node and this is the end boundary, we should favour
+            // a position within that, and likewise for a start boundary preceding a character data node
+            previousNode = (isCollapsed || !isStart) && workingNode.previousSibling;
+            nextNode = (isCollapsed || isStart) && workingNode.nextSibling;
+
+
+
+            if (nextNode && dom.isCharacterDataNode(nextNode)) {
+                boundaryPosition = new DomPosition(nextNode, 0);
+            } else if (previousNode && dom.isCharacterDataNode(previousNode)) {
+                boundaryPosition = new DomPosition(previousNode, previousNode.length);
+            } else {
+                boundaryPosition = new DomPosition(containerElement, dom.getNodeIndex(workingNode));
+            }
+        }
+
+        // Clean up
+        workingNode.parentNode.removeChild(workingNode);
+
+        return boundaryPosition;
+    }
+
+    // Returns a TextRange representing the boundary of a TextRange expressed as a node and an offset within that node.
+    // This function started out as an optimized version of code found in Tim Cameron Ryan's IERange
+    // (http://code.google.com/p/ierange/)
+    function createBoundaryTextRange(boundaryPosition, isStart) {
+        var boundaryNode, boundaryParent, boundaryOffset = boundaryPosition.offset;
+        var doc = dom.getDocument(boundaryPosition.node);
+        var workingNode, childNodes, workingRange = doc.body.createTextRange();
+        var nodeIsDataNode = dom.isCharacterDataNode(boundaryPosition.node);
+
+        if (nodeIsDataNode) {
+            boundaryNode = boundaryPosition.node;
+            boundaryParent = boundaryNode.parentNode;
+        } else {
+            childNodes = boundaryPosition.node.childNodes;
+            boundaryNode = (boundaryOffset < childNodes.length) ? childNodes[boundaryOffset] : null;
+            boundaryParent = boundaryPosition.node;
+        }
+
+        // Position the range immediately before the node containing the boundary
+        workingNode = doc.createElement("span");
+
+        // Making the working element non-empty element persuades IE to consider the TextRange boundary to be within the
+        // element rather than immediately before or after it, which is what we want
+        workingNode.innerHTML = "&#feff;";
+
+        // insertBefore is supposed to work like appendChild if the second parameter is null. However, a bug report
+        // for IERange suggests that it can crash the browser: http://code.google.com/p/ierange/issues/detail?id=12
+        if (boundaryNode) {
+            boundaryParent.insertBefore(workingNode, boundaryNode);
+        } else {
+            boundaryParent.appendChild(workingNode);
+        }
+
+        workingRange.moveToElementText(workingNode);
+        workingRange.collapse(!isStart);
+
+        // Clean up
+        boundaryParent.removeChild(workingNode);
+
+        // Move the working range to the text offset, if required
+        if (nodeIsDataNode) {
+            workingRange[isStart ? "moveStart" : "moveEnd"]("character", boundaryOffset);
+        }
+
+        return workingRange;
+    }
+
+    /*----------------------------------------------------------------------------------------------------------------*/
+
+    if (api.features.implementsDomRange && (!api.features.implementsTextRange || !api.config.preferTextRange)) {
+        // This is a wrapper around the browser's native DOM Range. It has two aims:
+        // - Provide workarounds for specific browser bugs
+        // - provide convenient extensions, which are inherited from Rangy's DomRange
+
+        (function() {
+            var rangeProto;
+            var rangeProperties = DomRange.rangeProperties;
+            var canSetRangeStartAfterEnd;
+
+            function updateRangeProperties(range) {
+                var i = rangeProperties.length, prop;
+                while (i--) {
+                    prop = rangeProperties[i];
+                    range[prop] = range.nativeRange[prop];
+                }
+            }
+
+            function updateNativeRange(range, startContainer, startOffset, endContainer,endOffset) {
+                var startMoved = (range.startContainer !== startContainer || range.startOffset != startOffset);
+                var endMoved = (range.endContainer !== endContainer || range.endOffset != endOffset);
+
+                // Always set both boundaries for the benefit of IE9 (see issue 35)
+                if (startMoved || endMoved) {
+                    range.setEnd(endContainer, endOffset);
+                    range.setStart(startContainer, startOffset);
+                }
+            }
+
+            function detach(range) {
+                range.nativeRange.detach();
+                range.detached = true;
+                var i = rangeProperties.length, prop;
+                while (i--) {
+                    prop = rangeProperties[i];
+                    range[prop] = null;
+                }
+            }
+
+            var createBeforeAfterNodeSetter;
+
+            WrappedRange = function(range) {
+                if (!range) {
+                    throw new Error("Range must be specified");
+                }
+                this.nativeRange = range;
+                updateRangeProperties(this);
+            };
+
+            DomRange.createPrototypeRange(WrappedRange, updateNativeRange, detach);
+
+            rangeProto = WrappedRange.prototype;
+
+            rangeProto.selectNode = function(node) {
+                this.nativeRange.selectNode(node);
+                updateRangeProperties(this);
+            };
+
+            rangeProto.deleteContents = function() {
+                this.nativeRange.deleteContents();
+                updateRangeProperties(this);
+            };
+
+            rangeProto.extractContents = function() {
+                var frag = this.nativeRange.extractContents();
+                updateRangeProperties(this);
+                return frag;
+            };
+
+            rangeProto.cloneContents = function() {
+                return this.nativeRange.cloneContents();
+            };
+
+            // TODO: Until I can find a way to programmatically trigger the Firefox bug (apparently long-standing, still
+            // present in 3.6.8) that throws "Index or size is negative or greater than the allowed amount" for
+            // insertNode in some circumstances, all browsers will have to use the Rangy's own implementation of
+            // insertNode, which works but is almost certainly slower than the native implementation.
+/*
+            rangeProto.insertNode = function(node) {
+                this.nativeRange.insertNode(node);
+                updateRangeProperties(this);
+            };
+*/
+
+            rangeProto.surroundContents = function(node) {
+                this.nativeRange.surroundContents(node);
+                updateRangeProperties(this);
+            };
+
+            rangeProto.collapse = function(isStart) {
+                this.nativeRange.collapse(isStart);
+                updateRangeProperties(this);
+            };
+
+            rangeProto.cloneRange = function() {
+                return new WrappedRange(this.nativeRange.cloneRange());
+            };
+
+            rangeProto.refresh = function() {
+                updateRangeProperties(this);
+            };
+
+            rangeProto.toString = function() {
+                return this.nativeRange.toString();
+            };
+
+            // Create test range and node for feature detection
+
+            var testTextNode = document.createTextNode("test");
+            dom.getBody(document).appendChild(testTextNode);
+            var range = document.createRange();
+
+            /*--------------------------------------------------------------------------------------------------------*/
+
+            // Test for Firefox 2 bug that prevents moving the start of a Range to a point after its current end and
+            // correct for it
+
+            range.setStart(testTextNode, 0);
+            range.setEnd(testTextNode, 0);
+
+            try {
+                range.setStart(testTextNode, 1);
+                canSetRangeStartAfterEnd = true;
+
+                rangeProto.setStart = function(node, offset) {
+                    this.nativeRange.setStart(node, offset);
+                    updateRangeProperties(this);
+                };
+
+                rangeProto.setEnd = function(node, offset) {
+                    this.nativeRange.setEnd(node, offset);
+                    updateRangeProperties(this);
+                };
+
+                createBeforeAfterNodeSetter = function(name) {
+                    return function(node) {
+                        this.nativeRange[name](node);
+                        updateRangeProperties(this);
+                    };
+                };
+
+            } catch(ex) {
+
+
+                canSetRangeStartAfterEnd = false;
+
+                rangeProto.setStart = function(node, offset) {
+                    try {
+                        this.nativeRange.setStart(node, offset);
+                    } catch (ex) {
+                        this.nativeRange.setEnd(node, offset);
+                        this.nativeRange.setStart(node, offset);
+                    }
+                    updateRangeProperties(this);
+                };
+
+                rangeProto.setEnd = function(node, offset) {
+                    try {
+                        this.nativeRange.setEnd(node, offset);
+                    } catch (ex) {
+                        this.nativeRange.setStart(node, offset);
+                        this.nativeRange.setEnd(node, offset);
+                    }
+                    updateRangeProperties(this);
+                };
+
+                createBeforeAfterNodeSetter = function(name, oppositeName) {
+                    return function(node) {
+                        try {
+                            this.nativeRange[name](node);
+                        } catch (ex) {
+                            this.nativeRange[oppositeName](node);
+                            this.nativeRange[name](node);
+                        }
+                        updateRangeProperties(this);
+                    };
+                };
+            }
+
+            rangeProto.setStartBefore = createBeforeAfterNodeSetter("setStartBefore", "setEndBefore");
+            rangeProto.setStartAfter = createBeforeAfterNodeSetter("setStartAfter", "setEndAfter");
+            rangeProto.setEndBefore = createBeforeAfterNodeSetter("setEndBefore", "setStartBefore");
+            rangeProto.setEndAfter = createBeforeAfterNodeSetter("setEndAfter", "setStartAfter");
+
+            /*--------------------------------------------------------------------------------------------------------*/
+
+            // Test for and correct Firefox 2 behaviour with selectNodeContents on text nodes: it collapses the range to
+            // the 0th character of the text node
+            range.selectNodeContents(testTextNode);
+            if (range.startContainer == testTextNode && range.endContainer == testTextNode &&
+                    range.startOffset == 0 && range.endOffset == testTextNode.length) {
+                rangeProto.selectNodeContents = function(node) {
+                    this.nativeRange.selectNodeContents(node);
+                    updateRangeProperties(this);
+                };
+            } else {
+                rangeProto.selectNodeContents = function(node) {
+                    this.setStart(node, 0);
+                    this.setEnd(node, DomRange.getEndOffset(node));
+                };
+            }
+
+            /*--------------------------------------------------------------------------------------------------------*/
+
+            // Test for WebKit bug that has the beahviour of compareBoundaryPoints round the wrong way for constants
+            // START_TO_END and END_TO_START: https://bugs.webkit.org/show_bug.cgi?id=20738
+
+            range.selectNodeContents(testTextNode);
+            range.setEnd(testTextNode, 3);
+
+            var range2 = document.createRange();
+            range2.selectNodeContents(testTextNode);
+            range2.setEnd(testTextNode, 4);
+            range2.setStart(testTextNode, 2);
+
+            if (range.compareBoundaryPoints(range.START_TO_END, range2) == -1 &
+                    range.compareBoundaryPoints(range.END_TO_START, range2) == 1) {
+                // This is the wrong way round, so correct for it
+
+
+                rangeProto.compareBoundaryPoints = function(type, range) {
+                    range = range.nativeRange || range;
+                    if (type == range.START_TO_END) {
+                        type = range.END_TO_START;
+                    } else if (type == range.END_TO_START) {
+                        type = range.START_TO_END;
+                    }
+                    return this.nativeRange.compareBoundaryPoints(type, range);
+                };
+            } else {
+                rangeProto.compareBoundaryPoints = function(type, range) {
+                    return this.nativeRange.compareBoundaryPoints(type, range.nativeRange || range);
+                };
+            }
+
+            /*--------------------------------------------------------------------------------------------------------*/
+
+            // Test for existence of createContextualFragment and delegate to it if it exists
+            if (api.util.isHostMethod(range, "createContextualFragment")) {
+                rangeProto.createContextualFragment = function(fragmentStr) {
+                    return this.nativeRange.createContextualFragment(fragmentStr);
+                };
+            }
+
+            /*--------------------------------------------------------------------------------------------------------*/
+
+            // Clean up
+            dom.getBody(document).removeChild(testTextNode);
+            range.detach();
+            range2.detach();
+        })();
+
+        api.createNativeRange = function(doc) {
+            doc = doc || document;
+            return doc.createRange();
+        };
+    } else if (api.features.implementsTextRange) {
+        // This is a wrapper around a TextRange, providing full DOM Range functionality using rangy's DomRange as a
+        // prototype
+
+        WrappedRange = function(textRange) {
+            this.textRange = textRange;
+            this.refresh();
+        };
+
+        WrappedRange.prototype = new DomRange(document);
+
+        WrappedRange.prototype.refresh = function() {
+            var start, end;
+
+            // TextRange's parentElement() method cannot be trusted. getTextRangeContainerElement() works around that.
+            var rangeContainerElement = getTextRangeContainerElement(this.textRange);
+
+            if (textRangeIsCollapsed(this.textRange)) {
+                end = start = getTextRangeBoundaryPosition(this.textRange, rangeContainerElement, true, true);
+            } else {
+
+                start = getTextRangeBoundaryPosition(this.textRange, rangeContainerElement, true, false);
+                end = getTextRangeBoundaryPosition(this.textRange, rangeContainerElement, false, false);
+            }
+
+            this.setStart(start.node, start.offset);
+            this.setEnd(end.node, end.offset);
+        };
+
+        DomRange.copyComparisonConstants(WrappedRange);
+
+        // Add WrappedRange as the Range property of the global object to allow expression like Range.END_TO_END to work
+        var globalObj = (function() { return this; })();
+        if (typeof globalObj.Range == "undefined") {
+            globalObj.Range = WrappedRange;
+        }
+
+        api.createNativeRange = function(doc) {
+            doc = doc || document;
+            return doc.body.createTextRange();
+        };
+    }
+
+    if (api.features.implementsTextRange) {
+        WrappedRange.rangeToTextRange = function(range) {
+            if (range.collapsed) {
+                var tr = createBoundaryTextRange(new DomPosition(range.startContainer, range.startOffset), true);
+
+
+
+                return tr;
+
+                //return createBoundaryTextRange(new DomPosition(range.startContainer, range.startOffset), true);
+            } else {
+                var startRange = createBoundaryTextRange(new DomPosition(range.startContainer, range.startOffset), true);
+                var endRange = createBoundaryTextRange(new DomPosition(range.endContainer, range.endOffset), false);
+                var textRange = dom.getDocument(range.startContainer).body.createTextRange();
+                textRange.setEndPoint("StartToStart", startRange);
+                textRange.setEndPoint("EndToEnd", endRange);
+                return textRange;
+            }
+        };
+    }
+
+    WrappedRange.prototype.getName = function() {
+        return "WrappedRange";
+    };
+
+    api.WrappedRange = WrappedRange;
+
+    api.createRange = function(doc) {
+        doc = doc || document;
+        return new WrappedRange(api.createNativeRange(doc));
+    };
+
+    api.createRangyRange = function(doc) {
+        doc = doc || document;
+        return new DomRange(doc);
+    };
+
+    api.createIframeRange = function(iframeEl) {
+        return api.createRange(dom.getIframeDocument(iframeEl));
+    };
+
+    api.createIframeRangyRange = function(iframeEl) {
+        return api.createRangyRange(dom.getIframeDocument(iframeEl));
+    };
+
+    api.addCreateMissingNativeApiListener(function(win) {
+        var doc = win.document;
+        if (typeof doc.createRange == "undefined") {
+            doc.createRange = function() {
+                return api.createRange(this);
+            };
+        }
+        doc = win = null;
+    });
+});rangy.createModule("WrappedSelection", function(api, module) {
+    // This will create a selection object wrapper that follows the Selection object found in the WHATWG draft DOM Range
+    // spec (http://html5.org/specs/dom-range.html)
+
+    api.requireModules( ["DomUtil", "DomRange", "WrappedRange"] );
+
+    api.config.checkSelectionRanges = true;
+
+    var BOOLEAN = "boolean",
+        windowPropertyName = "_rangySelection",
+        dom = api.dom,
+        util = api.util,
+        DomRange = api.DomRange,
+        WrappedRange = api.WrappedRange,
+        DOMException = api.DOMException,
+        DomPosition = dom.DomPosition,
+        getSelection,
+        selectionIsCollapsed,
+        CONTROL = "Control";
+
+
+
+    function getWinSelection(winParam) {
+        return (winParam || window).getSelection();
+    }
+
+    function getDocSelection(winParam) {
+        return (winParam || window).document.selection;
+    }
+
+    // Test for the Range/TextRange and Selection features required
+    // Test for ability to retrieve selection
+    var implementsWinGetSelection = api.util.isHostMethod(window, "getSelection"),
+        implementsDocSelection = api.util.isHostObject(document, "selection");
+
+    var useDocumentSelection = implementsDocSelection && (!implementsWinGetSelection || api.config.preferTextRange);
+
+    if (useDocumentSelection) {
+        getSelection = getDocSelection;
+        api.isSelectionValid = function(winParam) {
+            var doc = (winParam || window).document, nativeSel = doc.selection;
+
+            // Check whether the selection TextRange is actually contained within the correct document
+            return (nativeSel.type != "None" || dom.getDocument(nativeSel.createRange().parentElement()) == doc);
+        };
+    } else if (implementsWinGetSelection) {
+        getSelection = getWinSelection;
+        api.isSelectionValid = function() {
+            return true;
+        };
+    } else {
+        module.fail("Neither document.selection or window.getSelection() detected.");
+    }
+
+    api.getNativeSelection = getSelection;
+
+    var testSelection = getSelection();
+    var testRange = api.createNativeRange(document);
+    var body = dom.getBody(document);
+
+    // Obtaining a range from a selection
+    var selectionHasAnchorAndFocus = util.areHostObjects(testSelection, ["anchorNode", "focusNode"] &&
+                                     util.areHostProperties(testSelection, ["anchorOffset", "focusOffset"]));
+    api.features.selectionHasAnchorAndFocus = selectionHasAnchorAndFocus;
+
+    // Test for existence of native selection extend() method
+    var selectionHasExtend = util.isHostMethod(testSelection, "extend");
+    api.features.selectionHasExtend = selectionHasExtend;
+
+    // Test if rangeCount exists
+    var selectionHasRangeCount = (typeof testSelection.rangeCount == "number");
+    api.features.selectionHasRangeCount = selectionHasRangeCount;
+
+    var selectionSupportsMultipleRanges = false;
+    var collapsedNonEditableSelectionsSupported = true;
+
+    if (util.areHostMethods(testSelection, ["addRange", "getRangeAt", "removeAllRanges"]) &&
+            typeof testSelection.rangeCount == "number" && api.features.implementsDomRange) {
+
+        (function() {
+            var iframe = document.createElement("iframe");
+            iframe.frameBorder = 0;
+            iframe.style.position = "absolute";
+            iframe.style.left = "-10000px";
+            body.appendChild(iframe);
+
+            var iframeDoc = dom.getIframeDocument(iframe);
+            iframeDoc.open();
+            iframeDoc.write("12");
+            iframeDoc.close();
+
+            var sel = dom.getIframeWindow(iframe).getSelection();
+            var docEl = iframeDoc.documentElement;
+            var iframeBody = docEl.lastChild, textNode = iframeBody.firstChild;
+
+            // Test whether the native selection will allow a collapsed selection within a non-editable element
+            var r1 = iframeDoc.createRange();
+            r1.setStart(textNode, 1);
+            r1.collapse(true);
+            sel.addRange(r1);
+            collapsedNonEditableSelectionsSupported = (sel.rangeCount == 1);
+            sel.removeAllRanges();
+
+            // Test whether the native selection is capable of supporting multiple ranges
+            var r2 = r1.cloneRange();
+            r1.setStart(textNode, 0);
+            r2.setEnd(textNode, 2);
+            sel.addRange(r1);
+            sel.addRange(r2);
+
+            selectionSupportsMultipleRanges = (sel.rangeCount == 2);
+
+            // Clean up
+            r1.detach();
+            r2.detach();
+
+            body.removeChild(iframe);
+        })();
+    }
+
+    api.features.selectionSupportsMultipleRanges = selectionSupportsMultipleRanges;
+    api.features.collapsedNonEditableSelectionsSupported = collapsedNonEditableSelectionsSupported;
+
+    // ControlRanges
+    var implementsControlRange = false, testControlRange;
+
+    if (body && util.isHostMethod(body, "createControlRange")) {
+        testControlRange = body.createControlRange();
+        if (util.areHostProperties(testControlRange, ["item", "add"])) {
+            implementsControlRange = true;
+        }
+    }
+    api.features.implementsControlRange = implementsControlRange;
+
+    // Selection collapsedness
+    if (selectionHasAnchorAndFocus) {
+        selectionIsCollapsed = function(sel) {
+            return sel.anchorNode === sel.focusNode && sel.anchorOffset === sel.focusOffset;
+        };
+    } else {
+        selectionIsCollapsed = function(sel) {
+            return sel.rangeCount ? sel.getRangeAt(sel.rangeCount - 1).collapsed : false;
+        };
+    }
+
+    function updateAnchorAndFocusFromRange(sel, range, backwards) {
+        var anchorPrefix = backwards ? "end" : "start", focusPrefix = backwards ? "start" : "end";
+        sel.anchorNode = range[anchorPrefix + "Container"];
+        sel.anchorOffset = range[anchorPrefix + "Offset"];
+        sel.focusNode = range[focusPrefix + "Container"];
+        sel.focusOffset = range[focusPrefix + "Offset"];
+    }
+
+    function updateAnchorAndFocusFromNativeSelection(sel) {
+        var nativeSel = sel.nativeSelection;
+        sel.anchorNode = nativeSel.anchorNode;
+        sel.anchorOffset = nativeSel.anchorOffset;
+        sel.focusNode = nativeSel.focusNode;
+        sel.focusOffset = nativeSel.focusOffset;
+    }
+
+    function updateEmptySelection(sel) {
+        sel.anchorNode = sel.focusNode = null;
+        sel.anchorOffset = sel.focusOffset = 0;
+        sel.rangeCount = 0;
+        sel.isCollapsed = true;
+        sel._ranges.length = 0;
+    }
+
+    function getNativeRange(range) {
+        var nativeRange;
+        if (range instanceof DomRange) {
+            nativeRange = range._selectionNativeRange;
+            if (!nativeRange) {
+                nativeRange = api.createNativeRange(dom.getDocument(range.startContainer));
+                nativeRange.setEnd(range.endContainer, range.endOffset);
+                nativeRange.setStart(range.startContainer, range.startOffset);
+                range._selectionNativeRange = nativeRange;
+                range.attachListener("detach", function() {
+
+                    this._selectionNativeRange = null;
+                });
+            }
+        } else if (range instanceof WrappedRange) {
+            nativeRange = range.nativeRange;
+        } else if (api.features.implementsDomRange && (range instanceof dom.getWindow(range.startContainer).Range)) {
+            nativeRange = range;
+        }
+        return nativeRange;
+    }
+
+    function rangeContainsSingleElement(rangeNodes) {
+        if (!rangeNodes.length || rangeNodes[0].nodeType != 1) {
+            return false;
+        }
+        for (var i = 1, len = rangeNodes.length; i < len; ++i) {
+            if (!dom.isAncestorOf(rangeNodes[0], rangeNodes[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    function getSingleElementFromRange(range) {
+        var nodes = range.getNodes();
+        if (!rangeContainsSingleElement(nodes)) {
+            throw new Error("getSingleElementFromRange: range " + range.inspect() + " did not consist of a single element");
+        }
+        return nodes[0];
+    }
+
+    function isTextRange(range) {
+        return !!range && typeof range.text != "undefined";
+    }
+
+    function updateFromTextRange(sel, range) {
+        // Create a Range from the selected TextRange
+        var wrappedRange = new WrappedRange(range);
+        sel._ranges = [wrappedRange];
+
+        updateAnchorAndFocusFromRange(sel, wrappedRange, false);
+        sel.rangeCount = 1;
+        sel.isCollapsed = wrappedRange.collapsed;
+    }
+
+    function updateControlSelection(sel) {
+        // Update the wrapped selection based on what's now in the native selection
+        sel._ranges.length = 0;
+        if (sel.docSelection.type == "None") {
+            updateEmptySelection(sel);
+        } else {
+            var controlRange = sel.docSelection.createRange();
+            if (isTextRange(controlRange)) {
+                // This case (where the selection type is "Control" and calling createRange() on the selection returns
+                // a TextRange) can happen in IE 9. It happens, for example, when all elements in the selected
+                // ControlRange have been removed from the ControlRange and removed from the document.
+                updateFromTextRange(sel, controlRange);
+            } else {
+                sel.rangeCount = controlRange.length;
+                var range, doc = dom.getDocument(controlRange.item(0));
+                for (var i = 0; i < sel.rangeCount; ++i) {
+                    range = api.createRange(doc);
+                    range.selectNode(controlRange.item(i));
+                    sel._ranges.push(range);
+                }
+                sel.isCollapsed = sel.rangeCount == 1 && sel._ranges[0].collapsed;
+                updateAnchorAndFocusFromRange(sel, sel._ranges[sel.rangeCount - 1], false);
+            }
+        }
+    }
+
+    function addRangeToControlSelection(sel, range) {
+        var controlRange = sel.docSelection.createRange();
+        var rangeElement = getSingleElementFromRange(range);
+
+        // Create a new ControlRange containing all the elements in the selected ControlRange plus the element
+        // contained by the supplied range
+        var doc = dom.getDocument(controlRange.item(0));
+        var newControlRange = dom.getBody(doc).createControlRange();
+        for (var i = 0, len = controlRange.length; i < len; ++i) {
+            newControlRange.add(controlRange.item(i));
+        }
+        try {
+            newControlRange.add(rangeElement);
+        } catch (ex) {
+            throw new Error("addRange(): Element within the specified Range could not be added to control selection (does it have layout?)");
+        }
+        newControlRange.select();
+
+        // Update the wrapped selection based on what's now in the native selection
+        updateControlSelection(sel);
+    }
+
+    var getSelectionRangeAt;
+
+    if (util.isHostMethod(testSelection,  "getRangeAt")) {
+        getSelectionRangeAt = function(sel, index) {
+            try {
+                return sel.getRangeAt(index);
+            } catch(ex) {
+                return null;
+            }
+        };
+    } else if (selectionHasAnchorAndFocus) {
+        getSelectionRangeAt = function(sel) {
+            var doc = dom.getDocument(sel.anchorNode);
+            var range = api.createRange(doc);
+            range.setStart(sel.anchorNode, sel.anchorOffset);
+            range.setEnd(sel.focusNode, sel.focusOffset);
+
+            // Handle the case when the selection was selected backwards (from the end to the start in the
+            // document)
+            if (range.collapsed !== this.isCollapsed) {
+                range.setStart(sel.focusNode, sel.focusOffset);
+                range.setEnd(sel.anchorNode, sel.anchorOffset);
+            }
+
+            return range;
+        };
+    }
+
+    /**
+     * @constructor
+     */
+    function WrappedSelection(selection, docSelection, win) {
+        this.nativeSelection = selection;
+        this.docSelection = docSelection;
+        this._ranges = [];
+        this.win = win;
+        this.refresh();
+    }
+
+    api.getSelection = function(win) {
+        win = win || window;
+        var sel = win[windowPropertyName];
+        var nativeSel = getSelection(win), docSel = implementsDocSelection ? getDocSelection(win) : null;
+        if (sel) {
+            sel.nativeSelection = nativeSel;
+            sel.docSelection = docSel;
+            sel.refresh(win);
+        } else {
+            sel = new WrappedSelection(nativeSel, docSel, win);
+            win[windowPropertyName] = sel;
+        }
+        return sel;
+    };
+
+    api.getIframeSelection = function(iframeEl) {
+        return api.getSelection(dom.getIframeWindow(iframeEl));
+    };
+
+    var selProto = WrappedSelection.prototype;
+
+    function createControlSelection(sel, ranges) {
+        // Ensure that the selection becomes of type "Control"
+        var doc = dom.getDocument(ranges[0].startContainer);
+        var controlRange = dom.getBody(doc).createControlRange();
+        for (var i = 0, el; i < rangeCount; ++i) {
+            el = getSingleElementFromRange(ranges[i]);
+            try {
+                controlRange.add(el);
+            } catch (ex) {
+                throw new Error("setRanges(): Element within the one of the specified Ranges could not be added to control selection (does it have layout?)");
+            }
+        }
+        controlRange.select();
+
+        // Update the wrapped selection based on what's now in the native selection
+        updateControlSelection(sel);
+    }
+
+    // Selecting a range
+    if (!useDocumentSelection && selectionHasAnchorAndFocus && util.areHostMethods(testSelection, ["removeAllRanges", "addRange"])) {
+        selProto.removeAllRanges = function() {
+            this.nativeSelection.removeAllRanges();
+            updateEmptySelection(this);
+        };
+
+        var addRangeBackwards = function(sel, range) {
+            var doc = DomRange.getRangeDocument(range);
+            var endRange = api.createRange(doc);
+            endRange.collapseToPoint(range.endContainer, range.endOffset);
+            sel.nativeSelection.addRange(getNativeRange(endRange));
+            sel.nativeSelection.extend(range.startContainer, range.startOffset);
+            sel.refresh();
+        };
+
+        if (selectionHasRangeCount) {
+            selProto.addRange = function(range, backwards) {
+                if (implementsControlRange && implementsDocSelection && this.docSelection.type == CONTROL) {
+                    addRangeToControlSelection(this, range);
+                } else {
+                    if (backwards && selectionHasExtend) {
+                        addRangeBackwards(this, range);
+                    } else {
+                        var previousRangeCount;
+                        if (selectionSupportsMultipleRanges) {
+                            previousRangeCount = this.rangeCount;
+                        } else {
+                            this.removeAllRanges();
+                            previousRangeCount = 0;
+                        }
+                        this.nativeSelection.addRange(getNativeRange(range));
+
+                        // Check whether adding the range was successful
+                        this.rangeCount = this.nativeSelection.rangeCount;
+
+                        if (this.rangeCount == previousRangeCount + 1) {
+                            // The range was added successfully
+
+                            // Check whether the range that we added to the selection is reflected in the last range extracted from
+                            // the selection
+                            if (api.config.checkSelectionRanges) {
+                                var nativeRange = getSelectionRangeAt(this.nativeSelection, this.rangeCount - 1);
+                                if (nativeRange && !DomRange.rangesEqual(nativeRange, range)) {
+                                    // Happens in WebKit with, for example, a selection placed at the start of a text node
+                                    range = new WrappedRange(nativeRange);
+                                }
+                            }
+                            this._ranges[this.rangeCount - 1] = range;
+                            updateAnchorAndFocusFromRange(this, range, selectionIsBackwards(this.nativeSelection));
+                            this.isCollapsed = selectionIsCollapsed(this);
+                        } else {
+                            // The range was not added successfully. The simplest thing is to refresh
+                            this.refresh();
+                        }
+                    }
+                }
+            };
+        } else {
+            selProto.addRange = function(range, backwards) {
+                if (backwards && selectionHasExtend) {
+                    addRangeBackwards(this, range);
+                } else {
+                    this.nativeSelection.addRange(getNativeRange(range));
+                    this.refresh();
+                }
+            };
+        }
+
+        selProto.setRanges = function(ranges) {
+            if (implementsControlRange && ranges.length > 1) {
+                createControlSelection(this, ranges);
+            } else {
+                this.removeAllRanges();
+                for (var i = 0, len = ranges.length; i < len; ++i) {
+                    this.addRange(ranges[i]);
+                }
+            }
+        };
+    } else if (util.isHostMethod(testSelection, "empty") && util.isHostMethod(testRange, "select") &&
+               implementsControlRange && useDocumentSelection) {
+
+        selProto.removeAllRanges = function() {
+            // Added try/catch as fix for issue #21
+            try {
+                this.docSelection.empty();
+
+                // Check for empty() not working (issue #24)
+                if (this.docSelection.type != "None") {
+                    // Work around failure to empty a control selection by instead selecting a TextRange and then
+                    // calling empty()
+                    var doc;
+                    if (this.anchorNode) {
+                        doc = dom.getDocument(this.anchorNode);
+                    } else if (this.docSelection.type == CONTROL) {
+                        var controlRange = this.docSelection.createRange();
+                        if (controlRange.length) {
+                            doc = dom.getDocument(controlRange.item(0)).body.createTextRange();
+                        }
+                    }
+                    if (doc) {
+                        var textRange = doc.body.createTextRange();
+                        textRange.select();
+                        this.docSelection.empty();
+                    }
+                }
+            } catch(ex) {}
+            updateEmptySelection(this);
+        };
+
+        selProto.addRange = function(range) {
+            if (this.docSelection.type == CONTROL) {
+                addRangeToControlSelection(this, range);
+            } else {
+                WrappedRange.rangeToTextRange(range).select();
+                this._ranges[0] = range;
+                this.rangeCount = 1;
+                this.isCollapsed = this._ranges[0].collapsed;
+                updateAnchorAndFocusFromRange(this, range, false);
+            }
+        };
+
+        selProto.setRanges = function(ranges) {
+            this.removeAllRanges();
+            var rangeCount = ranges.length;
+            if (rangeCount > 1) {
+                createControlSelection(this, ranges);
+            } else if (rangeCount) {
+                this.addRange(ranges[0]);
+            }
+        };
+    } else {
+        module.fail("No means of selecting a Range or TextRange was found");
+        return false;
+    }
+
+    selProto.getRangeAt = function(index) {
+        if (index < 0 || index >= this.rangeCount) {
+            throw new DOMException("INDEX_SIZE_ERR");
+        } else {
+            return this._ranges[index];
+        }
+    };
+
+    var refreshSelection;
+
+    if (useDocumentSelection) {
+        refreshSelection = function(sel) {
+            var range;
+            if (api.isSelectionValid(sel.win)) {
+                range = sel.docSelection.createRange();
+            } else {
+                range = dom.getBody(sel.win.document).createTextRange();
+                range.collapse(true);
+            }
+
+
+            if (sel.docSelection.type == CONTROL) {
+                updateControlSelection(sel);
+            } else if (isTextRange(range)) {
+                updateFromTextRange(sel, range);
+            } else {
+                updateEmptySelection(sel);
+            }
+        };
+    } else if (util.isHostMethod(testSelection, "getRangeAt") && typeof testSelection.rangeCount == "number") {
+        refreshSelection = function(sel) {
+            if (implementsControlRange && implementsDocSelection && sel.docSelection.type == CONTROL) {
+                updateControlSelection(sel);
+            } else {
+                sel._ranges.length = sel.rangeCount = sel.nativeSelection.rangeCount;
+                if (sel.rangeCount) {
+                    for (var i = 0, len = sel.rangeCount; i < len; ++i) {
+                        sel._ranges[i] = new api.WrappedRange(sel.nativeSelection.getRangeAt(i));
+                    }
+                    updateAnchorAndFocusFromRange(sel, sel._ranges[sel.rangeCount - 1], selectionIsBackwards(sel.nativeSelection));
+                    sel.isCollapsed = selectionIsCollapsed(sel);
+                } else {
+                    updateEmptySelection(sel);
+                }
+            }
+        };
+    } else if (selectionHasAnchorAndFocus && typeof testSelection.isCollapsed == BOOLEAN && typeof testRange.collapsed == BOOLEAN && api.features.implementsDomRange) {
+        refreshSelection = function(sel) {
+            var range, nativeSel = sel.nativeSelection;
+            if (nativeSel.anchorNode) {
+                range = getSelectionRangeAt(nativeSel, 0);
+                sel._ranges = [range];
+                sel.rangeCount = 1;
+                updateAnchorAndFocusFromNativeSelection(sel);
+                sel.isCollapsed = selectionIsCollapsed(sel);
+            } else {
+                updateEmptySelection(sel);
+            }
+        };
+    } else {
+        module.fail("No means of obtaining a Range or TextRange from the user's selection was found");
+        return false;
+    }
+
+    selProto.refresh = function(checkForChanges) {
+        var oldRanges = checkForChanges ? this._ranges.slice(0) : null;
+        refreshSelection(this);
+        if (checkForChanges) {
+            var i = oldRanges.length;
+            if (i != this._ranges.length) {
+                return false;
+            }
+            while (i--) {
+                if (!DomRange.rangesEqual(oldRanges[i], this._ranges[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    };
+
+    // Removal of a single range
+    var removeRangeManually = function(sel, range) {
+        var ranges = sel.getAllRanges(), removed = false;
+        sel.removeAllRanges();
+        for (var i = 0, len = ranges.length; i < len; ++i) {
+            if (removed || range !== ranges[i]) {
+                sel.addRange(ranges[i]);
+            } else {
+                // According to the draft WHATWG Range spec, the same range may be added to the selection multiple
+                // times. removeRange should only remove the first instance, so the following ensures only the first
+                // instance is removed
+                removed = true;
+            }
+        }
+        if (!sel.rangeCount) {
+            updateEmptySelection(sel);
+        }
+    };
+
+    if (implementsControlRange) {
+        selProto.removeRange = function(range) {
+            if (this.docSelection.type == CONTROL) {
+                var controlRange = this.docSelection.createRange();
+                var rangeElement = getSingleElementFromRange(range);
+
+                // Create a new ControlRange containing all the elements in the selected ControlRange minus the
+                // element contained by the supplied range
+                var doc = dom.getDocument(controlRange.item(0));
+                var newControlRange = dom.getBody(doc).createControlRange();
+                var el, removed = false;
+                for (var i = 0, len = controlRange.length; i < len; ++i) {
+                    el = controlRange.item(i);
+                    if (el !== rangeElement || removed) {
+                        newControlRange.add(controlRange.item(i));
+                    } else {
+                        removed = true;
+                    }
+                }
+                newControlRange.select();
+
+                // Update the wrapped selection based on what's now in the native selection
+                updateControlSelection(this);
+            } else {
+                removeRangeManually(this, range);
+            }
+        };
+    } else {
+        selProto.removeRange = function(range) {
+            removeRangeManually(this, range);
+        };
+    }
+
+    // Detecting if a selection is backwards
+    var selectionIsBackwards;
+    if (!useDocumentSelection && selectionHasAnchorAndFocus && api.features.implementsDomRange) {
+        selectionIsBackwards = function(sel) {
+            var backwards = false;
+            if (sel.anchorNode) {
+                backwards = (dom.comparePoints(sel.anchorNode, sel.anchorOffset, sel.focusNode, sel.focusOffset) == 1);
+            }
+            return backwards;
+        };
+
+        selProto.isBackwards = function() {
+            return selectionIsBackwards(this);
+        };
+    } else {
+        selectionIsBackwards = selProto.isBackwards = function() {
+            return false;
+        };
+    }
+
+    // Selection text
+    // This is conformant to the new WHATWG DOM Range draft spec but differs from WebKit and Mozilla's implementation
+    selProto.toString = function() {
+
+        var rangeTexts = [];
+        for (var i = 0, len = this.rangeCount; i < len; ++i) {
+            rangeTexts[i] = "" + this._ranges[i];
+        }
+        return rangeTexts.join("");
+    };
+
+    function assertNodeInSameDocument(sel, node) {
+        if (sel.anchorNode && (dom.getDocument(sel.anchorNode) !== dom.getDocument(node))) {
+            throw new DOMException("WRONG_DOCUMENT_ERR");
+        }
+    }
+
+    // No current browsers conform fully to the HTML 5 draft spec for this method, so Rangy's own method is always used
+    selProto.collapse = function(node, offset) {
+        assertNodeInSameDocument(this, node);
+        var range = api.createRange(dom.getDocument(node));
+        range.collapseToPoint(node, offset);
+        this.removeAllRanges();
+        this.addRange(range);
+        this.isCollapsed = true;
+    };
+
+    selProto.collapseToStart = function() {
+        if (this.rangeCount) {
+            var range = this._ranges[0];
+            this.collapse(range.startContainer, range.startOffset);
+        } else {
+            throw new DOMException("INVALID_STATE_ERR");
+        }
+    };
+
+    selProto.collapseToEnd = function() {
+        if (this.rangeCount) {
+            var range = this._ranges[this.rangeCount - 1];
+            this.collapse(range.endContainer, range.endOffset);
+        } else {
+            throw new DOMException("INVALID_STATE_ERR");
+        }
+    };
+
+    // The HTML 5 spec is very specific on how selectAllChildren should be implemented so the native implementation is
+    // never used by Rangy.
+    selProto.selectAllChildren = function(node) {
+        assertNodeInSameDocument(this, node);
+        var range = api.createRange(dom.getDocument(node));
+        range.selectNodeContents(node);
+        this.removeAllRanges();
+        this.addRange(range);
+    };
+
+    selProto.deleteFromDocument = function() {
+        // Sepcial behaviour required for Control selections
+        if (implementsControlRange && implementsDocSelection && this.docSelection.type == CONTROL) {
+            var controlRange = this.docSelection.createRange();
+            var element;
+            while (controlRange.length) {
+                element = controlRange.item(0);
+                controlRange.remove(element);
+                element.parentNode.removeChild(element);
+            }
+            this.refresh();
+        } else if (this.rangeCount) {
+            var ranges = this.getAllRanges();
+            this.removeAllRanges();
+            for (var i = 0, len = ranges.length; i < len; ++i) {
+                ranges[i].deleteContents();
+            }
+            // The HTML5 spec says nothing about what the selection should contain after calling deleteContents on each
+            // range. Firefox moves the selection to where the final selected range was, so we emulate that
+            this.addRange(ranges[len - 1]);
+        }
+    };
+
+    // The following are non-standard extensions
+    selProto.getAllRanges = function() {
+        return this._ranges.slice(0);
+    };
+
+    selProto.setSingleRange = function(range) {
+        this.setRanges( [range] );
+    };
+
+    selProto.containsNode = function(node, allowPartial) {
+        for (var i = 0, len = this._ranges.length; i < len; ++i) {
+            if (this._ranges[i].containsNode(node, allowPartial)) {
+                return true;
+            }
+        }
+        return false;
+    };
+
+    selProto.toHtml = function() {
+        var html = "";
+        if (this.rangeCount) {
+            var container = DomRange.getRangeDocument(this._ranges[0]).createElement("div");
+            for (var i = 0, len = this._ranges.length; i < len; ++i) {
+                container.appendChild(this._ranges[i].cloneContents());
+            }
+            html = container.innerHTML;
+        }
+        return html;
+    };
+
+    function inspect(sel) {
+        var rangeInspects = [];
+        var anchor = new DomPosition(sel.anchorNode, sel.anchorOffset);
+        var focus = new DomPosition(sel.focusNode, sel.focusOffset);
+        var name = (typeof sel.getName == "function") ? sel.getName() : "Selection";
+
+        if (typeof sel.rangeCount != "undefined") {
+            for (var i = 0, len = sel.rangeCount; i < len; ++i) {
+                rangeInspects[i] = DomRange.inspect(sel.getRangeAt(i));
+            }
+        }
+        return "[" + name + "(Ranges: " + rangeInspects.join(", ") +
+                ")(anchor: " + anchor.inspect() + ", focus: " + focus.inspect() + "]";
+
+    }
+
+    selProto.getName = function() {
+        return "WrappedSelection";
+    };
+
+    selProto.inspect = function() {
+        return inspect(this);
+    };
+
+    selProto.detach = function() {
+        this.win[windowPropertyName] = null;
+        this.win = this.anchorNode = this.focusNode = null;
+    };
+
+    WrappedSelection.inspect = inspect;
+
+    api.Selection = WrappedSelection;
+
+    api.selectionPrototype = selProto;
+
+    api.addCreateMissingNativeApiListener(function(win) {
+        if (typeof win.getSelection == "undefined") {
+            win.getSelection = function() {
+                return api.getSelection(this);
+            };
+        }
+        win = null;
+    });
+});
diff --git a/resources/js/ext.uls.ime.js b/resources/js/ext.uls.ime.js
index 296374b9..7266247d 100644
--- a/resources/js/ext.uls.ime.js
+++ b/resources/js/ext.uls.ime.js
@@ -23,7 +23,7 @@
 
 	mwImeRulesPath = mw.config.get( 'wgExtensionAssetsPath' ) +
 		'/UniversalLanguageSelector/lib/jquery.ime/';
-	inputSelector = 'input:not([type]), input[type=text], input[type=search], textarea';
+	inputSelector = 'input:not([type]), input[type=text], input[type=search], textarea, [contenteditable]';
 
 	inputPreferences = mw.uls.preferences();
 
@@ -199,6 +199,7 @@
 				mw.loader.using( 'jquery.ime', function () {
 					$input.trigger( 'focus.ime' );
 				} );
+
 				return;
 			}
 
@@ -208,6 +209,15 @@
 				return;
 			}
 
+			if ( $input.is( '[contenteditable]' ) && !window.rangy ) {
+				// for supporting content editable divs we need rangy library
+				mw.loader.using( 'rangy.core', function () {
+					$input.trigger( 'focus.ime' );
+				} );
+
+				return;
+			}
+
 			if ( noImeSelector.length && $input.is( noImeSelector ) ) {
 				$input.addClass( 'noime' );
 				return;