User:KarenGrigMan/OldEraScript.js

/*jshint esversion: 8 */ $(function{

var isScriptOff = false; var shouldTranslateYearsPrecisely = false; var shouldTranslateDatesInBookTitles = false; var shouldTranslateDatesInQuotes = false; var imagesLastUpdatedOnServerAt = (new Date('2022-09-09T18:31:00')).getTime; var isMobile = window.location.host.includes('.m.'); if(isMobile){ var settingsButton = document.createElement('button'); settingsButton.id = "p-oesettings-button"; settingsButton.innerText = "OE"; settingsButton.style.width = "50px"; var firstHeading = document.getElementById('firstHeading'); firstHeading.appendChild(settingsButton); firstHeading.style.display = "flex"; firstHeading.style.justifyContent = "space-between"; }else{ mw.util.addPortletLink ( 'p-views', "#", 'OE', 'p-oesettings-button', 'Open date conversion settings' ); }   getConfigFromLocalStorage; var isSettingsDivVisible = false; document.getElementById('p-oesettings-button').addEventListener('click',function(e) {       e.preventDefault;        isSettingsDivVisible = !isSettingsDivVisible;        if(isSettingsDivVisible){            renderSettings;        }else{            removeListeners;            var settingsDiv = document.getElementById('oe-settings-div');            settingsDiv.parentElement.removeChild(settingsDiv);        }    }); function removeListeners{ var scriptOffButton = document.getElementById('toggleOnOff'); scriptOffButton.removeEventListener('click',scriptOffCheckboxChanged); var closeSettingsButton = document.getElementById('closePopup'); closeSettingsButton.removeEventListener('click',closeSettingsButtonPressed); var translatePreciselyCheckbox = document.getElementById('TranslateYearsPreciselyCheckbox'); translatePreciselyCheckbox.removeEventListener('change',translatePreciselyCheckboxChanged); var translateDatesInBookTitlesCheckbox = document.getElementById('TranslateInBookTitlesCheckbox'); translateDatesInBookTitlesCheckbox.removeEventListener('change', translateDatesInBookTitlesCheckboxChanged); var translateDatesQuotesCheckbox = document.getElementById('TranslateInQuotesCheckbox'); translateDatesQuotesCheckbox.removeEventListener('change', translateDatesQuotesCheckboxChanged); }   var settingsHTML = `  Toggle on/off Close

Settings  always translate years precisely  translate dates in book titles  translate dates in quotes

Links Old Era White paper Interactive timeline</a> `;   function renderSettings{ $('#content').prepend(settingsHTML); var scriptOffButton = document.getElementById('toggleOnOff'); scriptOffButton.innerText = isScriptOff ? 'Turn on' : 'Turn off'; scriptOffButton.addEventListener('click',scriptOffCheckboxChanged); var closeSettingsButton = document.getElementById('closePopup'); closeSettingsButton.addEventListener('click',closeSettingsButtonPressed); var translatePreciselyCheckbox = document.getElementById('TranslateYearsPreciselyCheckbox'); translatePreciselyCheckbox.checked = shouldTranslateYearsPrecisely; translatePreciselyCheckbox.addEventListener('change', translatePreciselyCheckboxChanged); var translateDatesInBookTitlesCheckbox = document.getElementById('TranslateInBookTitlesCheckbox'); translateDatesInBookTitlesCheckbox.checked = shouldTranslateDatesInBookTitles; translateDatesInBookTitlesCheckbox.addEventListener('change', translateDatesInBookTitlesCheckboxChanged); var translateDatesQuotesCheckbox = document.getElementById('TranslateInQuotesCheckbox'); translateDatesQuotesCheckbox.checked = shouldTranslateDatesInQuotes; translateDatesQuotesCheckbox.addEventListener('change', translateDatesQuotesCheckboxChanged); }   function closeSettingsButtonPressed(e){ e.preventDefault; isSettingsDivVisible = false; removeListeners; var settingsDiv = document.getElementById('oe-settings-div'); settingsDiv.parentElement.removeChild(settingsDiv); }   function scriptOffCheckboxChanged(e){ e.preventDefault; isScriptOff = !isScriptOff; localStorage.setItem('OE-isScriptOff',isScriptOff ? 1 : 0); var scriptOffButton = document.getElementById('toggleOnOff'); scriptOffButton.innerText = isScriptOff ? 'Turn on' : 'Turn off'; updateTranslation; }   function translatePreciselyCheckboxChanged(e){ e.preventDefault; shouldTranslateYearsPrecisely = !shouldTranslateYearsPrecisely; localStorage.setItem('OE-shouldTranslateYearsPrecisely',shouldTranslateYearsPrecisely ? 1 : 0); updateTranslation; }   function translateDatesInBookTitlesCheckboxChanged(e){ e.preventDefault; shouldTranslateDatesInBookTitles = !shouldTranslateDatesInBookTitles; localStorage.setItem('OE-shouldTranslateDatesInBookTitles',shouldTranslateDatesInBookTitles ? 1 : 0); updateTranslation; }   function translateDatesQuotesCheckboxChanged(e){ e.preventDefault; shouldTranslateDatesInQuotes = !shouldTranslateDatesInQuotes; localStorage.setItem('OE-shouldTranslateDatesInQuotes',shouldTranslateDatesInQuotes ? 1 : 0); updateTranslation; }   //CONSTANTS=====================; var numbersFromWords = { 'first': 1, 'second': 2, 'third': 3, 'fourth': 4, 'fifth': 5, 'sixth': 6, 'seventh': 7, 'eighth': 8, 'ninth': 9, 'tenth': 10, 'eleventh': 11, 'twelfth': 12, 'thirteenth': 13, 'fourteenth': 14, 'fifteenth': 15, 'sixteenth': 16, 'seventeenth': 17, 'eighteenth': 18, 'nineteenth': 19, 'twentieth': 20, 'twenty-first': 21, 'twenty-second': 22, 'twenty-third': 23, 'twenty-fourth': 24, 'twenty-fifth': 25, 'twenty-sixth': 26, 'twenty-seventh': 27, 'twenty-eighth': 28, 'twenty-ninth': 29, 'thirtieth': 30, 'thirty-first': 31, 'thirty-second': 32, 'thirty-third': 33, 'thirty-fourth': 34, 'thirty-fifth': 35 };   var ordinalNumberWords = [ 'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth', 'eleventh', 'twelfth', 'thirteenth', 'fourteenth', 'fifteenth', 'sixteenth', 'seventeenth', 'eighteenth', 'nineteenth', 'twentieth', 'twenty-first', 'twenty-second', 'twenty-third', 'twenty-fourth', 'twenty-fifth', 'twenty-sixth', 'twenty-seventh', 'twenty-eighth', 'twenty-ninth', 'thirtieth', 'thirty-first', 'thirty-second', 'thirty-third', 'thirty-fourth', 'thirty-fifth' ];   var monthNames = [ 'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december', ];   var methodConversions = { 'bc-y': 'year', 'bc-y1': 'oneDigitYear', 'bc-y2': 'twoDigitYear', 'bc-i': 'impreciseYear', 'bc-i2': 'bc-i2',//twoDigitImpreciseYear //1070/60 BC      'bc-d': 'decade', 'bc-sd': 'bc-sd',//'shortDecade' 'bc-dp': 'bc-dp',//decades (plural) 'bc-00s': '00s', 'bc-000s': '000s', 'bc-c': 'century', 'bc-m': 'millennium', 'bc-r': 'remove', 'bc-ig': 'bc-ig',//ignore 'bc-tn': 'OE', // Old Era timelineName 'bc-ot': 'ofOE', //of the Old Era ofTimeline 'bc-at': 'abbreviatedTimeline', //OE //the following classes should not be used in markup 'bc-ybc': 'bc-ybc',// add BC to year before 10,000 BC      'bc-yoe': 'bc-yoe',// add OE to year no matter what 'bc-ioe': 'bc-ioe',// add OE to year no matter what 'bc-y_': 'bc-y_',// don't use label no matter what 'bc-i_': 'bc-i_'// don't use label no matter what };   //PATTERNS================; var spacePattern = ' |\\s|\\ |\\&#160;|\\&#8201;'; var completeSpacePattern = `(<span[^>]*?>)(${spacePattern})|${spacePattern}`; var bcPattern = `(${completeSpacePattern}|-)((b\\.(${completeSpacePattern})?c\\.?|bc)e?|(bce?) )`; var methods = Object.keys(methodConversions).join('|'); var rangePattern = `(${spacePattern})?(—|−|–|-|\\&#8211;|\\–|\\&#8212;|\\&mdash;|or|to|to late|to early|to the|and|and late|and early|-to-|until|till|through)(${spacePattern})?`; var dashPattern = `(${spacePattern})?(—|−|–|-|\\&#8211;|\\–|\\&#8212;|\\&mdash;)(${spacePattern})?`; var nakedYearPattern = '\\b([1-9][0-9]{0,2},[0-9]{3}|[0-9]{1,4}|10000|10,000)(?!\\])\\b'; var roundNakedYearPattern = '\\b[0-9]{1,3},?000(?!\\])\\b'; var altCenturiesAndMillenniaMarkupPattern = `((bc-c|bc-m)( data-t="([^>]*?)")?( data-s="[^>]*?")?>)([^<]*?)</(bc-c|bc-m)>(${completeSpacePattern}|-)(century|centuries|cent\\.|c\\.|millennium|millennia))(${bcPattern})`;   var altMarkupWithInnerSpansPattern = `(<(${methods})( data-t="([^>]*?)")?( data-s="([^>]*?)")?>)([^<]*?)(<span[^>]*?>)(.)([^<]*?)</(${methods})>`;    var altGeneralMarkupPattern = `(<(${methods})( data-t="([^>]*?)")?( data-s="([^>]*?)")?>)([^<]*?)</(${methods})>`;    var centuriesAndMillenniaMarkupPattern = `((<span class="(bc-c|bc-m)"( data-t="([^>]*?)")?( data-s="[^>]*?")?>)([^<]*?) (${completeSpacePattern}|-)(century|centuries|cent\\.|c\\.|millennium|millennia))(${bcPattern})`;    var markupWithInnerSpansPattern = `(<span class="(${methods})"( data-t="([^>]*?)")?( data-s="([^>]*?)")?>)([^<]*?)(<span[^>]*?>)(.)([^<]*?) `;    var generalMarkupPattern = `(<span class="(${methods})"( data-t="([^>]*?)")?( data-s="([^>]*?)")?>)([^<]*?) `; var yearListRange = `((${spacePattern})?(—|−|–|-|\\&#8211;|\\–|\\&#8212;|\\&mdash;|, |or|to|to the|and|-to-|until|till)(${spacePattern})?)`; var nakedDatePattern = '\\b[0-9]{1,2}(?!\\])\\b'; var supPattern = '<sup((?!<sup).)*? ';   var negativeLookaheadPattern = '(?<!<[^>]*?)'; var nakedDecadePattern = "[0-9]{0,3}0'?s"; var decadePattern = `(${nakedDecadePattern})${bcPattern}`; var decadeRangePattern = `((${nakedDecadePattern})(${spacePattern})?(${rangePattern})(${spacePattern})?)((${nakedDecadePattern})${bcPattern})`; var nakedCenturyPattern = `\\b((\\d+(st|nd|rd|th))|${ordinalNumberWords.join('|')})\\b`; var centuriesPattern = `((${nakedCenturyPattern})(${completeSpacePattern}|-)(century|centuries|cent\\.|c\\.))(${bcPattern})`; var millenniumPattern = `((${nakedCenturyPattern})(${completeSpacePattern}|-)(millennium|millennia))(${bcPattern})`; var yearMonthRangePattern = `(${nakedYearPattern})(${supPattern})?(${rangePattern})((${nakedDatePattern})(${spacePattern}))?(${monthNames.join('|')})(/(${monthNames.join('|')}))?(${spacePattern})(${nakedYearPattern}${bcPattern})`; var leftFraction = `(${nakedYearPattern})(${supPattern})?/`; var leftPartOfYearRangePattern = `((((${leftFraction})?((${nakedYearPattern})(${supPattern})??)`;   var middleOfYearRangePattern = `(${rangePattern})((c\\.|around)(${completeSpacePattern}))?)`; var rightPartOfYearRangePattern = `(${leftFraction})?))((${nakedYearPattern})?(${supPattern})?(${bcPattern}))`; var simpleYearRangePattern = `((${nakedYearPattern})(${rangePattern}))((${nakedYearPattern})(${bcPattern}))`; var yearRangePattern = `${leftPartOfYearRangePattern}${middleOfYearRangePattern}${rightPartOfYearRangePattern}`; var roundYearRangePattern = `((${roundNakedYearPattern})(${rangePattern}))((${roundNakedYearPattern})${bcPattern})`; var yearRangeWithCircasPattern = `((<span [^>]*?>)?(${spacePattern}))(${nakedYearPattern})?${rangePattern}( c. |c.| c. )(<span [^>]*?>)?(${spacePattern})(${nakedYearPattern}?${bcPattern})`; var yearPattern = `(${leftFraction})?((${nakedYearPattern})?(${supPattern})?(${bcPattern}))`; var yearInListPattern = `(${nakedYearPattern})(${supPattern})?`; var longYearListPattern = `(${yearInListPattern}${yearListRange})?(${yearInListPattern}${yearListRange})?(${yearInListPattern}${yearListRange})?(${yearInListPattern}${yearListRange})?(${yearInListPattern}${yearListRange})?(${yearInListPattern}${yearListRange})?(${yearInListPattern}),?${yearListRange}${nakedYearPattern}${bcPattern}`; var monthBeforeNumberPattern = `(${monthNames.join('|')})(${completeSpacePattern})$`; var centuryRangePattern = `(${nakedCenturyPattern})-?(${rangePattern})(${nakedCenturyPattern})(${spacePattern}|-)(century|centuries)${bcPattern}`; var millenniumRangePattern = `(${nakedCenturyPattern})-?(${rangePattern})(${nakedCenturyPattern})(${spacePattern}|-)(millennium|millennia)${bcPattern}`; var h2Pattern = ` <span[^>]*?> <span class="mw-headline"[^>]*?>(.*?) <IgnoredPart> `; var yearInMarkUpWithInnerSpansPattern = `(<span class="(bc-y|bc-i)"( data-t="([^>]*?)")?( data-s="([^>]*?)")?>)([^<]*?)(<span[^>]*?>)(.)([^<]*?) `; var yearInMarkupPattern = `(<span class="(bc-y|bc-i)"( data-t="([^>]*?)")?( data-s="([^>]*?)")?>)([^<]*?) `; var yearRangeInMarkupWithInnerSpansPattern = `(((${yearInMarkupPattern}|${nakedYearPattern}|${roundNakedYearPattern}))${rangePattern})${yearInMarkUpWithInnerSpansPattern}`; var yearRangeInMarkupPattern = `((${yearInMarkupPattern}|${nakedYearPattern}|${roundNakedYearPattern})${rangePattern})${yearInMarkupPattern}`; var yearRangeWithFirstYearInMarkupPattern = `(${yearInMarkupPattern}${rangePattern})${yearPattern}`; //MARKUP PATTERN PROCESSORS=================; function ignoreSecondYearInRangeWithInnerSpansIfNeeded(html, replacementsArray) { var result; var reg = giReg(yearRangeInMarkupWithInnerSpansPattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var stringTillBeginingOfYear2Span = result[1] || ''; var year1StringWithoutMarkup = result[3] || ''; var method1 = result[5] || ''; var substitute1 = result[9] || ''; var year1String = result[10] || ''; var mainYear2SpanOpening = result[15] || ''; var substitute2 = result[20] || ''; var nakedYear2String = result[21] || ''; var spanOpening = result[22] || ''; var spanSpace = result[23] || ''; var spanClosing = result[24] || ''; var nakedBC = result[25] || ''; var year1 = 0; if (!method1) { year1 = numberFromString(year1StringWithoutMarkup); } else { year1 = numberFromString(substitute1 ? substitute1 : year1String); }           if (year1 > 10000) { var index = result.index + stringTillBeginingOfYear2Span.length + mainYear2SpanOpening.length; addReplacement(replacementsArray, 'bc-ig', nakedYear2String, index, false); index += nakedYear2String.length + spanOpening.length; addReplacement(replacementsArray, 'bc-ig', spanSpace, index, false); index += spanSpace.length + spanClosing.length; addReplacement(replacementsArray, 'bc-ig', nakedBC, index, false); }       }    }    function isPatternInsideTag(html,indexOfPattern){ var index = indexOfPattern - 1; while(true){ var char = html[index]; if(char === '<')return true; if(char === '>')return false; if(index <= 0)return false; index--; }   }    function isPatternAfterMonthName(html,indexOfPattern){ var firstIndex = indexOfPattern - 20; if(firstIndex<0)firstIndex = 0; var previousText = html.slice(firstIndex,indexOfPattern); var reg = new RegExp(monthBeforeNumberPattern,'gi'); var result = reg.exec(previousText); return result !== null; }   function ignoreSecondYearInRangeWithoutInnerSpansIfNeeded(html, replacementsArray) { var result; var reg = giReg(yearRangeInMarkupPattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var stringTillBeginingOfYear2Span = result[1] || ''; var year1StringWithoutMarkup = result[2] || ''; var method1 = result[4] || ''; var substitute1 = result[8] || ''; var year1String = result[9] || ''; var mainYear2SpanOpening = result[14] || ''; var year2String = result[20] || ''; var year1 = 0; if (!method1) { year1 = numberFromString(year1StringWithoutMarkup); } else { year1 = numberFromString(substitute1 ? substitute1 : year1String); }           if (year1 === 0 || year1 > 10000) { var index = result.index + stringTillBeginingOfYear2Span.length + mainYear2SpanOpening.length; addReplacement(replacementsArray, 'bc-ig', year2String, index, false); }       }    }    function ignoreSecondYearInRangeWhenOnlyFirstIsInMarkup(html, replacementsArray) { var result; var reg = giReg(yearRangeWithFirstYearInMarkupPattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var stringTillYear2 = result[1] || ''; var year1String = result[8] || ''; var year2FullString = result[17] || ''; var year2NakedString = result[18] || ''; var sup = result[21] || ''; var fullBC = result[23] || ''; var spanOpening = result[25] || ''; var spanSpace = result[26] || ''; var spanClosing = result[27] || ''; var nakedBC = result[28] || ''; var year1 = numberFromString(year1String); if (year1 === 0 || year1 > 10000) { var index = result.index + stringTillYear2.length; if (!sup && !spanOpening) { addReplacement(replacementsArray, 'bc-ig', year2FullString, index, false); } else { addReplacement(replacementsArray, 'bc-ig', year2NakedString, index, false); index += year2NakedString.length + sup.length; if (!spanOpening) { addReplacement(replacementsArray, 'bc-ig', fullBC, index, false); } else { index += spanOpening.length; addReplacement(replacementsArray, 'bc-ig', spanSpace, index, false); index += spanSpace.length + spanClosing.length; addReplacement(replacementsArray, 'bc-ig', nakedBC, index, false); }               }            }        }    }    function createYearRangeReplacementsFromMarkup(html, replacementsArray) { var result; var reg = giReg(yearRangeInMarkupWithInnerSpansPattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var stringTillBeginingOfYear2Span = result[1]; var stringTillYear1 = result[2] || ''; var year1StringWithoutMarkup = result[3] || ''; var method1 = result[5] || ''; var type1 = result[7] || ''; var substitute1 = result[9] || ''; var year1String = result[10] || ''; var mainYear2SpanOpening = result[15] || ''; var method2 = result[16] || ''; var substitute2 = result[20] || ''; var nakedYear2String = result[21] || ''; var spanOpening = result[22] || ''; var spanSpace = result[23] || ''; var spanClosing = result[24] || ''; var nakedBC = result[25] || ''; var year1 = 0; if (!method1) { year1 = numberFromString(year1StringWithoutMarkup); } else { year1 = numberFromString(substitute1 ? substitute1 : year1String); }           if (year1 === 0 || year1 > 10000) { var index = result.index + stringTillBeginingOfYear2Span.length + mainYear2SpanOpening.length; addReplacement(replacementsArray, 'bc-ig', nakedYear2String, index, false); index += nakedYear2String.length + spanOpening.length; addReplacement(replacementsArray, 'bc-ig', spanSpace, index, false); index += spanSpace.length + spanClosing.length; addReplacement(replacementsArray, 'bc-ig', nakedBC, index, false); }       }    }    function createCenturiesAndMillenniaReplacementsFromMarkup(html, replacementsArray) { var result; var reg = giReg(centuriesAndMillenniaMarkupPattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var stringTillBC = result[1] || ''; var spanOpening = result[2] || ''; var method = result[3] || ''; var centuryString = result[7] || ''; var bcSpanOpening = result[15] || ''; var space = result[16] || ''; var centMill = result[12] || ''; var bc = result[13] || ''; var totalBCSpan = result[14] || ''; var nakedBC = result[18] || ''; var type = result[5] || ''; var spaceBeforeSmallTag = result[14] || ''; var smallTag = result[24] || ''; var smallBC = result[25] || ''; if (method === 'bc-m' && (centMill === 'millennium' || centMill === 'millennia')) { method = 'millennium'; } else if (method === 'bc-c') { method = 'century'; } else { return; }           type = convertTypeFromMakup(type); var index = result.index + spanOpening.length; addReplacement(replacementsArray, method, centuryString, index, false, type); if(smallTag){ var index = result.index + stringTillBC.length; addReplacement(replacementsArray, 'remove', spaceBeforeSmallTag, index, false, type); index += spaceBeforeSmallTag.length + smallTag.length; addReplacement(replacementsArray, 'remove', smallBC, index, false, type); }else if (bcSpanOpening.length) { var index = result.index + stringTillBC.length + bcSpanOpening.length; addReplacement(replacementsArray, 'remove', space, index, false, type); index = result.index + stringTillBC.length + totalBCSpan.length; addReplacement(replacementsArray, 'remove', nakedBC, index, false, type); } else { var index = result.index + stringTillBC.length; addReplacement(replacementsArray, 'remove', bc, index, false, type); }       }    }    function createYearReplacementsWithInnerSpansFromMarkup(html, replacementsArray) { var result; var reg = giReg(markupWithInnerSpansPattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var spanOpening = result[1] || ''; var method = result[2] || ''; var type = result[4] || ''; var substitute = result[6] || ''; var target = result[7] || ''; var bcSpanOpening = result[8] || ''; var space = result[9] || ''; var bcSpanClosing = result[10] || ''; var bc = result[11] || ''; if(target.includes('class="bc-'))continue;           method = methodConversions[method];            if (['year', 'impreciseYear'].includes(method)) {                var year = numberFromString(target);                if (year === 0 || year > 10000) {                    method = 'bc-ig';                }            }            type = convertTypeFromMakup(type);            var index = result.index + spanOpening.length;            addReplacement(replacementsArray, method, target, index, true, type, substitute);            var removingMethod = method === 'bc-ig' ? 'bc-ig' : 'remove';            index += target.length + bcSpanOpening.length;            addReplacement(replacementsArray, removingMethod, space, index, true, type, substitute);            index += space.length + bcSpanClosing.length;            addReplacement(replacementsArray, removingMethod, bc, index, true, type, substitute); }   }    function createReplacementsFromMarkup(html, replacementsArray) { var result; var reg = giReg(generalMarkupPattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var spanOpening = result[1] || ''; var method = result[2] || ''; var type = result[4] || ''; var substitute = result[6] || ''; var target = result[7] || ''; var index = result.index + spanOpening.length; method = methodConversions[method]; type = convertTypeFromMakup(type); if (['year', 'impreciseYear'].includes(method)) { var year = numberFromString(target); if (year === 0 || year > 10000) { method = 'bc-ig'; }           }            addReplacement(replacementsArray, method, target, index, true, type, substitute); }   }    function findH2Headlines(html, replacementsArray){ var result; var reg = new RegExp(h2Pattern, "gi"); while ((result = reg.exec(html))) { var headline = result[1] || ''; if(!headline)continue; processOneHeadline(headline, html, replacementsArray); }   }    function processOneHeadline(headline, html, replacementsArray){ var reg = new RegExp(generalMarkupPattern, "gi"); var firstSpanReg = new RegExp(`<span class="bc-[^>]*>`,"gi");       var resultsArray = [];        while ((result = reg.exec(headline))) {            var method = result[2] || ;            var type = result[4] || ;            var originalSubstitute = result[6] || ;            var target = result[7] || ;            type = convertTypeFromMakup(type);            method = methodConversions[method];            resultsArray.push({method,type,target, originalSubstitute});        }        if(resultsArray.length == 0)return;        var cleanHeader = headline.replace(firstSpanReg,' ');        var cleanHeaderReg = new RegExp(escapeText(cleanHeader), "gi");        var res = cleanHeaderReg.exec(html);        var mainIndex = res.index;        for (var i = 0; i < resultsArray.length; i++) {            var {method,type,target, originalSubstitute} = resultsArray[i];            var cleanSpanReg = new RegExp(`(${target}) `, 'i'); var localIndex = cleanHeader.search(cleanSpanReg) + ' '.length; if(localIndex < 0)return; var index = mainIndex + localIndex; addReplacement(replacementsArray, method,target,index, false, type, originalSubstitute); }   }    //PATTERN PROCESSORS=====================; function processLongYearListPattern(html, replacementsArray, pageData) { var result; var yearReg = giReg(nakedYearPattern); var reg = giReg(longYearListPattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var fullString = result[0]; var yearResult; var instances = []; while (yearResult = yearReg.exec(fullString)) { var index = result.index + yearResult.index; if(isPatternAfterMonthName(html,index))continue; var target = yearResult[0]; var year = numberFromString(target); if (year > 10000 || year === 0) return; instances.push({index,target}); }           instances.pop; instances.forEach(function({ index, target }) {               var method = methodForYear(numberFromString(target),pageData);                addReplacement(replacementsArray,method,target,index, true);            }); }   }    function processRoundYearRangePattern(html, replacementsArray, pageData) { var result; var reg = giReg(roundYearRangePattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var stringTillSecondYear= result[1]; var firstYearString = result[2]; var fullSecondYearString = result[7]; var nakedSecondYearString = result[8]; var spanOpening = result[10]; var spanSpace = result[11]; var spanClosing = result[12]; var nakedBC = result[13]; var spaceBeforeSmallTag = result[9]; var smallTag = result[19]; var smallBC = result[20]; var method1 = 'year'; var method2 = 'year'; var firstYear = numberFromString(firstYearString); var secondYear = numberFromString(nakedSecondYearString); var {isPageAboutEarlyCenturyOrMillennium} = pageData; if (!isPageAboutEarlyCenturyOrMillennium && firstYear >= 3000) { method1 = 'impreciseYear'; }           if (!isPageAboutEarlyCenturyOrMillennium && secondYear >= 3000) { method2 = 'impreciseYear'; }           if(firstYear > 10000 && secondYear > 10000){ method1 = 'bc-ig'; method2 = 'bc-ig'; }else if(firstYear > 10000 && secondYear <= 10000){ method1 = 'bc-ybc'; method2 = method2 === 'impreciseYear' ? 'bc-ioe' : 'bc-yoe'; }else if (firstYear <= 10000 && secondYear < firstYear){ method1 = method1 === 'year' ? 'bc-y_' : 'bc-i_'; if(shouldUseDotNotation && Math.floor(firstYear/100) === Math.floor(secondYear/100)){ method2 = method2 === 'year' ? 'yearShort' : 'impreciseYearShort'; }           }            addReplacement(replacementsArray, method1, firstYearString, result.index); var index = result.index + stringTillSecondYear.length; if(smallTag){ addReplacement(replacementsArray, method2, nakedSecondYearString, index); if (method2 !== 'bc-ig') method2 = 'remove'; index += nakedSecondYearString.length; addReplacement(replacementsArray, method2, spaceBeforeSmallTag, index); index += spaceBeforeSmallTag.length + smallTag.length; addReplacement(replacementsArray, method2, smallBC, index); }else if (!spanOpening) { addReplacement(replacementsArray, method2, fullSecondYearString, index); } else { addReplacement(replacementsArray, method2, nakedSecondYearString, index); if (method2 !== 'bc-ig') method2 = 'remove'; index += nakedSecondYearString.length + spanOpening.length; addReplacement(replacementsArray, method2, spanSpace, index); index += spanSpace.length + spanClosing.length; addReplacement(replacementsArray, method2, nakedBC, index); }       }    }    function processSimpleYearRangePattern(html, replacementsArray,pageData) { var result; var reg = giReg(simpleYearRangePattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var stringTillBeginingOfYear2 = result[1] || ''; var year1String = result[3] || ''; var year2FullString = result[8] || ''; var year2StringBeforeSpan = result[10] || ''; var spanOpening = result[13] || ''; var spaceInSpan = result[14] || ''; var spanClosing = result[15] || ''; var bcAfterSpan = result[16] || ''; var year2StringBeforeSmallTag = result[10] || ''; var smallTag = result[22] || ''; var spaceBeforeSmallTag = result[12] || ''; var smallBC = result[23] || ''; var method1 = 'year'; var method2 = 'year'; var firstYear = numberFromString(year1String); var secondYear = numberFromString(year2FullString); var {isPageAboutEarlyCenturyOrMillennium} = pageData; if (!isPageAboutEarlyCenturyOrMillennium && firstYear >= 3000) { method1 = 'impreciseYear'; }           if (!isPageAboutEarlyCenturyOrMillennium && secondYear >= 3000) { method2 = 'impreciseYear'; }           if(firstYear > 10000 && secondYear > 10000){ method1 = 'bc-ig'; method2 = 'bc-ig'; }else if(firstYear > 10000 && secondYear <= 10000){ method1 = 'bc-ybc'; method2 = method2 === 'impreciseYear' ? 'bc-ioe' : 'bc-yoe'; }else if (firstYear <= 10000 && secondYear < firstYear){ method1 = method1 === 'year' ? 'bc-y_' : 'bc-i_'; if(shouldUseDotNotation && Math.floor(firstYear/100) === Math.floor(secondYear/100)){ method2 = method2 === 'year' ? 'yearShort' : 'impreciseYearShort'; }           }            var index = result.index; addReplacement(replacementsArray, method1, year1String, index); if(spanOpening){ index += stringTillBeginingOfYear2.length; addReplacement(replacementsArray, method2, year2StringBeforeSpan, index); if (method2 !== 'bc-ig') method2 = 'remove'; index += year2StringBeforeSpan.length + spanOpening.length; addReplacement(replacementsArray, method2, spaceInSpan, index); index += spaceInSpan.length + spanClosing.length; addReplacement(replacementsArray, method2, bcAfterSpan, index); }else if(smallTag){ index += stringTillBeginingOfYear2.length; addReplacement(replacementsArray, method2, year2StringBeforeSmallTag, index); if (method2 !== 'bc-ig') method2 = 'remove'; index += year2StringBeforeSmallTag.length; addReplacement(replacementsArray, method2, spaceBeforeSmallTag, index); index += spaceBeforeSmallTag.length + smallTag.length; addReplacement(replacementsArray, method2, smallBC, index); }else{ index += stringTillBeginingOfYear2.length; addReplacement(replacementsArray, method2, year2FullString, index); }       }    }    function processYearRangePattern(html, replacementsArray, pageData) { var result; var reg = giReg(yearRangePattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var partTillYearB2 = result[1] || ''; //or is it?; var partTillYearB1 = result[3] || ''; //or is it?; var partTillYearA2 = result[4] || ''; var yearA1String = result[5] || ''; var yearA2String = result[10] || ''; var yearB1String = result[26] || ''; var yearB2String = result[30] || ''; var lastSup = result[34] || ''; var spanOpening = result[38] || ''; var spanSpace = result[39] || ''; var spanClosing = result[40] || ''; var bc = result[41] || ''; var yearA1 = numberFromString(yearA1String); var yearA2 = numberFromString(yearA2String); var yearA2Substitute = ''; var method = methodForYear(yearA2, pageData); if (!yearA1String && !yearB1String && yearA2 > 10000 || yearA2 === 0) { var index = result.index + partTillYearA2.length; addReplacement(replacementsArray, 'bc-ig', yearA2String, index); return; }           if (yearA1String) { var { numberOfDigits, realYear } = checkIfSecondYearIsShortened(yearA1, yearA2); if (numberOfDigits !== 0) { yearA2Substitute = `${realYear}`; }               if (numberOfDigits === 1) { method = 'oneDigitYear'; } else if (numberOfDigits === 2) { method = 'twoDigitYear'; }           }            if (yearA1String) { addReplacement(replacementsArray, 'year', yearA1String, result.index); }           if (yearA2String) { var index = result.index + partTillYearA2.length; addReplacement(replacementsArray, method, yearA2String, index, true, 'normal', yearA2Substitute); }       }    }    function processYearRangeWithCircasPattern(html, replacementsArray,pageData) { var result; var reg = giReg(yearRangeWithCircasPattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var stringTillYear = result[1] || ''; var yearString = result[4] || ''; if (yearString) { var index = result.index + stringTillYear.length; addReplacement(replacementsArray, methodForYear(numberFromString(yearString),pageData), yearString, index); }       }    }    function processYearListPattern(html, replacementsArray) { var result; var reg = giReg(yearListPattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var yearString = result[6] || ''; if (yearString) { addReplacement(replacementsArray, 'year', yearString, result.index); }       }    }    function processYearPattern(html, replacementsArray,pageData) { var result; var reg = giReg(yearPattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var partTillYear2 = result[1] || ''; var year1String = result[2] || ''; var year2WithBC = result[6] || ''; var nakedYear2String = result[7] || ''; var extraSpan = result[9] || ''; var lastSup = result[10] || ''; var bcWithSpace = result[12] || ''; var year2TotalSpan = result[13] || ''; var year2Space = result[15] || ''; var spanOpening = result[14] || ''; var spanClosing = result[16] || ''; var nakedBC = result[17] || ''; var spaceBeforeSmallTag = result[13] || ''; var smallTag = result[23] || ''; var smallBC = result[24] || ''; var year2Substitute = ''; var method = 'year'; var year1 = numberFromString(year1String); var year2 = numberFromString(nakedYear2String); if(nakedYear2String === '000') continue; if (year1String) { var { numberOfDigits, realYear } = checkIfSecondYearIsShortened(year1, year2); if (numberOfDigits !== 0) { year2Substitute = `${realYear}`; }               if (numberOfDigits === 1) { method = 'oneDigitYear'; } else if (numberOfDigits === 2) { method = 'twoDigitYear'; }           }            if (year1String) { var yearMethod = 'year'; if (method === 'year') { yearMethod = methodForYear(year1,pageData); }               addReplacement(replacementsArray, yearMethod, year1String, result.index); }           if (method === 'year') { method = methodForYear(year2,pageData); }           if (!extraSpan && !spanOpening && !smallTag) { if (lastSup) { var index = result.index + partTillYear2.length; addReplacement(replacementsArray, method, nakedYear2String, index, true, 'normal', year2Substitute); index += nakedYear2String.length + lastSup.length; addReplacement(replacementsArray, 'remove', bcWithSpace, index); } else { var index = result.index + partTillYear2.length; addReplacement(replacementsArray, method, year2WithBC, index, true, 'normal', year2Substitute); }           } else if (extraSpan && spanOpening) { var index = result.index + partTillYear2.length; addReplacement(replacementsArray, method, nakedYear2String, index,true, 'normal', year2Substitute); index += nakedYear2String.length + lastSup.length + extraSpan.length + spanOpening.length; addReplacement(replacementsArray, 'remove', year2Space, index); index += year2Space.length + spanClosing.length; addReplacement(replacementsArray, 'remove', nakedBC, index); } else if (extraSpan && !spanOpening) { var index = result.index + partTillYear2.length; addReplacement(replacementsArray, method, nakedYear2String, index,true, 'normal', year2Substitute); index += nakedYear2String.length + extraSpan.length + lastSup.length; addReplacement(replacementsArray, 'remove', bcWithSpace, index); } else if (!extraSpan && spanOpening) { var index = result.index + partTillYear2.length; addReplacement(replacementsArray, method, nakedYear2String, index,true, 'normal', year2Substitute); index += nakedYear2String.length + lastSup.length + spanOpening.length; addReplacement(replacementsArray, 'remove', year2Space, index); index += year2Space.length + spanClosing.length; addReplacement(replacementsArray, 'remove', nakedBC, index); }else if (smallTag){ var index = result.index + partTillYear2.length; addReplacement(replacementsArray, method, nakedYear2String, index,true, 'normal', year2Substitute); index += nakedYear2String.length; addReplacement(replacementsArray, 'remove', spaceBeforeSmallTag, index); index += spaceBeforeSmallTag.length + smallTag.length; addReplacement(replacementsArray, 'remove', smallBC, index); }       }    }    function checkIfSecondYearIsShortened(year1, year2) { if (year2 < 10 && year1 > 9) { var lastDigit = year1 % 10; if ((lastDigit === 2 && year2 === 1) || (lastDigit === 1 && year2 === 0)) { var realYear = year1 - 1; return { numberOfDigits: 2, realYear }; }           if (lastDigit > year2) { var realYear = Math.floor(year1 / 10.0) * 10 + year2; return { numberOfDigits: 1, realYear }; }       }        if (year2 < 100 && year2 > 9 && year1 > 99) { var lastTwoDigits = year1 % 100; if (lastTwoDigits > year2) { var realYear = Math.floor(year1 / 100.0) * 100 + year2; return { numberOfDigits: 2, realYear }; }       }        return { numberOfDigits: 0, realYear:year2 }; }   function processYearMonthRangePattern(html, replacementsArray) { var result; var reg = giReg(yearMonthRangePattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var yearString = result[2] || ''; var middleWord = result[7] || ''; var monthName = result[12] || ''; var secondYearNakedString = result[17] || ''; if (monthName && middleWord.toLowerCase === 'or') continue; var year = numberFromString(yearString); var year2 = numberFromString(secondYearNakedString); if(year <= year2)continue; if(year > 10000 || year === 0) continue; addReplacement(replacementsArray, 'year', yearString, result.index); }   }    function processCenturyRangePattern(html, replacementsArray) { var result; var reg = giReg(centuryRangePattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var centuryString = result[1]; addReplacement(replacementsArray, 'century', centuryString, result.index); }   }    function processMillenniumRangePattern(html, replacementsArray) { var result; var reg = giReg(millenniumRangePattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var centuryString = result[1]; addReplacement(replacementsArray, 'millennium', centuryString, result.index); }   }    function processCenturyPattern(html, replacementsArray) { processCenturyOrMillenniumPattern(html,replacementsArray,'century'); }   function processMillenniumPattern(html, replacementsArray) { processCenturyOrMillenniumPattern(html,replacementsArray,'millennium'); }   function processCenturyOrMillenniumCategoryPattern(html, replacementsArray, method = ''){ if(!method){ if(isPageCenturyCategory){ method = 'century'; }else if(isPageMillenniumCategory){ method = 'millennium'; }else{ return; }       }        var pattern = `(title="Category:${nakedCenturyPattern}(-|${spacePattern})${method} BCE?[^"]*?">)(${nakedCenturyPattern}( BCE?)?)</a></li>`;        var reg = new RegExp(pattern, "gi");        while ((result = reg.exec(html))) {            var stringTillTarget = result[1] || ;            var targetString = result[6] || ;            if(method === 'millennium' && parseInt(targetString,10) > 10) continue;            var index = result.index + stringTillTarget.length;            addReplacement(replacementsArray, method, targetString, index);        }        if(isCurrentPageBCCategory){            var additionalPattern = `()(${nakedCenturyPattern}( BCE?)?)</li>`;            var additionalReg = new RegExp(additionalPattern, "gi");            var additionalResult = additionalReg.exec(html);            if(additionalResult){                var stringTillTarget = additionalResult[1] || ''; var targetString = additionalResult[2] || ''; if(method === 'millennium' && parseInt(targetString,10) > 10) return; var index = additionalResult.index + stringTillTarget.length; addReplacement(replacementsArray, method, targetString, index); }       }    }    function processDecadeCategoryPattern(html, replacementsArray){ if(!isPageDecadeCategory)return; var pattern = `(title="Category:${nakedDecadePattern} BCE?[^"]*?">)(${nakedDecadePattern}( BCE?)?)</a>`;       var reg = new RegExp(pattern, "gi");        while ((result = reg.exec(html))) {             var stringTillTarget = result[1] || ;             var targetString = result[2] || ;             var index = result.index + stringTillTarget.length;             addReplacement(replacementsArray, 'bc-sd', targetString, index);        }        if(isCurrentPageBCCategory){            var additionalPattern = `(<a class="mw-selflink selflink">)(${nakedDecadePattern})</a>`;            var additionalReg = new RegExp(additionalPattern, "gi");            var additionalResult = additionalReg.exec(html);            if(additionalResult){                var stringTillTarget = additionalResult[1] || ;                var targetString = additionalResult[2] || ;                var index = additionalResult.index + stringTillTarget.length; addReplacement(replacementsArray, 'bc-sd', targetString, index); }           var additionalPattern2 = `(<li>)(${nakedDecadePattern})</li>`; var additionalReg2 = new RegExp(additionalPattern2, "gi"); var additionalResult2 = additionalReg2.exec(html); if(additionalResult2){ var stringTillTarget = additionalResult2[1] || ''; var targetString = additionalResult2[2] || ''; var index = additionalResult2.index + stringTillTarget.length; addReplacement(replacementsArray, 'bc-sd', targetString, index); }       }        processCenturyOrMillenniumCategoryPattern(html, replacementsArray, 'century'); }   function processCenturyOrMillenniumPattern(html, replacementsArray, method) { var result; var pattern = method === 'millennium' ? millenniumPattern : centuriesPattern; var reg = giReg(pattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var stringTillBC = result[1] || ''; var centuryString = result[2] || ''; if(method === 'millennium' && parseInt(centuryString, 10) > 10) continue; var bcWithSpace = result[11] || ''; var bcSpan = result[12] || ''; var bcSpanOpening = result[13] || ''; var spaceInSpan = result[14] || ''; var bc = result[16] || ''; var smallTag = result[22] || ''; var smallBC = result[23] || ''; addReplacement(replacementsArray, method, centuryString, result.index); if(smallTag.length){ var index = result.index + stringTillBC.length; var space = bcSpan; addReplacement(replacementsArray, 'remove', space, index); index += space.length + smallTag.length; addReplacement(replacementsArray, 'remove', smallBC, index); }else if (!bcSpanOpening.length) { var index = result.index + stringTillBC.length; addReplacement(replacementsArray, 'remove', bcWithSpace, index); } else { var index = result.index + stringTillBC.length + bcSpanOpening.length; addReplacement(replacementsArray, 'remove', spaceInSpan, index); index = result.index + stringTillBC.length + bcSpan.length; addReplacement(replacementsArray, 'remove', bc, index); }       }    }    function processDecadeRangePattern(html, replacementsArray) { var result; var reg = giReg(decadeRangePattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var stringTillSecondDecade = result[1] || ''; var firstDecadeString = result[2] || ''; var fullSecondDecade = result[9] || ''; var nakedSecondDecade = result[10] || ''; var spanOpening = result[12] || ''; var spanSpace = result[13] || ''; var spanClosing = result[14] || ''; var bc = result[15] || ''; if (firstDecadeString) { addReplacement(replacementsArray, 'bc-sd', firstDecadeString, result.index); }           var index = result.index + stringTillSecondDecade.length; if (!spanOpening) { addReplacement(replacementsArray, 'bc-dp', fullSecondDecade, index); } else { addReplacement(replacementsArray, 'bc-dp', nakedSecondDecade, index); index += nakedSecondDecade.length + spanOpening.length; addReplacement(replacementsArray, 'remove', spanSpace, index); index += spanSpace.length + spanClosing.length; addReplacement(replacementsArray, 'remove', bc, index); }       }    }    function processDecadePattern(html, replacementsArray){ var result; var reg = giReg(decadePattern); while ((result = reg.exec(html))) { if(isPatternInsideTag(html,result.index))continue; var fullString = result[0] || ''; var spaceBeforeSmallTag = result[2] || ''; var decadeString = result[1] || ''; var spanOpening = result[3] || ''; var spanSpace = result[4] || ''; var spanClosing = result[5] || ''; var bc = result[6] || ''; var smallTag = result[12] || ''; var smallBC = result[13] || ''; if (!spanOpening && !smallTag) { addReplacement(replacementsArray, 'decade', fullString, result.index); } else if (smallTag) { addReplacement(replacementsArray, 'decade', decadeString, result.index); var index = result.index + decadeString.length; addReplacement(replacementsArray, 'remove', spaceBeforeSmallTag, index); index += spaceBeforeSmallTag.length + smallTag.length; addReplacement(replacementsArray, 'remove', smallBC, index); }else { addReplacement(replacementsArray, 'decade', decadeString, result.index); var index = result.index + decadeString.length + spanOpening.length; addReplacement(replacementsArray, 'remove', spanSpace, index); index += spanSpace.length + spanClosing.length; addReplacement(replacementsArray, 'remove', bc, index); }       }    }    //HELPERS=================; function saveTimestampedDataString(key, value) { var object = { value: value, timestamp: new Date.getTime }; localStorage.setItem([key], JSON.stringify(object)); }   function getDataStringFromStorage(key) { var dataObjectString = localStorage.getItem(key); if (!dataObjectString) return null; var obj = JSON.parse(dataObjectString); if (!obj) return null; var timestamp = obj.timestamp; if(!timestamp) return null; var diff = imagesLastUpdatedOnServerAt - timestamp; if (diff > 0) return null; return obj.value; }   function giReg(pattern) { return new RegExp(pattern, "gi"); }   function convertTypeFromMakup(typeInMarkup) { if (!typeInMarkup) { return 'normal'; } else if (typeInMarkup.includes('t')) { return 'bookTitle'; } else if (typeInMarkup.includes('q')) { return'quote'; }       return 'normal'; }   function numberFromString(string) { var newString = string.replace(/[^\d]/g, ''); return parseInt(newString, 10); }   function methodForYear(year, pageData) { if(year > 10000) return 'bc-ig'; if (!pageData.isPageAboutEarlyCenturyOrMillennium && year >= 3000 && year % 10 === 0) return'impreciseYear'; return 'year'; }   function getPageDataForSummary(html){ var reg = new RegExp(`href="/wiki/(\\d+(st|nd|rd|th))_(millennium|century)_BCE?`,"gi");       var result = reg.exec(html);        if(!result){         return {isPageAboutEarlyCenturyOrMillennium:false };        }        var number = parseInt(result[1],10);        var word = result[3];        var millennium = word === 'millennium' ? number : 1;        var century = word === 'century' ? number : 1;        var pageData = {isPageAboutEarlyCenturyOrMillennium:millennium >=3 || century >= 30 };        return pageData;    }    //MORE HELPERS==================;    function updateTranslation {        updateDates;        replaceImages(images, isScriptOff);    }    function createHTMLWithMarkers(replacementsArray, htmlWithIgParts, ignoredParts) {        var result = '';        var lastIndex = 0;        replacementsArray.forEach(function({ index, length, replacement }) {            result += htmlWithIgParts.substr(lastIndex, index - lastIndex); result += replacement; lastIndex = index + length; });       result += htmlWithIgParts.substr(lastIndex, htmlWithIgParts.length - lastIndex);        var chunks = result.split('<IgnoredPart>');        if (chunks.length === 1) return result;        var newHtml = '';        for (var i = 0; i < ignoredParts.length; i++) {            newHtml += chunks[i] + ignoredParts[i];        }        newHtml += chunks[chunks.length - 1];        return newHtml;    }    function htmlWithIgnoredParts(html) {        var pattern = new RegExp(`(<body.*?>| | .*?  |<link rel="mw-deduplicated-inline-style"[^>]*?/>|<h1.*?>|<(div|span|table) class="[^>]*?mw-collapsible[^>]*?>|<style[^>]*?>[^<]*? |<script[^>]*?>[^<]*? )`,'gm');        var ignoredParts = [];        var newHTML = html.replace(pattern, function(match){            ignoredParts.push(match);            return '<IgnoredPart>';        });        return { htmlWithIgParts: newHTML, ignoredParts };    } function findIndexOfSubstringOccurrence(parentString, substring, occurrenceNumber) { var startIndex = 0, index; var indices = []; while ((index = parentString.indexOf(substring, startIndex)) > -1) { indices.push(index); startIndex = index + substring.length; }       return indices[occurrenceNumber - 1]; }   function findAllIndicesOfSubstringOccurrences(parentString, substring) { var startIndex = 0, index; var indices = []; while ((index = parentString.indexOf(substring, startIndex)) > -1) { indices.push(index); startIndex = index + substring.length; }       return indices; }   //AUTOMATIC REPLACEMENTS============; function getLocalReplacements(htmlWithIgParts, replacementsArray, pageData) { // createCenturiesAndMillenniaReplacementsFromAltMarkup(htmlWithIgParts, replacementsArray); // createYearReplacementsWithInnerSpansFromAltMarkup(htmlWithIgParts, replacementsArray); // createReplacementsFromAltMarkup(htmlWithIgParts, replacementsArray); createCenturiesAndMillenniaReplacementsFromMarkup(htmlWithIgParts, replacementsArray); ignoreSecondYearInRangeWithInnerSpansIfNeeded(htmlWithIgParts, replacementsArray); ignoreSecondYearInRangeWithoutInnerSpansIfNeeded(htmlWithIgParts, replacementsArray); ignoreSecondYearInRangeWhenOnlyFirstIsInMarkup(htmlWithIgParts, replacementsArray); createYearReplacementsWithInnerSpansFromMarkup(htmlWithIgParts, replacementsArray); createReplacementsFromMarkup(htmlWithIgParts, replacementsArray); findH2Headlines(htmlWithIgParts, replacementsArray); createAutomaticReplacements(htmlWithIgParts, replacementsArray, pageData); }   function createAutomaticReplacements(html, replacementsArray, pageData) { processRoundYearRangePattern(html, replacementsArray, pageData); processYearRangePattern(html, replacementsArray, pageData); processSimpleYearRangePattern(html, replacementsArray, pageData); processLongYearListPattern(html, replacementsArray, pageData); processYearRangeWithCircasPattern(html, replacementsArray, pageData); processYearMonthRangePattern(html, replacementsArray); processYearPattern(html, replacementsArray, pageData); processCenturyOrMillenniumCategoryPattern(html,replacementsArray); processCenturyRangePattern(html, replacementsArray); processMillenniumRangePattern(html, replacementsArray); processDecadeCategoryPattern(html, replacementsArray); processDecadeRangePattern(html, replacementsArray); processDecadePattern(html, replacementsArray); processCenturyPattern(html, replacementsArray); processMillenniumPattern(html, replacementsArray); }   function addReplacement(replacementsArray, method,targetString, index, checkIfExists = true, type = 'normal', originalSubstitute = '') { if (checkIfExists) { var indexOfExistingReplacement = replacementsArray.findIndex(function(rep){return rep.index === index;}); if (indexOfExistingReplacement !== -1) return; }       var edit = { target: targetString, originalSubstitute, method, type };       var replacement = { isBroken: false, edit, index:index, length:targetString.length, replacement: createMarker(targetString, method, type, originalSubstitute) };       replacementsArray.push(replacement); }   //SUMMARIES============= var summaryTextsArray = []; var summaryTextNodesArray = []; var observer = new MutationObserver(function(mutations) {       mutations.forEach(function(mutation) { if(mutation.addedNodes.length){ mutation.addedNodes.forEach(function(node) {                   if(node.className && node.className.includes("mw-mmv-final-image")) {                        var img = node;                        replaceSrcInImage(img);                    }                    else if (node.className && node.className.includes("mwe-popups")) {                        editSummaryIfNeeded(node);                    }                    else if (node.className && node.className.includes("CategoryTreeSection")) {                        editSummaryIfNeeded(node);                    }                    else if (node.className && node.className.includes("mw-ui-icon")) {                        if(node.parentElement && node.parentElement.className && node.parentElement.className.includes("page-summary")){                            editSummaryIfNeeded(node.parentElement);                        }                    } else if(node.className && node.className.includes("ra-read-more")){ editSummaryIfNeeded(node); }               });            }        });    });    observer.observe(document, { childList: true, subtree: true });    function editSummaryIfNeeded(node){        if(isScriptOff)return;        var nonBreakableSpace = new RegExp(String.fromCharCode(160),'g');        var innerHTML = node.innerHTML.replace(/<img([^>]*?)>/,'<img$1/>').replace(/ /g,' ').replace(nonBreakableSpace,' ');        var substituteImageUrl = '';        var { htmlWithIgParts, ignoredParts } = htmlWithIgnoredParts(innerHTML);        var replacementsArray = [];        var pageData = getPageDataForSummary(innerHTML);        getLocalReplacements(htmlWithIgParts, replacementsArray, pageData);        replacementsArray = replacementsArray.filter(function(replacement){ return replacement.edit.method !== 'bc-ig';});        replacementsArray = replacementsArray.sort(function(a,b) { return a.index - b.index; }); editsArray = []; var htmlWithMarkers = createHTMLWithMarkers(replacementsArray, htmlWithIgParts, ignoredParts); if (!htmlWithMarkers) return; var parser = new DOMParser; var targetDOM = parser.parseFromString(htmlWithMarkers, "text/html"); summaryTextsArray = []; getSummaryTextsArray(targetDOM.documentElement); summaryTextNodesArray = []; getSummaryTextNodesArray(node); if(summaryTextsArray.length < summaryTextNodesArray.length){ summaryTextsArray = [''].concat(summaryTextsArray); }       doReplacementsInSummary; updateDatesInSummary(node); if(substituteImageUrl){ var imgs = document.getElementsByClassName('mwe-popups-thumbnail'); if(imgs){ var img = imgs[0]; img.src = substituteImageUrl; }       }    }    function getSummaryTextsArray(node) { if (node.nodeType === 3){ summaryTextsArray.push(node.data); }       node = node.firstChild; if (node) do { getSummaryTextsArray(node); node = node.nextSibling; } while (node); }   function getSummaryTextNodesArray(node) { if (node.nodeType === 3){ summaryTextNodesArray.push({ firstNode: node, lastNode: node }); }       node = node.firstChild; if (node) do { getSummaryTextNodesArray(node); node = node.nextSibling; } while (node); }   function doReplacementsInSummary { var newTextNodesArray = []; for (var i = 0; i < summaryTextsArray.length; i++) { var text = summaryTextsArray[i]; var nodes = summaryTextNodesArray[i]; var pair = replaceTextInNodeIfNeeded(nodes, text); newTextNodesArray.push(pair); }       summaryTextNodesArray = newTextNodesArray; }   function updateDatesInSummary(node){ var spans = Array.from(node.getElementsByClassName('oedatecase')); spans.forEach(function(span) {         updateDataInSpan(span);        }); }   //CONTENT==============; var originalTextsArray = []; var textsArray = []; var textNodesArray = []; var targets = []; var isPageCenturyCategory = false; var isPageMillenniumCategory = false; var isPageDecadeCategory = false;

var isCurrentPageBCCategory = false; var shouldUseDotNotation = false; var currentPageData = { isPageAboutEarlyCenturyOrMillennium:false, doesPageContainCenturiesTemplate:false };   var images = []; function getConfigFromLocalStorage{ isScriptOff = localStorage.getItem('OE-isScriptOff') == 1 ? true : false; shouldTranslateYearsPrecisely = localStorage.getItem('OE-shouldTranslateYearsPrecisely') == 1 ? true : false; shouldTranslateDatesInBookTitles = localStorage.getItem('OE-shouldTranslateDatesInBookTitles') == 1 ? true : false; shouldTranslateDatesInQuotes = localStorage.getItem('OE-shouldTranslateDatesInQuotes') == 1 ? true : false; }   var editForm = document.getElementById("editform"); if(editForm === null && mw.config.get('wgAction') !== 'history' && mw.config.get('wgCanonicalNamespace') !== 'Special'){ translateEverything(null); }   function getTextsArray(node, isOriginalHTML) { if (node.nodeType === 3) { if(isOriginalHTML){ originalTextsArray.push(node.data); }else{ textsArray.push(node.data); }       }        node = node.firstChild; if (node) do { getTextsArray(node, isOriginalHTML); node = node.nextSibling; } while (node); }   function getTextNodesArray(node) { if (node.nodeType === 3) { textNodesArray.push({ firstNode: node, lastNode: node }); }       node = node.firstChild; if (node) do { getTextNodesArray(node); node = node.nextSibling; } while (node); }   function imagesCSVLink { return `https://en${ isMobile ? '.m.' : '.'}wikipedia.org/w/api.php?action=parse&prop=wikitext&formatversion=2&format=json&page=User:KarenGrigMan/OldEraImages.csv`; }   function translateEverything(r) { findIfPageIsMillenniumOrCenturyCategory; findIfPageIsDecadeCategory; findIfPageIsAboutEarlyCenturyOrMillennium; findIfPageContainsCenturiesTemplate; var html = new XMLSerializer.serializeToString(document.body); html = html.replace('"=""','');       var htmlWithMarkers;        var { htmlWithIgParts, ignoredParts } = htmlWithIgnoredParts(html);        var replacementsArray = [];        getLocalReplacements(htmlWithIgParts, replacementsArray, currentPageData);        replacementsArray = replacementsArray.sort(function(a, b){return a.index - b.index;});        replacementsArray = replacementsArray.filter(function(replacement){return  replacement.edit.method !== 'bc-ig';});        replacementsArray = replacementsArray.sort(function(a, b) {return a.index - b.index;});        editsArray = replacementsArray.map(function(item){ return item.edit; });        htmlWithMarkers = createHTMLWithMarkers(replacementsArray, htmlWithIgParts, ignoredParts);        if (htmlWithMarkers) {            var parser = new DOMParser;            var originalBodyDOM = parser.parseFromString(html, "text/html");            var bodyDOM = parser.parseFromString(htmlWithMarkers, "text/html"); textsArray = []; getTextsArray(bodyDOM.documentElement, false); originalTextsArray = []; getTextsArray(originalBodyDOM.documentElement, true); textNodesArray = []; getTextNodesArray(document.body); var textInFirstNode = textNodesArray[1].firstNode.data; if(textNodesArray.length < textsArray.length){ var index = textsArray.findIndex(function(item) {                   return textInFirstNode === item;                }); if(index > 0){ textsArray.splice(0, index); }           }            doReplacements; updateDates; }       var dataString = getDataStringFromStorage('OE-imageUrls'); if(dataString){ parseImageData(dataString); replaceImages(images); }else{ fetch(imagesCSVLink).then(function(res) {return res.json;}).then(function(page) {               var wikitext = page.parse.wikitext;                if (!wikitext) return;                saveTimestampedDataString('OE-imageUrls',wikitext);                parseImageData(wikitext);                replaceImages(images);            }).catch(function(error) {console.log('fetch failed',error);}); }       allWorkFinishedForPage = true; updatePageTitle; }   function parseImageData(dataString){ var lines = dataString.split('\n'); var imgArray = []; lines.forEach(function(line) {           var [originalImageURL, substituteImageURL] = line.split(';');            var imageObj = {originalImageURL,substituteImageURL};            imgArray.push(imageObj);        }); images = imgArray; }   function findIfPageIsMillenniumOrCenturyCategory{ var html = document.body.innerHTML; var reg = new RegExp('<h1[^>]*>(.*?) '); var title = html.match(reg)[1]; if(title.includes('Category')){ var reg = new RegExp(`${nakedCenturyPattern}(-|${spacePattern})(millennium|century)( BCE?)?`); var matches = title.match(reg); if(matches){ isPageCenturyCategory = matches[5] === 'century'; isPageMillenniumCategory = matches[5] === 'millennium'; var bcLabel = matches[6]; isCurrentPageBCCategory = !!bcLabel; }        }    }    function findIfPageIsDecadeCategory{ var html = document.body.innerHTML; var reg = new RegExp('<h1[^>]*>(.*?) '); var title = html.match(reg)[1]; if(title.includes('Category')){ var reg = new RegExp(`${nakedDecadePattern}( BCE?)?`); var matches = title.match(reg); if(matches){ isPageDecadeCategory = true; var bcLabel = matches[1]; isCurrentPageBCCategory = !!bcLabel; }

}   }    function findIfPageIsAboutEarlyCenturyOrMillennium{ var html = document.body.innerHTML; var reg = new RegExp('<h1[^>]*>(.*?) '); var title = html.match(reg)[1];

var reg = new RegExp(`${nakedCenturyPattern} (millennium|century)( BCE?)`); var matches = title.match(reg); if(matches){ var word = matches[4]; var millennium = word === 'millennium' ? parseInt(matches[2],10) : 1; var century = word === 'century' ? parseInt(matches[2],10) : 1; currentPageData.isPageAboutEarlyCenturyOrMillennium = millennium >= 3 || century >= 30; }   }    function findIfPageContainsCenturiesTemplate{ }   function updatePageTitle { try{ var html = document.body.innerHTML; var reg = new RegExp('<h1.*>(.*?) '); var fullTitle = html.match(reg)[0]; var tag = new RegExp('<.*?>','g'); document.title = fullTitle.replace(tag,).replace('OE',) + ' - Wikipedia'; }catch(error){ //do nothing; }   }    function doReplacements { var newTextNodesArray = []; targets = []; var j = 0; for (var i = 0; i < textsArray.length; i++) { var text = textsArray[i]; var nodes; var cleanText = getTextWithoutMarkup(text); if(cleanText){ while(true){ if(j >= textNodesArray.length)break; nodes = textNodesArray[j]; if(!nodes){ j++; continue; }                   var textInNode = nodes.firstNode.data; if(cleanText !== textInNode) { j++; continue; }else{ var pair = replaceTextInNodeIfNeeded(nodes, text); newTextNodesArray.push(pair); break; }

}

}

j++; }       textNodesArray = newTextNodesArray; }   function updateDates{ var spans = Array.from(document.body.getElementsByClassName('oedatecase')); spans.forEach(function(span) {           updateDataInSpan(span);          }); }   function updateDataInSpan(span){ var originalText = span.getAttribute("o"); var originalSubstitute = span.getAttribute("s"); var method = span.getAttribute("m"); var type = span.getAttribute("t"); var translations = getReplacementStrings(originalText,originalSubstitute,method); if(!translations)return; var [translated, originalForToast, translatedForToast] = translations; if(isScriptOff        || (type === 'bookTitle' && !shouldTranslateDatesInBookTitles)        || (type === 'quote' && !shouldTranslateDatesInQuotes)){ span.innerHTML = originalText; span.title = translatedForToast ? translatedForToast : undefined; }else{ span.innerHTML = translated; span.title = originalForToast ? originalForToast : undefined; }   }    function replaceImages(images, reverse = false) { if (!images || images.length === 0) return; var allLazyPlaceholders = document.getElementsByClassName('lazy-image-placeholder'); var allImages = document.getElementsByTagName('img'); for(var placeholderSpan of allLazyPlaceholders){ replaceSrcInImagePlaceholder(placeholderSpan,reverse); }           for (var image of allImages) { replaceSrcInImage(image,reverse); }   }    function replaceSrcInImage(image,reverse){ var index = images.findIndex(function(imgObj) {           var originalImageNameFromServer = getImageNameFromUrl(imgObj.originalImageURL);            var currentImageNameFromSrc = getImageNameFromUrl(image.src);            return reverse ? image.src === imgObj.substituteImageURL :  originalImageNameFromServer === currentImageNameFromSrc;        }); if (index === -1) return; var imgObj = images[index]; image.crossOrigin = undefined; image.src = reverse ? imgObj.originalImageURL : imgObj.substituteImageURL; image.srcset = reverse ? imgObj.originalImageURL : imgObj.substituteImageURL; }   function replaceSrcInImagePlaceholder(placeholderSpan,reverse){ var index = images.findIndex(function(imgObj) {           var originalImageNameFromServer = getImageNameFromUrl(imgObj.originalImageURL);            var currentImageNameFromSrc = getImageNameFromUrl(placeholderSpan.dataset.src);            return reverse ? placeholderSpan.dataset.src === imgObj.substituteImageURL :  originalImageNameFromServer === currentImageNameFromSrc;        }); if (index === -1) return; var imgObj = images[index]; placeholderSpan.dataset.src = reverse ? imgObj.originalImageURL : imgObj.substituteImageURL; }   function getImageNameFromUrl(url){ var chunks = url.split('/'); var imageName = chunks[chunks.length - 1]; return imageName.replace(/\d+px-/,''); }

function getTextWithoutMarkup(text){ var pattern = new RegExp('(\\{\\{(.*?)\\|)(.*?)\\|(.*?)\\|(.*?)\\}\\}', 'g');

var replacements = []; while(result = pattern.exec(text)){ var fullString = result[0]; var dateString = result[3]; var index = result.index; var replacement = { index, length:fullString.length, replacement: dateString };           replacements.push(replacement); }       if(!replacements.length)return null;

var cleanText = ''; var lastIndex = 0; replacements.forEach(function({ index, length, replacement }) {           cleanText += text.substr(lastIndex, index - lastIndex);            cleanText += replacement;            lastIndex = index + length;        }); cleanText += text.substr(lastIndex, text.length - lastIndex); return cleanText; }   function replaceTextInNodeIfNeeded(oldNodes, sourceText) { var occurrences = []; var pattern = new RegExp('\\{\\{(.*?)\\|(.*?)\\|(.*?)\\|(.*?)\\}\\}', 'g'); while ((result = pattern.exec(sourceText))) { var obj = { index: result.index, length: result[0].length, method: result[1], originalText: result[2], type: result[3], originalSubstitute: result[4] }; occurrences.push(obj); }       if (!occurrences.length) return oldNodes; var { firstNode: firstOldNode, lastNode: lastOldNode } = oldNodes; var lastIndex = 0; var firstNode; for (var obj of occurrences) { var precedingTextNode = document.createTextNode(               sourceText.substr(lastIndex, obj.index - lastIndex)            ); firstOldNode.parentNode.insertBefore(precedingTextNode, firstOldNode); if (!firstNode) { firstNode = precedingTextNode; }           var replacementNode = getDateCaseNode(obj.originalText, obj.originalSubstitute, obj.method, obj.type); if (replacementNode) { firstOldNode.parentNode.insertBefore(replacementNode, firstOldNode); targets.push(obj.originalText); }           lastIndex = obj.index + obj.length; }       var lastNode = document.createTextNode(            sourceText.substr(lastIndex, sourceText.length - lastIndex)        ); firstOldNode.parentNode.insertBefore(lastNode, firstOldNode); while (lastNode.nextSibling && lastNode.nextSibling !== lastOldNode) { lastNode.parentNode.removeChild(lastNode.nextSibling); }       lastOldNode.parentNode.removeChild(lastOldNode); return { firstNode, lastNode }; }   function getDateCaseNode(originalText, originalSubstitute, method, type = 'normal'){ var span = document.createElement('span'); span.setAttribute("o",originalText); span.setAttribute("s",originalSubstitute); span.setAttribute("m",method); span.setAttribute("t",type); span.className = "rt-commentedText oedatecase"; var textNode = document.createTextNode(originalText); span.appendChild(textNode); return span; }   function getReplacementStrings(text, originalSubstitute, method) { var originalText = text; text = text.replace(',',''); var originalNumber = originalSubstitute ? numberFromString(originalSubstitute, 10) : numberFromString(text, 10); switch (method) { case 'bc-ybc':{ return [originalText + '\u00A0BC', "", ""]; }           case 'bc-yoe':{ return getYearReplacementString(originalNumber,'OE'); }           case 'bc-y_':{ return getYearReplacementString(originalNumber,'-'); }           case 'year': { return getYearReplacementString(originalNumber,'any'); }           case 'yearShort': { return getYearReplacementString(originalNumber,'any',true); }           case 'bc-ioe':{ return getImpreciseYearReplacementString(originalNumber,'OE'); }           case 'bc-i_':{ return getImpreciseYearReplacementString(originalNumber,'-'); }           case 'impreciseYear': { return getImpreciseYearReplacementString(originalNumber,'any'); }           case 'impreciseYearShort': { return getImpreciseYearReplacementString(originalNumber,'any',true); }           case 'oneDigitYear': { var year = originalNumber; if (isNaN(year)) return null; var translatedYear = 10001 - year; var translatedYearString = `${translatedYear % 10}`; return [translatedYearString, `${year} BC`,`${translatedYear}`]; }           case 'twoDigitYear': { var year = originalNumber; if (isNaN(year)) return null; var translatedYear = 10001 - year; var translatedYearString = `${translatedYear % 100}`; return [`${translatedYear % 100 < 10 ? '0' : ''}${translatedYearString}`, `${year} BC`, `${translatedYear}`]; }           case 'bc-i2': { var year = originalNumber; if (isNaN(year)) return null; var translatedYear = 10000 - year; var translatedYearString = `${translatedYear % 100}`; return [`${translatedYear % 100 < 10 ? '0' : ''}${translatedYearString}`, `${year} BC`, `${translatedYear}`]; }           case 'decade': case 'bc-dp': case 'bc-sd': { var decadeWord = method === 'bc-sd' ? '' : method === 'bc-dp' ? ' decades' :' decade'; var decade = originalNumber; if (isNaN(decade)) return null; var baseYear = 9990 - decade; var firstYear = baseYear + 2; var lastYear = (baseYear + 11); if (lastYear === 10001) lastYear = 10000; var lastYearShort = lastYear % 100; var translated = `${firstYear}/${lastYearShort < 10 ? lastYear : lastYearShort}${decadeWord}`; return [translated, `${numberFromString(text, 10)}s BC`, translated]; }           case 'century': { var century = originalNumber; if (isNaN(century)) { century = numbersFromWords[text.toLowerCase]; }               var translatedCentury = 101 - century; var translatedCenturyWithEnding = `${translatedCentury}${numberSuffix(translatedCentury)}`; var originalCenturyWithEnding = `${century}${numberSuffix(century)}`; return [translatedCenturyWithEnding, `${originalCenturyWithEnding} century BC`, `${translatedCenturyWithEnding} century`]; }           case '00s': { var x00s = originalNumber; if (isNaN(x00s)) return null; var translated = `${9900 - x00s}s`; return [translated, `${numberFromString(text, 10)}s BC`, translated]; }           case 'millennium': { var millennium = originalNumber; if (isNaN(millennium)) { millennium = numbersFromWords[text.toLowerCase]; }               var translatedMillennium = 11 - millennium; var translatedMillenniumWithEnding = `${translatedMillennium}${numberSuffix(translatedMillennium)}`; var originalMillenniumWithEnding = `${millennium}${numberSuffix(millennium)}`; return [translatedMillenniumWithEnding, `${originalMillenniumWithEnding} millennium BC`, `${translatedMillenniumWithEnding} millennium`]; }           case '000s': { var x000s = originalNumber; if (isNaN(x000s)) return null; var translated = `${9000 - x000s}s`; return [translated, `${numberFromString(text, 10)}s BC`, translated]; }           case 'remove': { return ["", "", ""]; }           case 'OE': { return ["Old Era", "", ""]; }           case 'ofOE': { return ["of the Old Era", "", ""]; }           case 'abbreviatedTimeline': { return ["OE", "", ""]; }           default: return [originalText, "", ""]; }   }    function getYearString(translatedYear, label, shortened = false){ label = resolveLabel(label, translatedYear); if(shouldUseDotNotation){ var yearWithinCentury = translatedYear % 100; var century = Math.floor(translatedYear / 100); if(yearWithinCentury === 0){ yearWithinCentury = 100; }else{ century += 1; }           return `${shortened ? '' : century + '^'}${yearWithinCentury}${label}`; }       return `${translatedYear}${label}`; }   function getYearReplacementString(year,label, shortened = false){ if (isNaN(year)) return null; var translatedYear = `${10001 - year}`; var translatedYearString = getYearString(translatedYear,label, shortened); return [translatedYearString, `${year} BC`, translatedYearString]; }   function getImpreciseYearReplacementString(year,label, shortened = false){ if (isNaN(year)) return null; var translatedYear = `${(shouldTranslateYearsPrecisely ? 10001 : 10000) - year}`; if(translatedYear == 0)translatedYear = 1; var translatedYearString = getYearString(translatedYear,label, shortened); return [translatedYearString, `${year} BC`, translatedYearString]; }   function resolveLabel(label, translatedYear){ if(label === 'any'){ return translatedYear <= 6000 ? '\u00A0OE' : ''; }else if(label === 'OE'){ return '\u00A0OE'; }else if(label === '-'){ return ''; }       return ''; }   function createMarker(text, method, type = 'normal', originalSubstitute = '') { return ``; }   function numberSuffix(number) { if (number > 10 && number < 20) return 'th'; var lastDigit = number % 10; if (lastDigit === 1) return 'st'; if (lastDigit === 2) return 'nd'; if (lastDigit === 3) return 'rd'; return 'th'; }   function escapeText(text) { return text.replace(/[.*+?^${}|[\]\\]/g, '\\$&'); }   });