/** SearchBox – wikitext search and replacement with RegExp support. v{version} Instrukcja obsługi (pl): https://pl.wikipedia.org/wiki/Wikipedia:Narz%C4%99dzia/Wyszukiwanie_i_zamiana Authors: [[:en:User:Zocky]], Maciej Jaros [[:pl:User:Nux]] Forked version by Zocky (2006-06-22): https://en.wikipedia.org/w/index.php?title=User:Zocky/SearchBox.js&oldid=60000195 Dev version: [[:pl:User:Nux/SearchBox.dev.js]] User version: [[:pl:MediaWiki:Gadget-searchbox.js]] Repo, bugz, pull requests: https://github.com/Eccenux/wiki-SearchBox */ /* eslint-disable array-bracket-newline */ /* eslint-disable no-useless-escape */ /* global mw, jQuery */ /* global sel_t, toolbarGadget */ /* Translatable strings */ mw.messages.set({ 'nuxsr-occurences-replaced': 'Zmieniono $1 wystąpień [$2] na [$3].', 'nuxsr-search-from-the-beginning': 'Wyszukiwanie od początku', 'nuxsr-search-title': 'Wyszukiwanie i zamiana (wer. $1)', 'nuxsr-search-alt': 'Szuk.', 'nuxsr-case-title': 'Zmiana wielkości liter', 'nuxsr-case-alt': 'Wlk. lit.', }); /** * Search and replace for MW code editor. */ function Nuxsr() { /** @type {String} App version */ this.version = '{version}'; } var nuxsr = new Nuxsr(); window.nuxsr = nuxsr; /** * Render HTML for the form. * @param {Object} options * {baseIndex:123} base index for tabindex. * Make sure this doesn't collide with othe fields on the page. * @returns search box code. */ nuxsr.boxHtml = function(options) { var ti = 100; if ('baseIndex' in options) { ti = options.baseIndex; } return '
' +'
' +'' +'znajdź:
' +'' +'
' +'' +'zamień na:
' +'' +'
' +'' +'' +'' +'
' +'< ' +'szukaj  >   ' +'< ' +'zamień ' +'>   ' +'zamień wszystkie   ' +'
' +'
' +'
' +'' +'MR' +'' +'   ' +'' +'Do wiersza:' +' ' +'' +'
' +'
' +'
' }; // // Variables set on page load // /** @type {Element} A textarea to search in (probably wpTextbox1). */ nuxsr.t = null; /** @type {Element} Gadget's main form (document.nuxsr_form). */ nuxsr.form = null; /** @type {Element} document.nuxsr_form.nuxsr.search */ nuxsr.s = null; /** @type {Element} document.nuxsr_form.nuxsr.replace */ nuxsr.r = null; /** @type {Element} The form container. */ nuxsr.srbox = null; /** @type {Element} SR messages textarea. */ nuxsr.messages = null; /** @type {Element} SR main button. */ nuxsr.searchButton = null; /* ===================================================== Common replace/search functions ===================================================== */ nuxsr.getSearchString = function () { var str = nuxsr.s.value; if (!nuxsr.form.nuxsr_regexp.checked) { str = str.replace(/([\[\]\{\}\|\.\*\?\(\)\$\^\\])/g,'\\$1'); } return str; }; nuxsr.getReplaceString = function () { var str = nuxsr.r.value; if (!nuxsr.form.nuxsr_regexp.checked) { // not needed //str=str.replace(/([\$\\])/g,'\\$1'); } else { //str=str.replace(/\\n/g,"\n").replace(/\\t/g,"\t").replace(/&backslash;/g,"\\").replace(/$/g,"\$") str = str.replace(/'/g,"\\'"); eval ("str='"+str+"'"); } return str; }; /** * Local storage key. */ nuxsr.storageKey = 'userjs.nuxsr'; /** * Save inputs to LS. */ nuxsr.saveInputs = function () { var data = { s:this.form.nuxsr_search.value, r:this.form.nuxsr_replace.value, case:this.form.nuxsr_case.checked, regexp:this.form.nuxsr_regexp.checked, }; localStorage.setItem(this.storageKey, JSON.stringify(data)); } /** * Restore inputs from LS. */ nuxsr.restoreInputs = function () { var raw = localStorage.getItem(this.storageKey); if (raw == null) { return false; } try { var data = JSON.parse(raw); } catch (error) { console.error('[nuxsr]', 'restoreInputs; error parsing object:', raw); } if (typeof data !== 'object') { return; } this.form.nuxsr_search.value = data.s; this.form.nuxsr_replace.value = data.r; this.form.nuxsr_case.checked = data.case; this.form.nuxsr_regexp.checked = data.regexp; return true; } /* ===================================================== Search functions ===================================================== */ nuxsr.back = function () { if (nuxsr.s.value==='') { nuxsr.t.focus(); return; } var searchString = nuxsr.getSearchString(); var selBB = sel_t.getSelBound(nuxsr.t); // set up greedy search to get the last match of the searchString searchString="^([\\s\\S]*)("+searchString+")"; var re=new RegExp(searchString, (nuxsr.form.nuxsr_case.checked ? "" : "i")); var res = re.exec (nuxsr.t.value.substring(0,selBB.start)); if (!res) { res = re.exec (nuxsr.t.value); } // set up selection if (res) { sel_t.setSelRange (nuxsr.t, res[1].length, res[1].length+res[2].length); } else { selBB.start = selBB.end; sel_t.setSelBound (nuxsr.t, selBB, false); } // move to selection nuxsr.sync(); }; nuxsr.next = function (norev) { if (nuxsr.s.value==='') { nuxsr.t.focus(); return; } var searchString = nuxsr.getSearchString(); var selBB = sel_t.getSelBound(nuxsr.t); // set up for search forward and execute var re=new RegExp(searchString, (nuxsr.form.nuxsr_case.checked ? "g" : "gi")); re.lastIndex=selBB.end; var res = re.exec (nuxsr.t.value); if (!res && !norev) { nuxsr.msg(mw.msg('nuxsr-search-from-the-beginning')); re.lastIndex=0; res = re.exec (nuxsr.t.value); } // set up selection if (res) { sel_t.setSelRange (nuxsr.t, res.index, res.index+res[0].length); } else { selBB.start = selBB.end; sel_t.setSelBound (nuxsr.t, selBB, false); } // move to selection nuxsr.sync(); }; /* ===================================================== Replace functions ===================================================== */ nuxsr.replace = function () { // // get string var str = sel_t.getSelStr(nuxsr.t, true); // // get attributes var searchString = nuxsr.getSearchString(); var replaceString = nuxsr.getReplaceString(); var selBB = sel_t.getSelBound(nuxsr.t); var re=new RegExp(searchString, (nuxsr.form.nuxsr_case.checked ? "g" : "gi")); // // replace var matchesArr = re.exec(str); // only full match counts if (matchesArr && matchesArr[0].length==str.length) { // run str = str.replace(re, replaceString); // save selection var sel_tmp = { start : selBB.start, strlen_post : str.length }; // replace in selection sel_t.qsetSelStr(nuxsr.t, str, true); // set new selection range sel_t.setSelRange (nuxsr.t, sel_tmp.start, sel_tmp.start + sel_tmp.strlen_post); } // // focus nuxsr.t.focus(); }; nuxsr.replaceAll = function () { // // get string var str = sel_t.getSelStr(nuxsr.t, true); // // get attributes var searchString = nuxsr.getSearchString(); var replaceString = nuxsr.getReplaceString(); var re=new RegExp(searchString, (nuxsr.form.nuxsr_case.checked ? "g" : "gi")); // // check for ocurrences var matchesArr = str.match(re); // // run str = str.replace(re, replaceString); // // output sel_t.qsetSelStr(nuxsr.t, str, true); // focus nuxsr.t.focus(); // // show num of ocurrences if (matchesArr) { nuxsr.msg(mw.msg('nuxsr-occurences-replaced', matchesArr.length, nuxsr.s.value, nuxsr.r.value)); } return; }; /* ===================================================== Toggle case functions ===================================================== */ nuxsr.toggleCase = function () { var selBB = sel_t.getSelBound(nuxsr.t); if (selBB.end>selBB.start) { var str = sel_t.getSelStr(nuxsr.t); if (str==str.toUpperCase()) { str = str.toLowerCase(); } else if (str==str.toLowerCase() && selBB.end-selBB.start>1) { str = str.substring(0,1).toUpperCase()+str.substring(1).toLowerCase(); } else { str = str.toUpperCase(); } // set selection with new value sel_t.setSelStr(nuxsr.t, str, false); } nuxsr.sync(); }; /* ===================================================== Move focus back to the textarea (previously moved selection to view) ===================================================== */ nuxsr.sync = function () { nuxsr.t.focus(); }; /* ===================================================== Box show/hide ===================================================== */ nuxsr.showHide = function() { var create = false; // first time? if ( !this.form ) { create = true; // // inserting search box var srbox = document.createElement( 'div' ); srbox.innerHTML = nuxsr.boxHtml({baseIndex:100}); srbox.firstChild.style.display = 'none'; var topEditor = document.querySelector('.wikiEditor-ui-top'); if (topEditor instanceof Element) { topEditor.appendChild(srbox); } else { jQuery(this.t).before(srbox); } this.srbox = srbox; this.form = document.nuxsr_form; this.s = document.nuxsr_form.nuxsr_search; this.r = document.nuxsr_form.nuxsr_replace; // init data (re)store nuxsr.restoreInputs(); jQuery('input', srbox).on('change', function(){ nuxsr.saveInputs(); }); } // // inserting message box if ( !this.messages ) { var el = document.createElement( 'textarea' ); el.cols = nuxsr.t.cols; el.style.cssText = nuxsr.t.style.cssText; el.rows = 5; //el.id = 'messages'; el.style.display = 'none'; el.style.width = '100%'; el.style.boxSizing = 'border-box' el.style.borderTop = '1px solid silver'; el.readOnly = true; nuxsr.messages = el; jQuery('.wikiEditor-ui').after(nuxsr.messages); } // setup show/hide and fix access key var hidding = false; if ( nuxsr.form.style.display == 'none' ) { if (nuxsr.messages.value.length) { nuxsr.messages.style.display = 'block'; } nuxsr.form.style.display = 'block'; nuxsr.searchButton.accessKey = "none"; nuxsr.s.focus(); } else { hidding = true; nuxsr.messages.style.display = 'none'; nuxsr.form.style.display = 'none'; nuxsr.searchButton.accessKey = "F"; } // usage: mw.hook('userjs.SearchBox.showHide').add(function (sr, hidding) {}); mw.hook('userjs.SearchBox.showHide').fire(nuxsr, hidding); // each time when shown if (!hidding) { mw.hook('userjs.SearchBox.show').fire(nuxsr); } // first time shown (form created) if (create) { mw.hook('userjs.SearchBox.create').fire(nuxsr); } } /* ===================================================== Go to a line given in the form field ===================================================== */ nuxsr.gotoLine = function () { if (nuxsr.form.nuxsr_goto_line.value=='') { nuxsr.t.focus(); return; } var lineno = parseInt(nuxsr.form.nuxsr_goto_line.value); // search for the line var index = (lineno==1) ? 0 : nuxsr.indexOfNthMatch (nuxsr.t.value, '\n', lineno-1); // set up selection if (index>=0) { if (index>0) // move after new line character { index++; } sel_t.setSelRange (nuxsr.t, index, index) } // move to selection nuxsr.sync(); } // little helper fun nuxsr.indexOfNthMatch = function (haystack, needle, n) { var index = -1; for (var i=1; i<=n && ((index=haystack.indexOf(needle, index+1)) != -1); i++) { if (i == n) { return index; } } return -1; } /* ===================================================== Memory module ===================================================== */ nuxsr.mem = { s : [ ' - ', // nie powinno łapać: class="wikitable sortable" // nie powinno łapać: |align="center"|abc "def" // powinno łapać: "a" '([^=])"([^|"\\]})> \\n\\t.,?;][^"]*?[^=| \\n\\t]|[^"|{}\\[\\]]{1,3})"([^>|])', ], r : [ ' – ', '$1„$2”$3', ] }; nuxsr.mem.index = -1; nuxsr.mem.remind = function() { nuxsr.mem.index++; nuxsr.mem.index%=nuxsr.mem.s.length; nuxsr.s.value = nuxsr.mem.s[nuxsr.mem.index]; nuxsr.r.value = nuxsr.mem.r[nuxsr.mem.index]; } nuxsr.mass_rep_htmlspecialchars = { s : ['&', '>', '<'], r : ['&', '>', '<'] }; nuxsr.mass_rep = function (obj) { // // always as regExp // var prev_ser_RE = nuxsr.form.nuxsr_regexp.checked; nuxsr.form.nuxsr_regexp.checked = true; /* // // always from the beginning // var selBB = {start:0, end:0}; sel_t.setSelBound(nuxsr.t, selBB, false); */ // // Set up selection vars // var selBB = sel_t.getSelBound(nuxsr.t); var field_len = nuxsr.t.value.length; var field_len_diff = 0; // // replace // for (var i=0; i