Last active
August 26, 2024 06:23
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!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