Skip to content

Instantly share code, notes, and snippets.

@sjgknight
Last active August 26, 2024 06:23
Show Gist options
  • Select an option

  • Save sjgknight/14f7cf3b5f6457ac5989666a0fa40749 to your computer and use it in GitHub Desktop.

Select an option

Save sjgknight/14f7cf3b5f6457ac5989666a0fa40749 to your computer and use it in GitHub Desktop.
Interface to reorder a table based on the sum of matches from applied rules. Here, dynamic table for matching synthesis methods based on user-defined rules. Generated with assistance from ChatGPT.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="description" content="Interface to reorder a table based on the sum of matches from applied rules. Here, dynamic table for matching synthesis methods based on user-defined rules. Generated with assistance from ChatGPT.">
<meta name="author" content="sjgknight with prompting of ChatGPT and customisation">
<meta name="keywords" content="HTML, JavaScript, Dynamic Table, Matching Logic">
<title>Method Match Example</title>
<style>
table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
th, td { padding: 10px; border: 1px solid #ddd; }
th { background-color: #f4f4f4; }
.highlight-negative { background-color: #fdd; } /* Light red for negative matches */
.highlight-positive { background-color: #dff; } /* Light blue for positive matches */
.highlight-neutral {
fill: #eee !important; /* Light grey */
}
</style>
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
</script>
<body>
</head>
<!-- Table 1: Rules Table (Inline JSON) -->
<!-- {
"twoplus": "people 2+",
"one": "people 1",
"none": "no people"
}, -->
<script type="application/json" id="rulesJson">
{
"Resourcing": {
"options": [
{ "value": "twoplus", "text": "Two or more", "rule": "2+" },
{ "value": "one", "text": "One", "rule": "single" }
],
"scoreForMatch": 1,
"scoreForNoMatch": -1,
"question": "How many researchers are available for the work?",
"columnHeader": "Resourcing"
},
"Complexity": {
"options": [
{ "value": "high", "text": "High", "rule": "High" },
{ "value": "moderate", "text": "Moderate", "rule": "Moderate" },
{ "value": "low", "text": "Low", "rule": "Low" }
],
"scoreForMatch": 1,
"scoreForNoMatch": -1,
"question": "Can you handle high complexity?",
"columnHeader": "Complexity"
},
"Time Commitment": {
"options": [
{ "value": "6plus", "text": "6+ months", "rule": "6+" },
{ "value": "3to6", "text": "3-6 months", "rule": "3-6" },
{ "value": "1to3", "text": "1-3 months", "rule": "1-3" }
],
"scoreForMatch": 1,
"scoreForNoMatch": -1,
"question": "What time commitment can you afford?",
"columnHeader": "Time Commitment"
}
}
</script>
<!-- Table 2: Display JSON Rules -->
<h2>Rules Table</h2>
<table id="jsonRulesTable">
<thead>
<tr>
<th>Property</th>
<th>Options</th>
<th>Score for Match</th>
<th>Score for No Match</th>
<th>Question</th>
<th>Column Header</th>
</tr>
</thead>
<tbody>
<!-- Rows will be populated by JavaScript -->
</tbody>
</table>
<!-- Table 3: Methods with Detailed Properties -->
<table id="methodTable">
<thead>
<tr>
<th>Method</th>
<th>Resourcing</th>
<th>Complexity</th>
<th>Time Commitment</th>
<th>Total Match</th>
</tr>
</thead>
<tbody>
<tr>
<td>Meta-analysis</td>
<td>Normally requires 2+ people for interrater reliability</td>
<td>Moderate complexity</td>
<td>High (6+ months)</td>
<td class="totalMatch">0</td>
</tr>
<tr>
<td>Systematic Review</td>
<td>Requires multiple researchers</td>
<td>High complexity</td>
<td>High (12+ months)</td>
<td class="totalMatch">0</td>
</tr>
<tr>
<td>Scoping Review</td>
<td>Can be conducted by a single researcher</td>
<td>Low complexity</td>
<td>Moderate (3-6 months)</td>
<td class="totalMatch">0</td>
</tr>
<tr>
<td>Rapid Review</td>
<td>Can be conducted by a small team</td>
<td>Moderate complexity</td>
<td>Low (1-3 months)</td>
<td class="totalMatch">0</td>
</tr>
<tr>
<td>Critical Review</td>
<td>Typically requires expert knowledge but fewer researchers</td>
<td>High complexity</td>
<td>Moderate (3-6 months)</td>
<td class="totalMatch">0</td>
</tr>
</tbody>
</table>
<!-- Step 2: HTML for User Input -->
<div id="questionsContainer">
<!-- Questions will be populated by JavaScript -->
</div>
<button id="updateButton">Update Diagram</button>
<code class="mermaid">
flowchart TD
subgraph types
direction LR
%% Overarching categories
ES["Approaches to Evidence Synthesis"]
ES --> Q["More configurative, interpretative, or/and hypothesis developing"]
ES --> Co["More confirmatory, consolidatory, or/and hypothesis testing"]
%% Detailed types of reviews under Confirmatory
Co --> A[fa:fa-ruler-combined Systematic Reviews]:::highlight-node
Co --> B[fa:fa-calculator Meta-Analysis]:::highlight-node
Co --> C[fa:fa-network-wired Scoping Review]:::highlight-node
Co --> E[fa:fa-hourglass-start Rapid Review]:::highlight-node
Co --> G[fa:fa-archive Umbrella Review]:::highlight-node
Co --> H[fa:fa-theater-masks Bibliometric Analysis]:::highlight-node
Co --> I[far:fa-compass State of the Art Review]:::highlight-node
Co --> J[fa:fa-route Evidence Maps]:::highlight-node
Co --> K[fa:fa-list Annotated Bibliographies]:::highlight-node
Co --> L[fa:fa-scale-unbalanced Critically Appraised Topic]:::highlight-node
%% Detailed types of reviews under Configurative
Q --> F[fa:fa-gears Realist Evidence Synthesis]:::highlight-node
Q --> M["far:fa-comments Qualitative Evidence Synthesis (QES)"]:::highlight-node
Q --> D[fa:fa-quote-left Narrative Review]:::highlight-node
Q --> N[far:fa-share-from-square Materials Review]:::highlight-node
M --> BF[fa:fa-puzzle-piece Including framework-synthesis methods such as best-fit and Rapid Best Fit]:::highlight-node
Q --> O[fa:fa-map]:::highlight-node
%% Duration and resourcing required
A --> A1["fa:fa-clock 18 months+ fa:fa-person fa:fa-repeat fa:fa-person 2+ personnel"]:::highlight-node
B --> B1["fa:fa-clock 18 months+ fa:fa-person fa:fa-repeat fa:fa-person 2+ personnel"]:::highlight-node
C --> C1["fa:fa-clock 2 months+" fa:fa-person 1+ personnel]:::highlight-node
D --> D1["fa:fa-clock 3 months+ fa:fa-person 1+ personnel"]:::highlight-node
E --> E1["fa:fa-clock 2 months+" fa:fa-person 1+ personnel]:::highlight-node
F --> F1["fa:fa-clock 12 months+"]:::highlight-node
G --> G1["fa:fa-clock 6 months+"]:::highlight-node
H --> H1["fa:fa-clock 6 months+"]:::highlight-node
I --> I1["fa:fa-clock 6 months+"]:::highlight-node
J --> J1["fa:fa-clock 6 months+" fa:fa-person 1+ personnel]:::highlight-node
K --> K1["fa:fa-clock 4 months+" fa:fa-person 1+ personnel]:::highlight-node
L --> L1["fa:fa-clock 4 months+" fa:fa-person 1+ personnel]:::highlight-node
M --> M1["fa:fa-clock 9 months+"]:::highlight-node
N --> N1["fa:fa-clock 3 months+ fa:fa-person 1+ personnel"]:::highlight-node
%% SALSA - Search, Appraisal, Synthesis, and Analysis
%% Revised SALSA - Search, Appraisal, Synthesis, and Analysis
A1 --> |"Components"| A2["Search: Exhaustive\\nAppraisal: Quality determines inclusion/exclusion\\nSynthesis: Narrative + Tabular\\nAnalysis: Known evidence; Recommendations for practice"]:::highlight-node
B1 --> |"Components"| B2["Search: Exhaustive\\nAppraisal: Quality determines inclusion/exclusion\\nSynthesis: Graphical & Tabular\\nAnalysis: Numerical effect size"]:::highlight-node
C1 --> |"Components"| C2["Search: Comprehensive within constraints\\nAppraisal: No formal quality assessment\\nSynthesis: Graphical & Tabular\\nAnalysis: Characterizes literature quantity & quality"]:::highlight-node
D1 --> |"Components"| D2["Search: May be comprehensive\\nAppraisal: No formal quality assessment\\nSynthesis: Narrative\\nAnalysis: Conceptual innovation, theory derivation"]:::highlight-node
E1 --> |"Components"| E2["Search: Time-constrained\\nAppraisal: Quality assessment\\nSynthesis: Narrative & Tabular\\nAnalysis: Literature quantity & direction of effect"]:::highlight-node
F1 --> |"Components"| F2["Search: Theory identification\\nAppraisal: Contextual analysis\\nSynthesis: Qualitative & Narrative\\nAnalysis: Mechanism explanation"]:::highlight-node
G1 --> |"Components"| G2["Search: Identifies component reviews\\nAppraisal: Reviews or studies\\nSynthesis: Graphical & Tabular\\nAnalysis: Recommendations for practice & research"]:::highlight-node
H1 --> |"Components"| H2["Search: Citation mapping\\nAppraisal: Network analysis\\nSynthesis: Graphical\\nAnalysis: Research trends and connections"]:::highlight-node
I1 --> |"Components"| I2["Search: Comprehensive of current literature\\nAppraisal: No formal quality assessment\\nSynthesis: Narrative + Tabular\\nAnalysis: State of knowledge & future priorities"]:::highlight-node
J1 --> |"Components"| J2["Search: Broad scoping\\nAppraisal: Evidence mapping\\nSynthesis: Graphical & Tabular\\nAnalysis: Gaps identification"]:::highlight-node
K1 --> |"Components"| K2["Search: Source selection\\nAppraisal: Annotations\\nSynthesis: Summarization\\nAnalysis: Key contributions identification"]:::highlight-node
L1 --> |"Components"| L2["Search: Critical appraisal\\nAppraisal: Relevance assessment\\nSynthesis: Summary of findings\\nAnalysis: Relevance to context"]:::highlight-node
%% Types of output and their purpose for stakeholders
A2 --> A3[fa:fa-users-involved Systematic Reviews typically result in comprehensive guidelines, often in consultation with experts and stakeholders at the synthesis stage. Comprehensive approach, with low risk of bias.]:::highlight-node
B2 --> B3[fa:fa-users-together Meta-Analysis outputs often involve aggregated data interpretations, with stakeholders providing feedback on applicability. Comprehensive approach, with low risk of bias.]:::highlight-node
C2 --> C3[fa:fa-users-discuss Scoping Reviews map evidence with some stakeholder input at initial stages for relevance, not comprehensive, but transparent approach, with some risk of bias.]:::highlight-node
D2 --> D3[fa:fa-users-share Narrative Reviews provide an overview of trends, generally with minimal stakeholder engagement. Non-comprehnsive approach, interpretative.]:::highlight-node
E2 --> E3[fa:fa-users-quick Rapid Reviews focus on quickly informing policy or practice, involving stakeholders to prioritize evidence. Non-comprehensive, but transparent approach, bias limited.]:::highlight-node
F2 --> F3[fa:fa-users-gear Realist Evidence Synthesis engages stakeholders to identify the problem space and theory of change and adapt the review focus iteratively.]:::highlight-node
G2 --> G3[fa:fa-users-consolidate Umbrella Reviews synthesize findings from multiple reviews, often consulting stakeholders to interpret results.]:::highlight-node
H2 --> H3[fa:fa-users-networks Bibliometric Analysis maps research networks and trends, usually with expert consultation.]:::highlight-node
I2 --> I3[fa:fa-users-overview State of the Art Reviews summarize leading ideas with stakeholder engagement mainly in initial scoping.]:::highlight-node
J2 --> J3[fa:fa-users-map Evidence Maps provide visual summaries of evidence, sometimes with stakeholder feedback on gaps.]:::highlight-node
K2 --> K3[fa:fa-users-annotate Annotated Bibliographies collect key sources, occasionally with stakeholder suggestions for inclusion.]:::highlight-node
L2 --> L3[fa:fa-users-appraise Critically Appraised Topics involve stakeholders in the appraisal process to ensure relevance and impact.]:::highlight-node
M2 --> M3[fa:fa-users-qualitative Qualitative Evidence Synthesis gathers qualitative insights with stakeholder collaboration to validate findings.]:::highlight-node
N2 --> N3[fa:fa-users-materials Materials Review organizes and classifies materials with input from stakeholders on categorization.]:::highlight-node
%% Example questions each review type answers
A3 --> |"Questions"| A4["fa:fa-question-circle What is the effect size of interventions?\\nHow effective is treatment X for condition Y?"]:::highlight-node
B3 --> |"Questions"| B4["fa:fa-question-circle How effective is treatment X for condition Y?\\nWhat is the combined effect size?"]:::highlight-node
C3 --> |"Questions"| C4["fa:fa-question-circle What is the extent of research on topic Z?\\nWhat types of interventions exist for condition A?"]:::highlight-node
D3 --> |"Questions"| D4["fa:fa-question-circle What are the general trends in research on X?\\nHow have views on Y evolved over time?"]:::highlight-node
E3 --> |"Questions"| E4["fa:fa-question-circle What is the current evidence on intervention X?\\nWhat are the immediate implications for policy Y?"]:::highlight-node
F3 --> |"Questions"| F4["fa:fa-question-circle How do interventions work in different contexts?\\nWhat mechanisms explain the success of program X?"]:::highlight-node
G3 --> |"Questions"| G4["fa:fa-question-circle What do existing reviews say about intervention X?\\nWhat are the overarching findings across reviews on topic Y?"]:::highlight-node
H3 --> |"Questions"| H4["fa:fa-question-circle Who is working on what topics?\\nHow are different studies connected?"]:::highlight-node
I3 --> |"Questions"| I4["fa:fa-question-circle What is the current state of research on X?\\nWhat are the leading thoughts and gaps?"]:::highlight-node
J3 --> |"Questions"| J4["fa:fa-question-circle What is the distribution of evidence on topic Y?\\nWhere are the gaps in current research?"]:::highlight-node
K3 --> |"Questions"| K4["fa:fa-question-circle What are the key sources on topic X?\\nWhat do they contribute to the understanding of Y?"]:::highlight-node
L3 --> |"Questions"| L4["fa:fa-question-circle What are the critical findings on topic X?\\nHow relevant are these findings for context Y?"]:::highlight-node
M3 --> |"Questions"| M4["fa:fa-question-circle What are the qualitative insights on X?\\nHow do themes emerge across different studies?"]:::highlight-node
N3 --> |"Questions"| N4["fa:fa-question-circle What materials exist on topic X?\\nHow can these materials be classified and organized?"]:::highlight-node
%% Styles and possible fontawesome icons to use
classDef reviewStyle fill:#f9f,stroke:#333,stroke-width:2px;
classDef characteristicsStyle fill:#ccf,stroke:#333,stroke-width:1px;
class highlight-node fill:#ccf,stroke:#333,stroke-width:1px;
class A,B,C,D,E,F,G,H,I,J,K,L,M,N,BF reviewStyle;
class A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1 characteristicsStyle;
class A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2,N2 characteristicsStyle;
class A3,B3,C3,D3,E3,F3,G3,H3,I3,J3,K3,L3,M3,N3 characteristicsStyle;
end
types ~~~ meta
subgraph meta
note["fa:fa-copyright Issues may arise with substantive parts"]
grey["far:fa-newspaper consider if grey literature included"]
other["fab:fa-creative-commons fab:fa-creative-commons-by"]
end
</code>
<!-- Step 3: JavaScript to Handle Matching Logic -->
<script>
// Load and parse the rules JSON
const rulesJson = document.getElementById('rulesJson').textContent;
const rules = JSON.parse(rulesJson);
function createQuestionInputs() {
const container = document.getElementById('questionsContainer');
container.innerHTML = ''; // Clear existing inputs
for (const [property, ruleData] of Object.entries(rules)) {
const label = document.createElement('label');
label.innerHTML = `${ruleData.question}<br>`;
const select = document.createElement('select');
select.id = `userInput_${ruleData.columnHeader.replace(/ /g, '')}`;
// Create and append the default 'unselected' option
const defaultOption = document.createElement('option');
defaultOption.value = ''; // Empty value for unselected
defaultOption.text = 'Please select'; // Display text for the default option
select.appendChild(defaultOption);
ruleData.options.forEach(option => {
const opt = document.createElement('option');
opt.value = option.value;
opt.text = option.text;
select.appendChild(opt);
});
select.addEventListener('change', updateMatches);
container.appendChild(label);
container.appendChild(select);
container.appendChild(document.createElement('br'));
}
}
function calculateMethodMatch(userInput, ruleData, cellText) {
if (!ruleData) return 0; // No rule defined for this property
// Handle 'NULL' case
if (userInput === ''|| userInput === 'NULL') {
return 0; // 'NULL' selected, return 0 for this match
}
// Find the rule that matches the user's selection
const matchingOption = ruleData.options.find(opt => opt.value === userInput);
const match = matchingOption ? cellText.toLowerCase().includes(matchingOption.rule.toLowerCase()) : false;
return match ? ruleData.scoreForMatch : ruleData.scoreForNoMatch;
}
function updateMatches() {
// Get user inputs dynamically based on rules
const methodRows = document.querySelectorAll('#methodTable tbody tr');
methodRows.forEach(row => {
let totalMatch = 0;
for (const [property, ruleData] of Object.entries(rules)) {
const userInput = document.getElementById(`userInput_${ruleData.columnHeader.replace(/ /g, '')}`).value;
const cellText = row.cells[Object.keys(rules).indexOf(property) + 1].innerText;
totalMatch += calculateMethodMatch(userInput, ruleData, cellText);
}
const totalMatchCell = row.querySelector('.totalMatch');
totalMatchCell.innerText = totalMatch;
// Apply CSS class based on match value
row.classList.remove('highlight-negative', 'highlight-positive','highlight-neutral');
if (totalMatch < 0) {
row.classList.add('highlight-negative');
} else if (totalMatch > 0) {
row.classList.add('highlight-positive');
row.classList.add('highlight-neutral');
}
});
// Sort rows based on total match
const table = document.getElementById('methodTable');
const rows = Array.from(table.querySelectorAll('tbody tr'));
rows.sort((a, b) => {
return parseInt(b.querySelector('.totalMatch').innerText) - parseInt(a.querySelector('.totalMatch').innerText);
});
// Re-attach sorted rows
rows.forEach(row => table.querySelector('tbody').appendChild(row));
}
function displayRules() {
// Display rules table
const jsonRulesTable = document.getElementById('jsonRulesTable').getElementsByTagName('tbody')[0];
jsonRulesTable.innerHTML = ''; // Clear existing rows
for (const [property, ruleData] of Object.entries(rules)) {
const row = document.createElement('tr');
row.innerHTML = `
<td>${property}</td>
<td>${ruleData.options.map(opt => `${opt.text} (${opt.rule})`).join('<br>')}</td>
<td>${ruleData.scoreForMatch}</td>
<td>${ruleData.scoreForNoMatch}</td>
<td>${ruleData.question}</td>
<td>${ruleData.columnHeader}</td>
`;
jsonRulesTable.appendChild(row);
}
}
// Initialize and update tables
createQuestionInputs();
displayRules();
updateMatches();
</script>
<script>
// Function to update diagram
function updateDiagram() {
// Re-render Mermaid diagram
mermaid.init(undefined, document.querySelectorAll('div.mermaid'));
}
// Apply CSS classes based on user inputs
function applyClasses() {
const userInput = {
'Systematic Reviews': 'positive',
'Meta-Analysis': 'negative',
'Narrative Review': 'neutral'
};
// Apply classes based on user input
for (const [nodeName, value] of Object.entries(userInput)) {
const nodeClass = value === 'positive' ? 'highlight-positive' :
value === 'negative' ? 'highlight-negative' :
'highlight-neutral';
document.querySelectorAll(`.mermaid .${nodeName}`).forEach(node => {
node.classList.add(nodeClass);
});
}
}
// Example function to handle changes (e.g., from a form or other inputs)
function handleUserInput() {
applyClasses();
updateDiagram();
}
// Set up event listener for changes
document.addEventListener("DOMContentLoaded", function () {
handleUserInput();
// Example: Trigger update when a button is clicked
document.getElementById('updateButton').addEventListener('click', handleUserInput);
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment