您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds additional functionality to the UK General Register Office (GRO) BMD index search
当前为
// ==UserScript== // @name GRO Index Search Helper // @description Adds additional functionality to the UK General Register Office (GRO) BMD index search // @namespace cuffie81.scripts // @include https://www.gro.gov.uk/gro/content/certificates/indexes_search.asp // @version 1.5 // @grant none // @require https://code.jquery.com/jquery-2.2.4.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js // ==/UserScript== /* ======================INLINE_RESOURCE_BEGIN====================== ***********RESOURCE_START=Template-EW_Birth************* <style type="text/css"> div[results-view='EW_Birth'] td { padding: 5px 3px; font-size: 75%; color: #663333; vertical-align: top; } div[results-view='EW_Birth'] thead td { font-weight: bold; } div[results-view='EW_Birth'] tbody tr:nth-child(4n+1), div[results-view='EW_Birth'] tbody tr:nth-child(4n+2) { background-color: #F9E8A5; } div[results-view='EW_Birth'] tr.rec-actions a { padding: 0px 5px; font-size: 90%; color: #663333; text-decoration: none; } </style> <div results-view='EW_Birth' style='display: none; margin-bottom: 25px'> <table style='width: 100%; border-collapse: collapse'> <thead> <tr> <td class='main_text' style='padding: 5px 3px; font-weight: bold; width: 12%'>Date</td> <td>Name</td> <td>Mother</td> <td style='max-width: 30%'>District</td> <td>Vol</td> <td>Page</td> </tr> </thead> <tbody> {{#each items}} <tr class='rec'> <td>{{year}} Q{{quarter}}</td> <td><span class='forenames'>{{forenames}}</span> <span class='surname'>{{surname}}</span></td> <td>{{mother}}</td> <td>{{district}}</td> <td>{{volume}}</td> <td>{{page}}</td> </tr> <tr class='rec-actions' style='display: none'> <td colspan='6' style='text-align: right'> {{#actions}} <a href='{{url}}' {{#if title}}title='{{title}}'{{/if}}>{{text}}</a> {{/actions}} </td> </tr> {{/each}} </tbody> </table> </div> *************RESOURCE_END************* ***********RESOURCE_START=Template-EW_Death************* <style type="text/css"> div[results-view='EW_Death'] td { padding: 5px 3px; font-size: 75%; color: #663333; vertical-align: top; } div[results-view='EW_Death'] thead td { font-weight: bold; } div[results-view='EW_Death'] tbody tr:nth-child(4n+1), div[results-view='EW_Death'] tbody tr:nth-child(4n+2) { background-color: #F9E8A5; } div[results-view='EW_Death'] tr.rec-actions a { padding: 0px 5px; font-size: 90%; color: #663333; text-decoration: none; } </style> <div results-view='EW_Death' style='display: none; margin-bottom: 25px'> <table style='width: 100%; border-collapse: collapse'> <thead> <tr> <td style='width: 12%'>Date</td> <td>Name</td> <td>Age{{#if ageCautionThreshold}}*{{/if}}</td> <td>Birth</td> <td style='max-width: 30%'>District</td> <td>Vol</td> <td>Page</td> </tr> </thead> <tbody> {{#each items}} <tr class='rec'> <td>{{year}} Q{{quarter}}</td> <td><span class='forenames'>{{forenames}}</span> <span class='surname'>{{surname}}</span></td> <td>{{age}}{{#if ageCaution}}*{{/if}}</td> <td>{{birth}} <td>{{district}}</td> <td>{{volume}}</td> <td>{{page}}</td> </tr> <tr class='rec-actions' style='display: none'> <td colspan='7' style='text-align: right'> {{#actions}} <a href='{{url}}' {{#if title}}title='{{title}}'{{/if}}>{{text}}</a> {{/actions}} </td> </tr> {{/each}} </tbody> </table> {{#if ageCautionThreshold}} <p class='main_text'>* Ages are assumed to be years but <i>may</i> be months. Ages below {{ageCautionThreshold}} should be treated with caution.</p> {{/if}} </div> *************RESOURCE_END************* ======================INLINE_RESOURCE_END====================== */ this.$ = this.jQuery = jQuery.noConflict(true); $(function() { var initialiseSearchForm = function() { // Hide the reset button $("form[name='SearchIndexes'] input[type='submit'][value='Reset']").hide(); // Hide superfluous text $("table[summary*='contains the search form fields'] > tbody > tr:nth-of-type(2)").hide(); $("table[summary*='contains the search form fields'] > tbody > tr:nth-of-type(3) td.main_text[colspan='5']").parent().hide(); // Add gender and year navigation buttons, and style them var searchButton = $("form[name='SearchIndexes'] input[type='submit'][value='Search']") $("<input class='formButton' id='groish_BtnGenderToggle' type='button' value='Gender' />").insertBefore($(searchButton)); $("<input class='formButton' id='groish_BtnYearsPrev' type='button' value='< Years' />").insertBefore($(searchButton)); $("<input class='formButton' id='groish_BtnYearsNext' type='button' value='Years >' />").insertBefore($(searchButton)); var buttonContainer = $("form[name='SearchIndexes'] input[type='submit'][value='Search']").closest("td"); $(buttonContainer).css("padding-bottom", "10px"); $(buttonContainer).find("input[type='button']").css("margin-right", "20px"); $(buttonContainer).find("input[type='submit'], input[type='button']").css("min-width", "100px").css("font-size", "13px").css("padding", "4px 10px"); // Add button event handlers $("input#groish_BtnYearsPrev").click(function() { navigateYears(false); }); $("input#groish_BtnYearsNext").click(function() { navigateYears(true); }); $("input#groish_BtnGenderToggle").click(function() { toggleGender(); }); } var initialiseResultViews = function(recordType, resources) { //console.log("start: initialiseResultViews"); // Move default results table into a view container var defaultTable = $("form[name='SearchIndexes'] h3:contains('Results:')").closest("table").css("width", "100%").addClass("groish_ResultsTable"); $(defaultTable).before($("<div results-view='default' />")); var defaultView = $("div[results-view='default']"); $(defaultView).append($("table.groish_ResultsTable")); // Move header row to before default view $(defaultView).before($("<div class='groish_ResultsHeader' style='margin: 10px 0px; position: relative' />")); $(".groish_ResultsHeader").append($("table.groish_ResultsTable h3:contains('Results:')")); // Move pager row contents to after default view $(defaultView).after($("table.groish_ResultsTable > tbody > tr:last table:first")); $("div[results-view='default'] + table").css("width", "100%").addClass("groish_ResultsInfo"); // Add alternate view var results = getResults(recordType); //console.log(results); if (results != null && recordType && results.items != null && results.items.length > 0) { // Get template and add alternate view var template = resources["Template-" + recordType].toString(); var compiledTemplate = Handlebars.compile(template); var html = compiledTemplate(results); $(defaultView).after($(html)); // Add event handler to hide/show actions row // TODO: Make adding view event handlers more dynamic, so they can be specific to the view $("div[results-view][results-view!='default'] tbody tr.rec").click(function(index) { $(this).next("tr.rec-actions:not(:empty)").toggle(); }); // Add click handlers to results header, to toggle views $(".groish_ResultsHeader").append($("<div id='groish_ViewSwitcher' class='main_text' style='display:inline-block; position: absolute; color: #993333; font-weight: bold; right: 10px; bottom: 0px; cursor: pointer'>Switch view</div>")) .click(function() { switchResultsView(); }); //$("form[name='SearchIndexes'] h3:contains('Results:')").click(function() { switchResultsView(); }); // Show the last used view var viewName = sessionStorage.getItem("groish_view." + recordType); //console.log("initialising view: %s", viewName); if (viewName && $("div[results-view='" + viewName + "']:hidden").length == 1) { //console.log("setting active view: %s", viewName); $("div[results-view][results-view!='" + viewName + "']").hide(); $("div[results-view][results-view='" + viewName + "']").show(); } } //console.log("end: initialiseResultViews"); } var switchResultsView = function() { //console.log("switchResultsView"); var recordType = getRecordType(); var views = $("div[results-view]"); if (views.length > 1) { var curIndex = -1; $(views).each(function(index) { if ($(this).css("display") != "none") curIndex = index; }); //console.log("current view index: %s", curIndex); if (curIndex !== -1) { var newIndex = ((curIndex == (views.length-1)) ? 0 : curIndex+1); $(views).hide(); $("div[results-view]:eq(" + newIndex + ")").show(); // Get the name and save it var viewName = $("div[results-view]:eq(" + newIndex + ")").attr("results-view") sessionStorage.setItem("groish_view." + recordType, viewName); //save it //console.log("new view: %s", viewName); } } } var getResults = function(recordType) { //console.log("start: getResults"); var results = { "ageCautionThreshold": 24, "items": [] }; // Lookup record type - birth or death if (recordType !== null && (recordType === "EW_Birth" || recordType === "EW_Death")) { $("div[results-view='default'] > table > tbody > tr") .has("img[src='./graphics/order_certificate_button.gif']") .each(function(index) { // Get names and reference var names = $(this).find("td:eq(0)").text().replace(/\u00a0/g, " ").replace(/\s\s+/g, ' ').trim(); var ref = $(this).next().find("td:eq(0)").text(); // Clean up reference ref = ref.replace(/\u00a0/g, " "); ref = ref.replace(/\s\s+/g, ' '); ref = ref.replace(/GRO Reference: /g, ""); ref = ref.replace(/M Quarter in/g, "Q1"); ref = ref.replace(/J Quarter in/g, "Q2"); ref = ref.replace(/S Quarter in/g, "Q3"); ref = ref.replace(/D Quarter in/g, "Q4"); var age = 0; if (recordType === "EW_Death") { var ageArr = /^([0-9]{1,3})$/.exec($(this).find("td:eq(1)").text().replace(/\u00a0/g, " ").replace(/\s\s+/g, ' ').trim()); if (ageArr) age = parseInt(ageArr[1], 10); } var mother = null; if (recordType === "EW_Birth") mother = toTitleCase($(this).find("td:eq(1)").text().replace(/\u00a0/g, " ").replace(/\s\s+/g, ' ')).trim(); var actions = []; var orderCertUrl = $(this).find("a[href^='indexes_order.asp']:eq(0)").prop("href"); var orderPdfUrl = $(this).next().find("a[href^='indexes_order.asp']:eq(0)").prop("href"); if (orderCertUrl) actions.push( {"text": "Order Certificate", "url": orderCertUrl }); if (orderPdfUrl) actions.push( {"text": "Order Research Copy", "title": "PDF", "url": orderPdfUrl }); // Parse forenames, surname, year, quarter, district, vol, page var namesArr = /([a-z' -]+),([a-z' -]*)/gi.exec(names); var refArr = /([0-9]{4}) Q([1-4]) ([a-z\.\-,\(\)0-9\&' ]*)Volume ([a-z0-9]+) Page ([0-9]+)/gi.exec(ref); // NB: the district may not be set in some cases //console.log("index: %d, namesArr: %s, refArr: %s", index, namesArr, refArr); if (namesArr !== null && refArr !== null) { var forenames = toTitleCase(namesArr[2]).trim(); var surname = toTitleCase(namesArr[1]).trim(); var year = parseInt(refArr[1], 10); var quarter = parseInt(refArr[2], 10); var district = toTitleCase(refArr[3]).trim(); var volume = refArr[4].toLowerCase(); var page = refArr[5]; //console.log("forenames: %s, surname: %s, age: %d, year: %s, quarter: %s, district: %s, vol: %s, page: %s", forenames, surname, age, year, quarter, district, volume, page); var record = { "forenames": forenames, "surname": surname, "age": age, "ageCaution": (age != null && age > 0 && age <= results.ageCautionThreshold), "birth": (age != null ? year - age : null), "mother": mother, "year": year, "quarter": quarter, "district": district, "volume": volume, "page": page, "actions": actions }; results.items.push(record); //console.log(record); } else { //console.log("Failed to read record: %d", index); } }); } // Sort records if (results.items.length > 0) { results.items.sort(function(a, b) { if (a.year == b.year && a.quarter == b.quarter) return 0; else if ((a.year > b.year) || (a.year == b.year && a.quarter > b.quarter)) return 1; else return -1; }); } //console.log("end: getResults"); return results; } var toTitleCase = function(str) { return str.replace(/([^\W_]+[^\s-]*) */g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}); } var toggleGender = function() { var curGender = $("form[name='SearchIndexes'] select#Gender").val(); $("form[name='SearchIndexes'] select#Gender").val((curGender === "F" ? "M" : "F")); $("form[name='SearchIndexes'] input[type='submit'][value='Search']").click(); } var navigateYears = function(forward) { // Get min and max years var minYear = parseInt($("form[name='SearchIndexes'] select#Year option:eq(2)").val(), 10); var maxYear = parseInt($("form[name='SearchIndexes'] select#Year option:last").val(), 10); //console.log("Year range: %s - %s", minYear, maxYear); if (!isNaN(minYear) && !isNaN(maxYear)) { // Read current year and range var curYear = parseInt($("form[name='SearchIndexes'] select#Year").val(), 10); var curRange = parseInt($("form[name='SearchIndexes'] select#Range").val(), 10); if (!isNaN(curYear) && !isNaN(curRange)) { // Calculate the new year var step = (curRange * 2) + 1; var newYear = (forward ? curYear+step : curYear-step); newYear = Math.min(Math.max(newYear, minYear), maxYear); // Update the year and submit the search $("form[name='SearchIndexes'] select#Year").val(newYear); $("form[name='SearchIndexes'] input[type='submit'][value='Search']").click(); } //console.log("Current year: %d +-%d (%d-%d), New year: %d (%d-%d)", curYear, curRange, curYear-curRange, curYear+curRange, newYear, newYear-curRange, newYear+curRange); } } var getRecordType = function() { return $("form[name='SearchIndexes'] input[type='radio'][name='index']:checked").val(); } // https://gist.github.com/aidanhs/5534196 var getInlineResources = function() { var resource = {}, len, match, resourceBlocks, inlineResourcesMatch = (/^=+INLINE_RESOURCE_BEGIN=+$([\s\S]*?)^=+INLINE_RESOURCE_END=+$/m).exec(GM_info.scriptSource); resourceBlocks = (inlineResourcesMatch && inlineResourcesMatch[1].match(/^\**RESOURCE_START[\s\S]*?^\**RESOURCE_END\**$/mg)) || null; len = (resourceBlocks && resourceBlocks.length) || 0; for (var i = 0; i < len; i++) { match = (/^\**RESOURCE_START=(.*?)\**$\s*^([\s\S]*)^\**RESOURCE_END\**$/m).exec(resourceBlocks[i]); resource[match[1]] = match[2]; } return resource; } // Get the ball rolling... var resources = getInlineResources(); var recordType = getRecordType(); initialiseSearchForm(); initialiseResultViews(recordType, resources); });