MediaWiki:Gadget-Compare2texts.js
Материал из ЕЖЕВИКА-Публикаций - pubs.EJWiki.org - Вики-системы компетентных публикаций по еврейским и израильским темам
Замечание. Возможно, после сохранения вам придётся очистить кэш своего браузера, чтобы увидеть изменения.
- Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl-F5 или Ctrl-R (⌘-R на Mac)
- Google Chrome: Нажмите Ctrl-Shift-R (⌘-Shift-R на Mac)
- Internet Explorer: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl-F5
- Opera: Выберите очистку кэша в меню Инструменты → Настройки
//Скрипт для поиска совпадающих подстрок в двух текстах //Этот код выполняется в начале. if (wgAction == 'edit' || wgAction == 'submit'){ addOnloadHook(XRomix_Compare2texts_OnLoad) } ///////////////////////////////////////////////////////////////////////////// function XRomix_Compare2texts_OnLoad(){ //Этот код выполнится после загрузки страницы var toolbar = document.getElementById('toolbar') var textbox = document.getElementById('wpTextbox1') if (!textbox || !toolbar) return addToolbarButton("Сравнение", XRomix_Compare2texts, 'btnXRomix_Compare2texts', 'Сравнение двух текстов', ""); //Adds a text button to edit toolbar function addToolbarButton(name, onclick, id, tooltip, accesskey){ var toolbar = document.getElementById('toolbar'); if (!toolbar) return; var newBtn = document.createElement('input'); newBtn.type = 'button'; newBtn.style.background = '#adbede'; newBtn.style.height = '22px'; newBtn.style.verticalAlign = 'middle'; if (name) newBtn.value = name; if (onclick) newBtn.onclick = onclick; if (id) newBtn.id = id; if (tooltip) newBtn.title = tooltip; if (accesskey) newBtn.accessKey = accesskey; toolbar.appendChild(newBtn); return newBtn; } } ///////////////////////////////////////////////////////////////////////////// function insertAfter(parent, node, referenceNode) { parent.insertBefore(node, referenceNode.nextSibling); } ///////////////////////////////////////////////////////////////////////////// function XRomix_Compare2texts(){ XRomix_CreateNewTextbox(); } ///////////////////////////////////////////////////////////////////////////// function XRomix_CreateNewTextbox(){ //var input = document.getElementById('wpSummary') var input = document.getElementById('wpTextbox1') if (!input) return var el = document.getElementById('XRomix_wpTextbox2') if (el) { removeElementById('XRomix_wpTextbox2'); return; } var el = document.createElement('span') el.id = 'XRomix_wpTextbox2'; el.style.marginLeft = '3px' input.parentNode.insertBefore(el, input.nextSibling) el.innerHTML = '<p>Текст в окне ниже не будет сохранён на сервер.\ <input type="button" value="Выполнить сравнение" onclick="XRomix_btnCompare2texts_Compare()">\ <input type="button" value="Следующее соответствие" onclick="XRomix_btnCompare2texts_CompareNext()">\ <br/><span id="XRomix_ComparedText"></span></p><textarea cols="80" rows="15" id="XRomix_Textbox2" name="XRomix_Textbox2"> \ </textarea> \ <input id="XRomix_h1" name="XRomix_h1" type="hidden" value="" /> \ <input id="XRomix_h2" name="XRomix_h2" type="hidden" value="" /> '; //Вспомогательные функции function removeChildrenRecursively(node) { if (!node) return; while (node.hasChildNodes()) { removeChildrenRecursively(node.firstChild); node.removeChild(node.firstChild); } } function removeElementById(nodeId) { document.getElementById(nodeId).parentNode.removeChild( document.getElementById(nodeId)); } } ///////////////////////////////////////////////////////////////////////////// function XRomix_Compare2texts_Compare(mode){ ////////////////////////////////////// // Переменные для функции var XRomix_maxP1; //позиция максимально совпадающих фрагментов var XRomix_maxP2; var XRomix_max1;//длина максимвльно совпадающих фрагментов var XRomix_max2; var XRomix_len1;//длина текущего соответствия для checkCompareLength var XRomix_len2; var XRomix_s1// тексты для сравнения. в них знаки препинания и прочие различия удалены, но число и позиция символов сохранена var XRomix_s2 var wpTextbox1=document.getElementById('wpTextbox1'); if(!wpTextbox1) return; if(mode=="first"){ var s= wpTextbox1.value; XRomix_s1=prepareText(s, true); //см. ниже }else if (mode=="next"){ var h1=document.getElementById('XRomix_h1'); XRomix_s1 = h1.value; } var wpTextbox2=document.getElementById('XRomix_Textbox2'); if(!wpTextbox2) return; if(mode=="first"){ var s= wpTextbox2.value; XRomix_s2=prepareText(s, false); //см. ниже }else if (mode=="next"){ var h2=document.getElementById('XRomix_h2'); XRomix_s2 = h2.value; } getMaxSameText(); //см.ниже //alert("Совпадение1: "+wpTextbox1.value.substr(XRomix_maxP1, XRomix_max1)) //alert("Совпадение2: "+wpTextbox2.value.substr(XRomix_maxP2, XRomix_max2)) var sovp1=wpTextbox1.value.substr(XRomix_maxP1, XRomix_max1); var sovp2=wpTextbox2.value.substr(XRomix_maxP2, XRomix_max2); if(XRomix_max2>3){ selectInTextArea(wpTextbox1, sovp1); selectInTextArea(wpTextbox2, sovp2); setSelectionRange(wpTextbox1, XRomix_maxP1, XRomix_maxP1+XRomix_max1); setSelectionRange(wpTextbox2, XRomix_maxP2, XRomix_maxP2+XRomix_max2); wpTextbox1.focus(); var label = document.getElementById('XRomix_ComparedText'); label.innerHTML="<i><font color='blue'>"+sovp2+"</font></i>"; }else{ var label = document.getElementById('XRomix_ComparedText'); label.innerHTML="<font color='blue'>Совпадений не найдено</font>"; //alert("Совпадений не найдено"); } var s=XRomix_s1; var left=s.substr(0, XRomix_maxP1); var right=s.substr(XRomix_maxP1+XRomix_max1); var sp=generateSpaces(XRomix_max1); var XRomix_s1=left+sp+right; if(s.length!=XRomix_s1.length){ alert("Длина строк не совпадает"); } var h1=document.getElementById('XRomix_h1'); h1.value=XRomix_s1; var h2=document.getElementById('XRomix_h2'); h2.value=XRomix_s2; ////////////////////////////////////// //Выполняет замену подстроки s1 на s2 в строке s. Сама строка s при этом не изменяется function replace(s, s1, s2){ var p=s.indexOf(s1); if (p<0) return; var left=s.substr(0, p); var right=s.substr(p+s1.length); return left+s2+right; } ////////////////////////////////////// //генерирует строку из пробелов указанной длины function generateSpaces(len){ var s1=""; for(var i=0; i<len; i++){ s1+=" "; } return s1; } ////////////////////////////////////// //Извлекает текстовое значение внутри [[викификации]], заменяя все лишнее на пробелы function spaceWikify(s){ if (s.indexOf("|")>=0){ //если найдена конструкция [[ | var flagSpace=1; //признак замены на пробел var s1=""; for(var i=0; i<s.length; i++){ var c=s.charAt(i); if(c=="|"){ flagSpace=0; c=" "; } if(flagSpace==1){ c=" "; } s1+=c; } s=s1; } s=s.replace(/\[\[/, " "); //[[ на два пробела s=s.replace(/\]\]/, ""); //[[ на пустую строку, т.к. надо отработать еще слова наподобие [[год]]у s=s+" ";//добавляем два пробела в конец, чтобы скомпенсировать длину return s; } ////////////////////////////////////// //Подготавливает текст function prepareText(s, delQuoutes){ //Заменяем знаки препинания на пробелы s=s.replace(/[\.\,\;\?\!\(\)\—\-\:\=\*]/g, " "); //Заменим викификацию var arr=s.match(/\[\[.*?\]\]([^\s])*/g); if(arr){ for(var i=0; i<arr.length; i++){ var w=arr[i]; var w1=spaceWikify(w); //см. ниже if(w.length!=w1.length) alert('Строки не совпадают по длине: '+w+'<>'+w1); s=replace(s, w, w1); } } //Убираем закавыченное, если передан такой параметр if(delQuoutes){ var arr=s.match(/«.*?»/g); if(arr){ for(var i=0; i<arr.length; i++){ var w=arr[i]; var w1=generateSpaces(w.length); //см. ниже s=replace(s, w, w1); } } } //Убираем то что внутри [квадратных скобок] var arr=s.match(/\[.*?\]/g); if(arr){ for(var i=0; i<arr.length; i++){ var w=arr[i]; var w1=generateSpaces(w.length); //см. ниже s=replace(s, w, w1); } } //Убираем символы кавычек и апострофов s=s.replace(/[«»„“\"\']/g, " "); //Убираем {{шаблоны}} Википедии var arr=s.match(/\{\{.*?\}\}/g); if(arr){ for(var i=0; i<arr.length; i++){ var w=arr[i]; var w1=generateSpaces(w.length); //см. ниже s=replace(s, w, w1); } } //Переводим строку в нижний регистр s=s.toLocaleLowerCase(); //Заменяем ё для целей сравнения s=s.replace(/ё/g, "е"); //Заменяем различные пробельные символы на пробел s=s.replace(/\s/g, " "); return s } ////////////////////////////////////// //Измеряет длину совпадения в символах для строк XRomix_s1 и XRomix_s2 начиная с указанных позиций p1 и p2 function checkCompareLength(p1, p2){ var c1=XRomix_s1.charAt(p1); var c2=XRomix_s2.charAt(p2); if(c1!=c2){ XRomix_len1=0; // XRomix_len2=0; return false; } var len1=XRomix_s1.length; var len2=XRomix_s2.length; var p1_=p1; //сохраняем позиции для вычисления длины var p2_=p2; var p1_nosp=-1; //позиция последнего совпадающего непробельного символа var p2_nosp=-1; for(;;){ if(p1>=len1) break; if(p2>=len2) break; c1=XRomix_s1.charAt(p1); c2=XRomix_s2.charAt(p2); if((c1==" ") && (c2==" ")){ //отыскиваем первый непробельный символ для p1 while(c1==" "){ p1++; c1=XRomix_s1.charAt(p1); if(p1>=len1) break; } //отыскиваем первый непробельный символ для p2 while(c2==" "){ p2++; c2=XRomix_s2.charAt(p2); if(p2>=len2) break; } } //Пропускаем мягкий перенос с кодом 173 (дес) или 0xAD if(c1=="\xAD"){ p1++; continue; } if(c2=="\xAD"){ p2++; continue; } //Пропускаем символ ударения if(c1=="́"){ p1++; continue; } if(c2=="́"){ p2++; continue; } if(c1==c2){ if(c1!=" ") p1_nosp=p1; if(c2!=" ") p2_nosp=p2; p1++; p2++; continue; } break; } if(p1_nosp==-1){ //не совпал ни один символ XRomix_len1=0; // XRomix_len2=0; }else{ XRomix_len1=p1_nosp-p1_+1; // XRomix_len2=p2_nosp-p2_+1; } return true; } //////////////////////////////////////////////////////////////////////////// //Отыскивает максимально совпадающий текст между XRomix_s1 и XRomix_s2 //Помещет его начальные указатели в XRomix_maxP1 и XRomix_maxP1, и длины в XRomix_max1 и XRomix_max1 function getMaxSameText(){ XRomix_maxP1=0; XRomix_maxP2=0; XRomix_max1=0; XRomix_max2=0; var arr1 = new Array(); //массивы позиций начала слова для ускорения поиска var arr2 = new Array(); //Заполняем массив позициями начала слова var c=" "; var wasSp=1; //признак наличия пробела до текущего символа for(var i=0; i<XRomix_s1.length; i++){ c=XRomix_s1.charAt(i); if(c<=" "){ wasSp=1; continue; }else{ if(wasSp==0) continue; //пропускаем не первые буквы каждого слова wasSp=0; arr1.push(i); } } //Для второй строки делаем то же самое var wasSp=1; //признак наличия пробела до текущего символа for(var i=0; i<XRomix_s2.length; i++){ c=XRomix_s2.charAt(i); if(c<=" "){ wasSp=1; continue; }else{ if(wasSp==0) continue; //пропускаем не первые буквы каждого слова wasSp=0; arr2.push(i); } } for(var i=0; i<arr1.length; i++){ var p1=arr1[i]; for(var j=0; j<arr2.length; j++){ var p2=arr2[j]; if(checkCompareLength(p1, p2)){ if (XRomix_len2>XRomix_max2){ //сравниваем по второму тексту, т.к. там нет викификации XRomix_max1=XRomix_len1; XRomix_max2=XRomix_len2; XRomix_maxP1=p1; XRomix_maxP2=p2; } } } } } ///////////////////////////////////////////////////////////////////////////// function selectInTextArea(txtarea, text1){ //Обрезаем многострочный текст до одной строки - иначе поиск не срабатывает var arr=text1.split(/[\n\r]/); var max=""; //найдем максимальную по длине строку из многострочного фрагмента for(var i=0; i<arr.length; i++){ if (max.length<arr[i].length){ max=arr[i]} } text=max; if (txtarea.setSelectionRange) {//Mozilla/Opera var selPos = txtarea.value.indexOf(text) if (selPos < 0) return txtarea.focus() txtarea.setSelectionRange(0, 0);//перейдем в начало //http://www.dynamicdrive.com/dynamicindex11/findpage.htm var caseSensitive = true // is search case sensitive? var backwards = false //should we also search backwards? var wrapAround = true // should we wrap the search? try{ self.find(text, caseSensitive, backwards, wrapAround); }catch(e){ } }else if (txtarea.createTextRange){ //IE var oRange = txtarea.createTextRange() if (oRange.findText(text)) oRange.select() } } //подсчитывает концы строк в фрагменте текста function countCrlf(str){ var cnt=0; for(var i=0; i<str.length; i++){ var c=str.charCodeAt(i); if (c==13){ cnt++; } } return cnt; } //Браузеро-независимый setSelectionRange - изменяет начало и конец //выделенного фрагмента в поле ввода input function setSelectionRange(input, start, end) { if (typeof wpTextbox1.selectionStart != 'undefined' && (navigator.productSub > 20031000 || is_safari)) { //Mozilla/Opera/Safari3 input.setSelectionRange(start, end); }else if (document.selection && document.selection.createRange) { //Internet Explorer var range = input.createTextRange(); range.collapse(true); range.moveStart("character", start - countCrlf(input.value.substring(0, start))); range.moveEnd("character", end - start - countCrlf(input.value.substring(start, end))); range.select(); } }; }//function ///////////////////////////////////////////////////////////////////////////// function XRomix_btnCompare2texts_Compare(){ XRomix_Compare2texts_Compare("first"); var wpSummary = document.getElementById('wpSummary') if(wpSummary){ var temp=wpSummary.value; temp=temp.replace(/\/\*.*?\*\// , ""); //комментарии temp=temp.replace(/[\s]*/ , ""); //пробелы if (temp==""){ var s=wpSummary.value; s+=" [[User talk:X-romix/compare2texts.js|compare2texts.js]] - поиск совпадений"; if (s.length<200) wpSummary.value=s; } } } //////////////////////////////////////////////////////////////////////////// function XRomix_btnCompare2texts_CompareNext(){ XRomix_Compare2texts_Compare("next"); }