مستخدم:TJones (WMF)/Arabic-DWIM.js
يمكن توفير توثيق لسكربت المستخدم هذا في الصفحة : مستخدم:TJones (WMF)/Arabic-DWIM. |
ملاحظة: بعد الحفظ، قد يلزمك إفراغ الكاش لرؤية التغييرات.
// Target keyboard layouts from https://ar.wikipedia.org/wiki/ميدياويكي:Gadget-Dwim.js
// Javascript UI code from https://ru.wikipedia.org/wiki/Участник:Kaganer/Gadget-Dwim.js
// which is currently live and working. All DWIMs seem to be based on the Hebrew original
// https://he.wikipedia.org/wiki/מדיה ויקי:Gadget-Dwim.js
//
// Please adapt to use whatever skin and Javascript UI hooks currently make sense.
//
// Creating DWIM script Arabic & Latin keyboards presents several challenges. Like the
// Cyrillic/Russian DWIM (and unlike the Hebrew original), Arabic/Latin DWIM needs to
// account for uppercase AND lowercase Latin characters, because they map to different
// characters on the Arabic keyboard.
//
// A further complexity comes from the fact that certain characters (notably <>, [], {},
// ', and /) are present on both the Arabic and US keyboards, but in different locations,
// meaning that there isn't just one mapping value for each. (For example, q always maps
// to︎ ض, and vice versa, but / maps to ظ going from Latin to Arabic, but / maps to L
// going from Arabic to Latin.)
//
// Another difficulty is that some keys on the Arabic keyboard type two characters:
//
// Arabic - decomposition - US keyboard - US keyboard decomposition
// لا x ل+ا b gh
// لآ x ل+آ B gN
// لأ x ل+أ G gH
// لإ x ل+إ T gY
//
// While mixed-case gN, gH, and gY are generally very unlikely digraphs, gh is a
// reasonably common digraph in English ("laugh", "ghost", etc.) Unfortunately, this makes
// لا ambiguous--it could come from "b" or "gh" typed on the US keyboard. I've chosen to
// always map it to "b" because "b" is much more common than "gh" in English. This means
// that typing "laugh" or "ghost" on the Arabic keyboard will result in suggestions for
// "laub" or "bost" from the US keyboard. This is not optimal. (It also isn't pessimal--it
// could have been "e" and "th" that were conflated by the mapping!)
//
// To handle all of these complexities, we detect whether any reasonably unambiguously
// Latin or Arabic keyboard characters are present in the string. For Latin, that is a-z,
// A-Z, and ; and ?. I ignored the semicolon and question mark because they seem too
// likely to show up in another context. For Arabic, I chose a range that includes all the
// Arabic characters in the mapping, plus ×, ÷, and ~. While these three characters CAN
// show up in other contexts, they are much less likely to do so than ; and ?.
//
// If a string has both Latin and Arabic keyboard characters (or neither) then we just
// return the input unchanged, which prevents any DWIM suggestions from being generated.
//
// If the string contains Latin or Arabic (but not both), we need to first handle the
// four two-letter mappings using four calls to replaceAll(). We also need to specify
// which general mapping to use (latinMap maps Latin to Arabic, and arabicMap maps Arabic
// to Latin); this prevents us from always mapping / to ظ or always mapping / to L. Using
// the chosen map, we perform the original DWIM character-by-character swap, and return
// the result.
//
// Another problem I've seen when the Hebrew DWIM is adapted to another keyboard is that
// the magic numbers 58 and 29 get copied to the new DWIM. They are the length and half
// the length of the Hebrew-English mapping, respectively, so if the new mapping is a
// different length, they are incorrect and the new DWIM will not work correctly. Rather
// than introduce new magic numbers, I've caclulated them here. This also makes the script
// more robust to updates to the mapping (for example, if we wanted to add 0-9 and ٠-٩).
//
// I've also renamed the mapping function from hebeng() (HEBrew-ENGlish) to araeng()
// (ARAbic-ENGlish).
mw.loader.using( [ 'mediawiki.searchSuggest', 'mediawiki.util' ] ).done( function() {
'use strict';
$( function() {
var latinPat = new RegExp('[a-zA-Z]'),
arabicPat = new RegExp('[\u060c-\u0652×÷~]'),
// map keyboard layouts [[:File:KB United States-NoAltGr.svg]] vs [[:File:KB Arabic.svg]]
latinMap = "qwertyuiop[]asdfghjkl;'zxcvnm,./QWERYUIOP{}ASDFHJKLZXCVNM<>?ضصثقفغعهخحجدشسيبلاتنمكطئءؤرىةوزظًٌَُإ‘÷×؛<>ٍِ][أـ،/~ْ}{آ’,.؟",
arabicMap = "ضصثقفغعهخحجدشسيبلاتنمكطئءؤرىةوزظًٌَُإ‘÷×؛<>ٍِ][أـ،/~ْ}{آ’,.؟qwertyuiop[]asdfghjkl;'zxcvnm,./QWERYUIOP{}ASDFHJKLZXCVNM<>?",
maplen = arabicMap.length,
rotate = maplen / 2,
araeng = function ( str ) {
var isLatin = latinPat.test(str);
var isArabic = arabicPat.test(str);
var myMap;
if (isLatin) {
if (isArabic) {
return str; // mixed-script, do nothing
}
str = str.replaceAll('T', 'gY');
str = str.replaceAll('G', 'gH');
str = str.replaceAll('B', 'gN');
str = str.replaceAll('b', 'gh');
myMap = latinMap;
} else if (isArabic) {
str = str.replaceAll('لإ', 'T');
str = str.replaceAll('لأ', 'G');
str = str.replaceAll('لآ', 'B');
str = str.replaceAll('لا', 'b');
myMap = arabicMap;
} else {
return str; // neither Arabic nor Latin, do nothing
}
var res = '';
for (var i = 0; i < str.length; i++) {
var ic = myMap.indexOf( str.charAt( i ) );
res += ic + 1 ? myMap.charAt( ( ic + rotate ) % maplen ) : str.charAt( i );
}
return res;
};
var $searchBoxes = $(
'#searchInput, #searchInput2, #powerSearchText, #searchText'
);
$searchBoxes.suggestions( {
fetch: function( query ) {
var $this = $( this ),
apiUrl = mw.util.wikiScript( 'api' );
if ( query.length !== 0 ) {
var params = {
action: 'opensearch',
search: query,
redirects: 'return',
suggest: true
};
$.ajax( {
data: params,
url: apiUrl,
dataType: 'json',
success: function( data ) {
if ( $.isArray( data ) && 1 in data ) {
var orig = data[1];
$this.suggestions( 'suggestions', orig );
if ( data[1].length < 10 ) {
params.search = araeng( query );
if ( params.search === query ) {
return;
}
params.limit = 10 - data[1].length;
$.ajax( {
data: params,
url: apiUrl,
dataType: 'json',
success: function( data ) {
if ( $.isArray( data ) && 1 in data ) {
$this.suggestions(
'suggestions',
orig.concat( data[1] )
);
}
}
} );
}
}
}
} );
}
}
} );
} ); // document.ready
} ); // mw.loader.using