മീഡിയവിക്കി:Jquery.ime.js
ശ്രദ്ധിക്കുക: സേവ് ചെയ്തശേഷം മാറ്റങ്ങൾ കാണാനായി താങ്കൾക്ക് ബ്രൗസറിന്റെ കാഷെ ഒഴിവാക്കേണ്ടി വന്നേക്കാം.
- ഫയർഫോക്സ് / സഫാരി: Reload ബട്ടൺ അമർത്തുമ്പോൾ Shift കീ അമർത്തി പിടിക്കുകയോ, Ctrl-F5 അല്ലെങ്കിൽ Ctrl-R (മാക്കിന്റോഷിൽ ⌘-R ) എന്ന് ഒരുമിച്ച് അമർത്തുകയോ ചെയ്യുക
- ഗൂഗിൾ ക്രോം: Ctrl-Shift-R (മാക്കിന്റോഷിൽ ⌘-Shift-R ) അമർത്തുക
- ഇന്റർനെറ്റ് എക്സ്പ്ലോറർ: Refresh ബട്ടൺ അമർത്തുമ്പോൾ Ctrl കീ അമർത്തിപിടിക്കുക. അല്ലെങ്കിൽ Ctrl-F5 അമർത്തുക
- ഓപ്പറ: Menu → Settings എടുക്കുക (മാക്കിൽ Opera → Preferences) എന്നിട്ട് Privacy & security → Clear browsing data → Cached images and files ചെയ്യുക.
( function ( $ ) {
'use strict';
function IME( element, options ) {
this.$element = $( element );
// This needs to be delayed here since extending language list happens at DOM ready
$.ime.defaults.languages = arrayKeys( $.ime.languages );
this.options = $.extend( {}, $.ime.defaults, options );
this.active = false;
this.inputmethod = null;
this.language = null;
this.context = '';
this.selector = this.$element.imeselector( this.options );
this.listen();
}
IME.prototype = {
constructor: IME,
listen: function () {
this.$element.on( 'keypress.ime', $.proxy( this.keypress, this ) );
this.$element.on( 'destroy.ime', $.proxy( this.destroy, this ) );
this.$element.on( 'enable.ime', $.proxy( this.enable, this ) );
this.$element.on( 'disable.ime', $.proxy( this.disable, this ) );
},
/**
* Transliterate a given string input based on context and input method definition.
* If there are no matching rules defined, returns the original string.
*
* @param input
* @param context
* @param altGr bool whether altGr key is pressed or not
* @returns String transliterated string
*/
transliterate: function ( input, context, altGr ) {
var patterns, regex, rule, replacement, i;
if ( altGr ) {
patterns = this.inputmethod.patterns_x || [];
} else {
patterns = this.inputmethod.patterns || [];
}
if ( $.isFunction( patterns ) ) {
return patterns.call( this, input, context );
}
for ( i = 0; i < patterns.length; i++ ) {
rule = patterns[i];
regex = new RegExp( rule[0] + '$' );
// Last item in the rules.
// It can also be a function, because the replace
// method can have a function as the second argument.
replacement = rule.slice( -1 )[0];
// Input string match test
if ( regex.test( input ) ) {
// Context test required?
if ( rule.length === 3 ) {
if ( new RegExp( rule[1] + '$' ).test( context ) ) {
return input.replace( regex, replacement );
}
} else {
// No context test required. Just replace.
return input.replace( regex, replacement );
}
}
}
// No matches, return the input
return input;
},
keypress: function ( e ) {
var altGr = false,
c, startPos, pos, endPos, divergingPos, input, replacement;
if ( !this.active ) {
return true;
}
if ( !this.inputmethod ) {
return true;
}
// handle backspace
if ( e.which === 8 ) {
// Blank the context
this.context = '';
return true;
}
if ( e.altKey || e.altGraphKey ) {
altGr = true;
}
// Don't process ASCII control characters (except linefeed),
// as well as anything involving
// Alt (except for extended keymaps), Ctrl and Meta
if ( ( e.which < 32 && e.which !== 13 && !altGr ) || e.ctrlKey || e.metaKey ) {
// Blank the context
this.context = '';
return true;
}
c = String.fromCharCode( e.which );
// Get the current caret position. The user may have selected text to overwrite,
// so get both the start and end position of the selection. If there is no selection,
// startPos and endPos will be equal.
pos = this.getCaretPosition( this.$element );
startPos = pos[0];
endPos = pos[1];
// Get the last few characters before the one the user just typed,
// to provide context for the transliteration regexes.
// We need to append c because it hasn't been added to $this.val() yet
input = this.lastNChars( this.$element.val() || this.$element.text(), startPos,
this.inputmethod.maxKeyLength )
+ c;
replacement = this.transliterate( input, this.context, altGr );
// Update the context
this.context += c;
if ( this.context.length > this.inputmethod.contextLength ) {
// The buffer is longer than needed, truncate it at the front
this.context = this.context.substring( this.context.length
- this.inputmethod.contextLength );
}
// If replacement equals to input, no replacement is made, because
// there's apparently nothing to do. However, there may be something
// to do if AltGr was pressed. For example, if a layout is built in
// a way that allows typing the original character instead of
// the replacement by pressing it with AltGr.
if ( !altGr && replacement === input ) {
return true;
}
// Drop a common prefix, if any
divergingPos = this.firstDivergence( input, replacement );
input = input.substring( divergingPos );
replacement = replacement.substring( divergingPos );
replaceText( this.$element, replacement, startPos - input.length + 1, endPos );
e.stopPropagation();
return false;
},
isActive: function () {
return this.active;
},
disable: function () {
this.active = false;
$.ime.preferences.setIM( 'system' );
},
enable: function () {
this.active = true;
},
toggle: function () {
this.active = !this.active;
},
destroy: function () {
$( 'body' ).off( '.ime' );
this.$element.off( '.ime' ).removeData( 'ime' ).removeData( 'imeselector' );
},
getIM: function () {
return this.inputmethod;
},
setIM: function ( inputmethodId ) {
this.inputmethod = $.ime.inputmethods[inputmethodId];
$.ime.preferences.setIM( inputmethodId );
},
setLanguage: function ( languageCode ) {
if ( !$.ime.languages[languageCode] ) {
debug( 'Language ' + languageCode + ' is not known to jquery.ime.' );
return false;
}
this.language = languageCode;
$.ime.preferences.setLanguage( languageCode );
return true;
},
getLanguage: function () {
return this.language;
},
load: function ( name, callback ) {
var ime = this,
dependency;
if ( $.ime.inputmethods[name] ) {
if ( callback ) {
callback.call( ime );
}
return true;
}
dependency = $.ime.sources[name].depends;
if ( dependency ) {
this.load( dependency ) ;
}
$.ajax( {
url: ime.options.imePath + $.ime.sources[name].source + '&action=raw&ctype=text/javascript',
dataType: 'script'
} ).done( function () {
debug( name + ' loaded' );
if ( callback ) {
callback.call( ime );
}
} ).fail( function ( jqxhr, settings, exception ) {
debug( 'Error in loading inputmethod ' + name + ' Exception: ' + exception );
} );
},
// Returns an array [start, end] of the beginning
// and the end of the current selection in $element
getCaretPosition: function ( $element ) {
return getCaretPosition( $element );
},
/**
* Find the point at which a and b diverge, i.e. the first position
* at which they don't have matching characters.
*
* @param a String
* @param b String
* @return Position at which a and b diverge, or -1 if a === b
*/
firstDivergence: function ( a, b ) {
return firstDivergence( a, b );
},
/**
* Get the n characters in str that immediately precede pos
* Example: lastNChars( 'foobarbaz', 5, 2 ) === 'ba'
*
* @param str String to search in
* @param pos Position in str
* @param n Number of characters to go back from pos
* @return Substring of str, at most n characters long, immediately preceding pos
*/
lastNChars: function ( str, pos, n ) {
return lastNChars( str, pos, n );
}
};
$.fn.ime = function ( option ) {
return this.each( function () {
var data,
$this = $( this ),
options = typeof option === 'object' && option;
// Some exclusions: IME shouldn't be applied to textareas with
// these properties.
if ( $this.prop( 'readonly' ) ||
$this.prop( 'disabled' ) ||
$this.hasClass( 'noime' ) ) {
return;
}
data = $this.data( 'ime' );
if ( !data ) {
data = new IME( this, options );
$this.data( 'ime', data );
}
if ( typeof option === 'string' ) {
data[option]();
}
} );
};
$.ime = {};
$.ime.inputmethods = {};
$.ime.sources = {};
$.ime.preferences = {};
$.ime.languages = {};
var defaultInputMethod = {
contextLength: 0,
maxKeyLength: 1
};
$.ime.register = function ( inputMethod ) {
$.ime.inputmethods[inputMethod.id] = $.extend( {}, defaultInputMethod, inputMethod );
};
// default options
$.ime.defaults = {
imePath: '../', // Relative/Absolute path for the rules folder of jquery.ime
languages: [] // Languages to be used- by default all languages
};
// private function for debugging
function debug( $obj ) {
if ( window.console && window.console.log ) {
window.console.log( $obj );
}
}
// Returns an array [start, end] of the beginning
// and the end of the current selection in $element
function getCaretPosition( $element ) {
var el = $element.get( 0 ),
start = 0,
end = 0,
normalizedValue,
range,
textInputRange,
len,
newLines,
endRange;
if ( typeof el.selectionStart === 'number' && typeof el.selectionEnd === 'number' ) {
start = el.selectionStart;
end = el.selectionEnd;
} else {
// IE
range = document.selection.createRange();
if ( range && range.parentElement() === el ) {
len = el.value.length;
normalizedValue = el.value.replace( /\r\n/g, '\n' );
newLines = normalizedValue.match( /\n/g );
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark( range.getBookmark() );
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse( false );
if ( textInputRange.compareEndPoints( 'StartToEnd', endRange ) > -1 ) {
if ( newLines ) {
start = end = len - newLines.length;
} else {
start = end = len;
}
} else {
start = -textInputRange.moveStart( 'character', -len );
if ( textInputRange.compareEndPoints( 'EndToEnd', endRange ) > -1 ) {
end = len;
} else {
end = -textInputRange.moveEnd( 'character', -len );
}
}
}
}
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();
sel.moveToElementText( e );
return sel;
}
}
function replaceText( $element, replacement, start, end ) {
var element = $element.get( 0 ),
selection,
length,
newLines,
scrollTop;
if ( typeof element.selectionStart === 'number' && typeof element.selectionEnd === 'number' ) {
// IE9+ and all other browsers
scrollTop = element.scrollTop;
// 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 );
// restore scroll
element.scrollTop = scrollTop;
// set selection
element.selectionStart = element.selectionEnd = start + replacement.length;
} else {
// IE8 and lower
selection = rangeForElementIE(element);
length = element.value.length;
// IE doesn't count \n when computing the offset, so we won't either
newLines = element.value.match( /\n/g );
if ( newLines ) {
length = length - newLines.length;
}
selection.moveStart( 'character', start );
selection.moveEnd( 'character', end - length );
selection.text = replacement;
selection.collapse( false );
selection.select();
}
}
/**
* Find the point at which a and b diverge, i.e. the first position
* at which they don't have matching characters.
*
* @param a String
* @param b String
* @return Position at which a and b diverge, or -1 if a === b
*/
function firstDivergence( a, b ) {
var minLength, i;
minLength = a.length < b.length ? a.length : b.length;
for ( i = 0; i < minLength; i++ ) {
if ( a.charCodeAt( i ) !== b.charCodeAt( i ) ) {
return i;
}
}
return -1;
}
/**
* Get the n characters in str that immediately precede pos
* Example: lastNChars( 'foobarbaz', 5, 2 ) === 'ba'
*
* @param str String to search in
* @param pos Position in str
* @param n Number of characters to go back from pos
* @return Substring of str, at most n characters long, immediately preceding pos
*/
function lastNChars( str, pos, n ) {
if ( n === 0 ) {
return '';
} else if ( pos <= n ) {
return str.substr( 0, pos );
} else {
return str.substr( pos - n, n );
}
}
function arrayKeys ( obj ) {
var rv = [];
$.each( obj, function ( key ) {
rv.push( key );
} );
return rv;
}
}( jQuery ) );