Article Overview: Difference between revisions

From AlphaX Wiki
Jump to navigation Jump to search
Created page with "<div id="article-overview-wrapper"> <div style="margin-bottom:12px;"> <button id="download-csv-btn" style="background-color:#e07b00;color:#fff;padding:8px 18px;border:none;border-radius:4px;font-size:14px;font-weight:bold;cursor:pointer;">⬇ Download CSV</button> <span id="overview-status" style="margin-left:14px;font-size:13px;color:#aaa;"></span> </div> <table id="article-overview-table" style="width:100%;border-collapse:collapse;font-size:13px;"> <thead> <tr style=..."
 
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
<div id="article-overview-wrapper">
== Article Overview ==


<div style="margin-bottom:12px;">
This page displays all wiki articles organised by category and subcategory, including word count and focus area. The table and download button are generated automatically by JavaScript.
<button id="download-csv-btn" style="background-color:#e07b00;color:#fff;padding:8px 18px;border:none;border-radius:4px;font-size:14px;font-weight:bold;cursor:pointer;">⬇ Download CSV</button>
<span id="overview-status" style="margin-left:14px;font-size:13px;color:#aaa;"></span>
</div>


<table id="article-overview-table" style="width:100%;border-collapse:collapse;font-size:13px;">
<div id="article-overview-wrapper" style="margin-top:16px;"></div>
<thead>
<tr style="background-color:#2a2a2a;color:#f0a500;">
<th style="padding:8px 10px;border:1px solid #444;text-align:left;">Category</th>
<th style="padding:8px 10px;border:1px solid #444;text-align:left;">Subcategory</th>
<th style="padding:8px 10px;border:1px solid #444;text-align:left;">Title</th>
<th style="padding:8px 10px;border:1px solid #444;text-align:right;">Words</th>
<th style="padding:8px 10px;border:1px solid #444;text-align:left;">Focus</th>
</tr>
</thead>
<tbody id="article-overview-body">
<tr><td colspan="5" style="padding:10px;text-align:center;color:#aaa;">Loading data…</td></tr>
</tbody>
</table>
 
</div>
 
<script>
(function() {
  var apiBase = '/api.php';
  var allRows = [];
 
  function fetchAllCategories(continueParam, accumulated, callback) {
    var url = apiBase + '?action=query&list=allcategories&aclimit=500&format=json&origin=*';
    if (continueParam) url += '&accontinue=' + encodeURIComponent(continueParam);
    fetch(url)
      .then(function(r){ return r.json(); })
      .then(function(data) {
        var cats = data.query && data.query.allcategories ? data.query.allcategories : [];
        cats.forEach(function(c){ accumulated.push(c['*']); });
        if (data.continue && data.continue.accontinue) {
          fetchAllCategories(data.continue.accontinue, accumulated, callback);
        } else {
          callback(accumulated);
        }
      })
      .catch(function(){ callback(accumulated); });
  }
 
  function getCategoryMembers(catName, type, continueParam, accumulated, callback) {
    var cmtype = type || 'page|subcat';
    var url = apiBase + '?action=query&list=categorymembers&cmtitle=Category:' + encodeURIComponent(catName) + '&cmlimit=500&cmtype=' + cmtype + '&format=json&origin=*';
    if (continueParam) url += '&cmcontinue=' + encodeURIComponent(continueParam);
    fetch(url)
      .then(function(r){ return r.json(); })
      .then(function(data) {
        var members = data.query && data.query.categorymembers ? data.query.categorymembers : [];
        members.forEach(function(m){ accumulated.push(m); });
        if (data.continue && data.continue.cmcontinue) {
          getCategoryMembers(catName, type, data.continue.cmcontinue, accumulated, callback);
        } else {
          callback(accumulated);
        }
      })
      .catch(function(){ callback(accumulated); });
  }
 
  function getPageWordCount(pageTitle, callback) {
    var url = apiBase + '?action=query&titles=' + encodeURIComponent(pageTitle) + '&prop=revisions&rvprop=content&rvslots=main&format=json&origin=*';
    fetch(url)
      .then(function(r){ return r.json(); })
      .then(function(data) {
        var pages = data.query && data.query.pages ? data.query.pages : {};
        var pageData = Object.values(pages)[0];
        var content = pageData && pageData.revisions && pageData.revisions[0] && pageData.revisions[0].slots && pageData.revisions[0].slots.main && pageData.revisions[0].slots.main['*'] ? pageData.revisions[0].slots.main['*'] : '';
        var text = content.replace(/\[\[.*?\]\]/g,'$1').replace(/{{.*?}}/gs,'').replace(/<.*?>/g,'').replace(/[^a-zA-ZäöüÄÖÜß\s]/g,' ');
        var words = text.trim().split(/\s+/).filter(function(w){ return w.length > 0; }).length;
        callback(words);
      })
      .catch(function(){ callback(0); });
  }
 
  function getPageCategories(pageTitle, callback) {
    var url = apiBase + '?action=query&titles=' + encodeURIComponent(pageTitle) + '&prop=categories&cllimit=50&format=json&origin=*';
    fetch(url)
      .then(function(r){ return r.json(); })
      .then(function(data) {
        var pages = data.query && data.query.pages ? data.query.pages : {};
        var pageData = Object.values(pages)[0];
        var cats = pageData && pageData.categories ? pageData.categories.map(function(c){ return c.title.replace('Category:',''); }) : [];
        callback(cats);
      })
      .catch(function(){ callback([]); });
  }
 
  function buildTable() {
    var status = document.getElementById('overview-status');
    status.textContent = 'Fetching categories…';
 
    fetch(apiBase + '?action=query&list=allcategories&aclimit=500&format=json&origin=*')
      .then(function(r){ return r.json(); })
      .then(function(data) {
        var topCats = data.query && data.query.allcategories ? data.query.allcategories.map(function(c){ return c['*']; }) : [];
        var rows = [];
        var pending = 0;
        var totalCats = topCats.length;
        var processed = 0;
 
        if (totalCats === 0) {
          document.getElementById('article-overview-body').innerHTML = '<tr><td colspan="5" style="padding:10px;text-align:center;color:#aaa;">No categories found.</td></tr>';
          status.textContent = '';
          return;
        }
 
        function checkDone() {
          processed++;
          status.textContent = 'Loading… (' + processed + '/' + totalCats + ' categories)';
          if (processed === totalCats) {
            rows.sort(function(a,b){
              if (a.category < b.category) return -1;
              if (a.category > b.category) return 1;
              if (a.sub < b.sub) return -1;
              if (a.sub > b.sub) return 1;
              return a.title.localeCompare(b.title);
            });
            allRows = rows;
            renderTable(rows);
            status.textContent = rows.length + ' articles loaded.';
          }
        }
 
        topCats.forEach(function(catName) {
          getCategoryMembers(catName, 'page|subcat', null, [], function(members) {
            var pages = members.filter(function(m){ return m.ns === 0; });
            var subcats = members.filter(function(m){ return m.ns === 14; });
 
            if (pages.length === 0 && subcats.length === 0) {
              checkDone();
              return;
            }
 
            var subPending = 0;
 
            function trySubDone() {
              subPending--;
              if (subPending <= 0) checkDone();
            }
 
            // Direct pages in this category (no subcat)
            pages.forEach(function(page) {
              subPending++;
              var focus = catName;
              rows.push({ category: catName, sub: '—', title: page.title, words: '…', focus: focus, _title: page.title });
            });
 
            // Pages in subcategories
            subcats.forEach(function(subcat) {
              subPending++;
              var subName = subcat.title.replace('Category:','');
              getCategoryMembers(subName, 'page', null, [], function(subPages) {
                subPages.filter(function(m){ return m.ns === 0; }).forEach(function(page) {
                  subPending++;
                  rows.push({ category: catName, sub: subName, title: page.title, words: '…', focus: catName, _title: page.title });
                });
                trySubDone();
              });
            });
 
            if (subPending === 0) checkDone();
          });
        });
      })
      .catch(function() {
        document.getElementById('article-overview-body').innerHTML = '<tr><td colspan="5" style="padding:10px;text-align:center;color:#f00;">Error loading data.</td></tr>';
      });
  }
 
  function renderTable(rows) {
    var tbody = document.getElementById('article-overview-body');
    if (!rows || rows.length === 0) {
      tbody.innerHTML = '<tr><td colspan="5" style="padding:10px;text-align:center;color:#aaa;">No articles found.</td></tr>';
      return;
    }
    var html = '';
    rows.forEach(function(row, i) {
      var bg = i % 2 === 0 ? '#1a1a1a' : '#222';
      html += '<tr style="background:' + bg + ';">';
      html += '<td style="padding:6px 10px;border:1px solid #333;">' + escHtml(row.category) + '</td>';
      html += '<td style="padding:6px 10px;border:1px solid #333;">' + escHtml(row.sub) + '</td>';
      html += '<td style="padding:6px 10px;border:1px solid #333;"><a href="/wiki/' + encodeURIComponent(row.title.replace(/ /g,'_')) + '">' + escHtml(row.title) + '</a></td>';
      html += '<td style="padding:6px 10px;border:1px solid #333;text-align:right;">' + escHtml(String(row.words)) + '</td>';
      html += '<td style="padding:6px 10px;border:1px solid #333;">' + escHtml(row.focus) + '</td>';
      html += '</tr>';
    });
    tbody.innerHTML = html;
  }
 
  function escHtml(str) {
    return String(str).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
  }
 
  function downloadCSV() {
    var rows = allRows;
    if (!rows || rows.length === 0) { alert('No data to download yet. Please wait for the table to load.'); return; }
    var csv = 'Category,Subcategory,Title,Words,Focus\n';
    rows.forEach(function(row) {
      csv += [row.category, row.sub, row.title, row.words, row.focus].map(function(v){
        return '"' + String(v).replace(/"/g,'""') + '"';
      }).join(',') + '\n';
    });
    var blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
    var url = URL.createObjectURL(blob);
    var a = document.createElement('a');
    a.href = url;
    a.download = 'article-overview.csv';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  }
 
  document.addEventListener('DOMContentLoaded', function() {
    var btn = document.getElementById('download-csv-btn');
    if (btn) btn.addEventListener('click', downloadCSV);
    buildTable();
  });
 
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', function() {
      var btn = document.getElementById('download-csv-btn');
      if (btn) btn.addEventListener('click', downloadCSV);
      buildTable();
    });
  } else {
    var btn = document.getElementById('download-csv-btn');
    if (btn) btn.addEventListener('click', downloadCSV);
    buildTable();
  }
})();
</script>

Latest revision as of 07:19, 11 May 2026

Article Overview

This page displays all wiki articles organised by category and subcategory, including word count and focus area. The table and download button are generated automatically by JavaScript.