PageSourceSearch

https://nlpfin.github.io/assets/js/publications.js

js nlpfin.github.io collected 2026-10-03 09:41:27 UTC 5,244 bytes, 142 lines download raw bytes

1// ============================================================
2// nlpfin.github.io — publications live search & filter
3// Renders the complete list in the original section order:
4// Latest, Book, Conference (grouped by year), Journal,
5// Preprint, Overview, Workshop.
6// Requires: assets/js/publications-data.js (const PUBLICATIONS)
7// ============================================================
8(function () {
9  'use strict';
10
11  document.addEventListener('DOMContentLoaded', function () {
12    if (typeof PUBLICATIONS === 'undefined') return;
13
14    var listEl = document.getElementById('pub-list');
15    var emptyEl = document.getElementById('pub-empty');
16    var searchEl = document.getElementById('pub-search-input');
17    var typeRow = document.getElementById('filter-types');
18
19    var state = { q: '', type: 'All' };
20
21    var SECTION_ORDER = ['Latest', 'Book', 'Conference', 'Journal', 'Preprint', 'Overview', 'Workshop'];
22    var SECTION_LABEL = {
23      Latest: 'Latest',
24      Book: 'Book',
25      Conference: 'Peer-Reviewed Conference Papers',
26      Journal: 'Journal Articles',
27      Preprint: 'Preprints',
28      Overview: 'Research Agenda / Tutorial / Shared Task Overview Papers',
29      Workshop: 'Workshop Papers'
30    };
31    var TYPE_ORDER = ['All'].concat(SECTION_ORDER);
32    var TYPE_LABEL = {
33      All: 'All', Latest: 'Latest', Conference: 'Conference', Journal: 'Journal',
34      Book: 'Book', Overview: 'Agenda & Overview', Workshop: 'Workshop', Preprint: 'Preprint'
35    };
36
37    TYPE_ORDER.forEach(function (t, idx) {
38      var b = document.createElement('button');
39      b.className = 'chip' + (idx === 0 ? ' on' : '');
40      b.type = 'button';
41      b.textContent = TYPE_LABEL[t];
42      b.addEventListener('click', function () {
43        state.type = t;
44        typeRow.querySelectorAll('.chip').forEach(function (c) { c.classList.remove('on'); });
45        b.classList.add('on');
46        render();
47      });
48      typeRow.appendChild(b);
49    });
50
51    var debounce;
52    if (searchEl) {
53      searchEl.addEventListener('input', function () {
54        clearTimeout(debounce);
55        debounce = setTimeout(function () {
56          state.q = searchEl.value.trim().toLowerCase();
57          render();
58        }, 120);
59      });
60    }
61
62    function matches(p) {
63      if (state.type !== 'All' && p.s !== state.type) return false;
64      if (state.q) {
65        var hay = p.x.toLowerCase();
66        var terms = state.q.split(/\s+/);
67        for (var i = 0; i < terms.length; i++) {
68          if (hay.indexOf(terms[i]) === -1) return false;
69        }
70      }
71      return true;
72    }
73
74    function esc(s) {
75      return String(s || '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
76    }
77
78    function fmt(p) {
79      var t = esc(p.x).replace(/Chung-Chi Chen/g, '<strong>Chung-Chi Chen</strong>');
80      // trim trailing bare link words (the links themselves are shown below)
81      t = t.replace(/\s+(pdf|dataset|website|site|code|Open Access|Proceedings|slides)(\s+(pdf|dataset|website|site|code|Open Access|Proceedings|slides))*\s*$/i, '');
82      return t;
83    }
84
85    function itemNode(p) {
86      var d = document.createElement('article');
87      d.className = 'pub-item';
88      var linksHtml = '';
89      Object.keys(p.l || {}).forEach(function (k) {
90        var url = p.l[k];
91        if (!url) return;
92        linksHtml += '<a href="' + esc(url) + '" target="_blank" rel="noopener">' + esc(k) + ' ↗</a>';
93      });
94      d.innerHTML =
95        '<p class="pub-title" style="font-weight: 500; font-family: var(--font-body); font-size: .98rem;">' + fmt(p) + '</p>' +
96        (linksHtml ? '<div class="pub-links">' + linksHtml + '</div>' : '');
97      return d;
98    }
99
100    function render() {
101      var filtered = PUBLICATIONS.filter(matches);
102      listEl.innerHTML = '';
103      if (emptyEl) emptyEl.style.display = filtered.length ? 'none' : 'block';
104
105      SECTION_ORDER.forEach(function (sec) {
106        var items = filtered.filter(function (p) { return p.s === sec; });
107        if (!items.length) return;
108
109        var h = document.createElement('h2');
110        h.className = 'pub-year-header';
111        h.textContent = SECTION_LABEL[sec];
112        listEl.appendChild(h);
113
114        if (sec === 'Conference') {
115          // group by year, descending, preserving order within each year
116          var years = [];
117          items.forEach(function (p) {
118            var y = p.y || 'Other';
119            if (years.indexOf(y) === -1) years.push(y);
120          });
121          years.sort(function (a, b) {
122            if (a === 'Other') return 1; if (b === 'Other') return -1;
123            return b.localeCompare(a);
124          });
125          years.forEach(function (y) {
126            var yh = document.createElement('h3');
127            yh.style.cssText = 'font-family: var(--font-head); font-size: 1.15rem; font-weight: 700; color: var(--primary-deep); margin: 1.3rem 0 .8rem;';
128            yh.textContent = y;
129            listEl.appendChild(yh);
130            items.forEach(function (p) {
131              if ((p.y || 'Other') === y) listEl.appendChild(itemNode(p));
132            });
133          });
134        } else {
135          items.forEach(function (p) { listEl.appendChild(itemNode(p)); });
136        }
137      });
138    }
139
140    render();
141  });
142})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.