/** * Description: Restore deleted lines easier while you are editing and viewing changes * Documentation: [[User:Aram/diff restorer]] * Version: 1.0.3 */'use strict';mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Aram/diff_restorer.css&action=raw&ctype=text/css','text/css');functiongetInsertPosition(element,content){constinitialLineRow=element.closest('tr').prevAll('tr').find('td.diff-lineno:first');if(!initialLineRow.length)returnnull;constlineText=initialLineRow.text();// Transform the text by replacing separators and converting digitsletnormalizedText=lineText;constseparatorMap=mw.language.getSeparatorTransformTable();Object.entries(separatorMap).forEach(([latin,local])=>{normalizedText=normalizedText.replace(newRegExp(local,'g'),latin);});constdigitMap=mw.language.getDigitTransformTable();digitMap.forEach((latin,index)=>{normalizedText=normalizedText.replace(newRegExp(latin,'g'),index);});// Extract all numbers from the textconstnumbers=normalizedText.match(/\d+/g);if(!numbers||numbers.length===0)returnnull;// Use the last number when moving from bottom to topconstexactLineNumber=parseInt(numbers[numbers.length-1]);// Count non-deleted rows between current position and initial lineconstprevRows=element.closest('tr').prevUntil(initialLineRow.closest('tr')).not(':has(td.diff-empty.diff-side-deleted)');constlineNumber=exactLineNumber+prevRows.length;constlines=content.split('\n');// If line number exceeds content length, return end of contentif(lineNumber>lines.length)returncontent.length;// Calculate insert positionreturnlines.slice(0,lineNumber-1).join('\n').length+(lineNumber>1?1:0);}(function(){functionaddRestoreButtons(){$('table.diff tbody tr:not(.diff-title) .diff-side-deleted:not(.diff-context)').each(function(){vardeletedLine=$(this);varaddedLine=deletedLine.closest('tr').find('.diff-side-added');varmovedPara=deletedLine.closest('tr').find('.mw-diff-movedpara-left');if(movedPara.length){vartargetAnchor=movedPara.attr('href').substring(1);addedLine=$('.diff-side-added').has('a[name="'+targetAnchor+'"]');}if(!addedLine.length)return;varrestoreBtn=$('<span>').addClass('restore-btn').attr('title','Restore this line').click(function(){vareditBox=$('#wpTextbox1');if(!editBox.length||editBox.css('display')==='none'){mw.notify('Edit box not found. Please ensure you are in edit mode, or if you are, turn off code editor',{type:'error',autoHide:false});return;}vareditContent=editBox.val();vardeletedText=deletedLine.text();varsuccess=false;if(movedPara.length){varaddedText=addedLine.text();varcurrentPosition=editContent.indexOf(addedText);if(currentPosition!==-1){varcontentWithoutMoved=editContent.substring(0,currentPosition)+editContent.substring(currentPosition+addedText.length+(editContent[currentPosition+addedText.length]==='\n'?1:0));vartargetPosition=getInsertPosition(deletedLine,contentWithoutMoved);if(targetPosition!==null){editBox.val(contentWithoutMoved.substring(0,targetPosition)+deletedText+'\n'+contentWithoutMoved.substring(targetPosition));success=true;}}}elseif(addedLine.hasClass('diff-empty')||addedLine.find('br').length){varposition=getInsertPosition(deletedLine,editContent);if(position!==null){varnewContent=addedLine.hasClass('diff-empty')?editContent.substring(0,position)+deletedText+'\n'+editContent.substring(position):editContent.substring(0,position)+editContent.substring(position+1);editBox.val(newContent);success=true;}}elseif(editContent.includes(addedLine.text())){editBox.val(editContent.replace(addedLine.text(),deletedText));success=true;}restoreBtn.addClass(success?'restore-success':'restore-fail').off('click');});deletedLine.append(restoreBtn);});}mw.hook('wikipage.diff').add(addRestoreButtons);})();