Widget:BcaSearch: Difference between revisions

From Bodhicitta
(Start panel: two columns)
(Mobile: finger-sized chapter/verse number chips)
 
(5 intermediate revisions by the same user not shown)
Line 7: Line 7:
.bcas__go:hover{background:#fff}
.bcas__go:hover{background:#fff}
.bcas__hint{font-size:.85rem;color:#666;margin:.2rem 0 1rem}
.bcas__hint{font-size:.85rem;color:#666;margin:.2rem 0 1rem}
.bcas__hint a{cursor:pointer}
.bcas__tabs{display:flex;flex-wrap:wrap;gap:.4rem;border-bottom:1px solid rgba(17,54,81,.15);margin:1rem 0 .8rem}
.bcas__tabs{display:flex;flex-wrap:wrap;gap:.4rem;border-bottom:1px solid rgba(17,54,81,.15);margin:1rem 0 .8rem}
.bcas__tab{padding:.45rem .9rem;border:1px solid transparent;border-bottom:0;border-radius:6px 6px 0 0;cursor:pointer;color:#41607D;font-size:.95rem;margin-bottom:-1px;background:none}
.bcas__tab{padding:.45rem .9rem;border:1px solid transparent;border-bottom:0;border-radius:6px 6px 0 0;cursor:pointer;color:#41607D;font-size:.95rem;margin-bottom:-1px;background:none}
Line 25: Line 24:
.bcas__pills{margin:.2rem 0 .8rem}
.bcas__pills{margin:.2rem 0 .8rem}
.bcas__empty{padding:1.2rem;color:#666}
.bcas__empty{padding:1.2rem;color:#666}
.bcas__tips{font-size:.88rem;color:#555;margin:-.4rem 0 .8rem}
.bcas__tips summary{cursor:pointer;color:#41607D;display:inline-block}
.bcas__tips ul{margin:.4rem 0 0 1.2rem}
.bcas__tips li{margin:.15rem 0}
.bcas__tips a,.bcas__hint a{cursor:pointer;color:#0645AD;text-decoration:none;border-bottom:1px dotted rgba(6,69,173,.4)}
.bcas__tips a:hover,.bcas__hint a:hover{color:#001028}
/* Start panel (in the page below the widget) */
/* Start panel (in the page below the widget) */
.bcas-start{max-width:1100px;margin:1.5rem auto 3rem}
.bcas-start{max-width:1100px;margin:1.5rem auto 3rem}
Line 38: Line 43:
.bcas-start__chips a:hover{border-color:#bf9659;background:rgba(191,150,89,.08)}
.bcas-start__chips a:hover{border-color:#bf9659;background:rgba(191,150,89,.08)}
.bcas-start__chips a span{color:#888;font-size:.8rem}
.bcas-start__chips a span{color:#888;font-size:.8rem}
.bcas-start__chips--small{margin-top:.6rem}
.bcas-start__chips--small{margin-top:.5rem}
.bcas-start__sub{margin-bottom:.8rem}
.bcas-start__chips--small a{padding:.15rem .6rem;font-size:.82rem}
.bcas-start__chips--small a{padding:.15rem .6rem;font-size:.82rem}
/* Phones: finger-sized number chips (they were ~29x26px). */
@media (max-width:767.98px){.bcas-start__chips--small{gap:.5rem}.bcas-start__chips--small a{min-width:2.5rem;min-height:2.5rem;justify-content:center;font-size:.95rem}}
.bcas-start__more{margin-top:.7rem;font-size:.85rem;color:#666}
.bcas-start__more{margin-top:.7rem;font-size:.85rem;color:#666}
.bcas-start__more--stack a{display:block;padding:.15rem 0}
.bcas-start__sub{margin:.1rem 0 .6rem .6rem;padding-left:.8rem;border-left:2px solid rgba(191,150,89,.35)}
.bcas-start__label{font-size:.78rem;color:#888;margin-right:.2rem;align-self:center}
.bcas-start__note{font-size:.82rem;color:#666;margin-top:.45rem}
/* Whole row is the link: hover tint and a gold edge, as on PLL's lists */
/* Whole row is the link: hover tint and a gold edge, as on PLL's lists */
.bcas__list .topic-biblio-row,.bcas__hit{cursor:pointer;position:relative;transition:background-color .15s ease,box-shadow .15s ease}
.bcas__list .topic-biblio-row,.bcas__hit{cursor:pointer;position:relative;transition:background-color .15s ease,box-shadow .15s ease}
Line 56: Line 68:
</form>
</form>
<div class="bcas__hint" id="bcas-hint">Try <a data-q="tonglen">tonglen</a>, <a data-q="Santideva">Santideva</a> (accents optional), <a data-q="9.1">9.1</a> (a verse), <a data-q="&quot;bodhicitta of aspiration&quot;">"bodhicitta of aspiration"</a> (exact phrase) or <a data-q="བྱང་ཆུབ་སེམས">བྱང་ཆུབ་སེམས</a>.</div>
<div class="bcas__hint" id="bcas-hint">Try <a data-q="tonglen">tonglen</a>, <a data-q="Santideva">Santideva</a> (accents optional), <a data-q="9.1">9.1</a> (a verse), <a data-q="&quot;bodhicitta of aspiration&quot;">"bodhicitta of aspiration"</a> (exact phrase) or <a data-q="བྱང་ཆུབ་སེམས">བྱང་ཆུབ་སེམས</a>.</div>
<details class="bcas__tips"><summary>Search tips</summary><ul>
<li><b>"exact phrase"</b> in quotes finds the words together: <a data-q="&quot;wish-fulfilling jewel&quot;">"wish-fulfilling jewel"</a></li>
<li><b>-word</b> leaves a word out: <a data-q="compassion -dalai">compassion -dalai</a></li>
<li><b>OR</b> finds either word: <a data-q="tonglen OR lojong">tonglen OR lojong</a></li>
<li><b>word*</b> matches any ending: <a data-q="meditat*">meditat*</a></li>
<li><b>intitle:</b> searches titles only: <a data-q="intitle:bodhisattva">intitle:bodhisattva</a></li>
<li><b>incategory:</b> searches by tag. Topics, decades, people and publishers are all tags: <a data-q="incategory:&quot;Topic: Tonglen&quot;">incategory:"Topic: Tonglen"</a>, <a data-q="incategory:&quot;Decade: 1990s&quot;">incategory:"Decade: 1990s"</a>, <a data-q="incategory:&quot;Padmakara Translation Group&quot;">incategory:"Padmakara Translation Group"</a>. Combine with words: <a data-q="patience incategory:&quot;Topic: Six Perfections&quot;">patience incategory:"Topic: Six Perfections"</a></li>
<li>Accents are optional (<a data-q="santideva">santideva</a> finds Śāntideva); Tibetan script and Wylie work too.</li>
<li>A verse number such as <a data-q="8.120">8.120</a> offers that Bodhicaryāvatāra verse page.</li>
</ul></details>
<div id="bcas-shortcut"></div>
<div id="bcas-shortcut"></div>
<div class="bcas__tabs" id="bcas-tabs" role="tablist" hidden></div>
<div class="bcas__tabs" id="bcas-tabs" role="tablist" hidden></div>
Line 82: Line 104:


var state = { q: '', tab: 'library', cls: '', offset: 0 };
var state = { q: '', tab: 'library', cls: '', offset: 0 };
// First page of results per class, fetched with the class counts, so a class
// button shows its rows without waiting for another search.
var firstPages = {};
var counts = {};
var counts = {};
var token = 0;
var token = 0;
Line 112: Line 137:
return (d && d.query && d.query.results) || {};
return (d && d.query && d.query.results) || {};
});
});
}
function covers(files) {
if (!files.length) return $.Deferred().resolve({}).promise();
return $.getJSON(API, { action: 'query', format: 'json', formatversion: 2, titles: files.join('|'), prop: 'imageinfo', iiprop: 'url', iiurlwidth: 120 })
.then(function (d) {
var out = {};
((d.query && d.query.pages) || []).forEach(function (p) { if (p.imageinfo && p.imageinfo[0]) out[p.title] = p.imageinfo[0].thumburl || p.imageinfo[0].url; });
((d.query && d.query.normalized) || []).forEach(function (n) { if (out[n.to]) out[n.from] = out[n.to]; });
return out;
}, function () { return {}; });
}
}
function first(po, k) { var v = po && po[k]; if (!v || !v.length) return ''; v = v[0]; return typeof v === 'object' ? (v.fulltext || v.raw || '') : v; }
function first(po, k) { var v = po && po[k]; if (!v || !v.length) return ''; v = v[0]; return typeof v === 'object' ? (v.fulltext || v.raw || '') : v; }
Line 139: Line 154:
}).join('');
}).join('');
}
}
// Where a passage sits in its bilingual layout: the same rules as the
// citations panel (Module:SscCitations bilingualLink).
var SINGLE_PAGE_BILINGUAL = { '013-Tsadra-BCA-Com-Minyak-Ch9': 1, '011-Tsadra-BCA-Com-Pawo': 1 };
var NAMED_BILINGUAL_SUBPAGE = { '020-Tsadra-BC-Root-Bhavanakrama-1': 'Bhavanakrama-1', '020-Tsadra-BC-Root-Bhavanakrama-2': 'Bhavanakrama-2', '020-Tsadra-BC-Root-Bhavanakrama-3': 'Bhavanakrama-3' };
function bilingual(po, title) {
function bilingual(po, title) {
var base = first(po, 'TranslationWikiPage'), ch = first(po, 'TranslationChapter'), ord = first(po, 'SegmentOrder');
var tm = first(po, 'TransMemID') || title.split('/')[0].replace('Translation Memory:', '');
if (!base || !ord) return '';
var base = first(po, 'TranslationWikiPage'), ch = first(po, 'TranslationChapter');
ord = String(ord).replace(/,/g, '');
var ord = String(first(po, 'SegmentOrder') || first(po, 'SourceSegmentOrder') || '').replace(/,/g, '');
return mw.util.getUrl(base + '/Bilingual' + (ch ? '/' + ch : '')) + '#seg-' + ord;
if (!base) { base = first(po, 'SourceWikiPage'); return base ? mw.util.getUrl(base) : ''; }
if (!ord) return mw.util.getUrl(base + '/Bilingual');
if (NAMED_BILINGUAL_SUBPAGE[tm]) return mw.util.getUrl(base + '/Bilingual/' + NAMED_BILINGUAL_SUBPAGE[tm]) + '#seg-' + ord;
if (SINGLE_PAGE_BILINGUAL[tm] || !ch) return mw.util.getUrl(base + '/Bilingual') + '#seg-' + ord;
return mw.util.getUrl(base + '/Bilingual/' + ch) + '#seg-' + ord;
}
}
function renderPassages(hits, data) {
function renderPassages(hits, data) {
Line 151: Line 174:
var ch = first(po, 'TranslationChapter'), href = bilingual(po, h.title);
var ch = first(po, 'TranslationChapter'), href = bilingual(po, h.title);
return '<div class="bcas__hit"><div class="bcas__hit-title">' + (href ? '<a href="' + esc(href) + '">' : '') + esc(String(work).replace(/^(Books|Articles|Dissertations)\//, '')) + (href ? '</a>' : '') + '</div>' +
return '<div class="bcas__hit"><div class="bcas__hit-title">' + (href ? '<a href="' + esc(href) + '">' : '') + esc(String(work).replace(/^(Books|Articles|Dissertations)\//, '')) + (href ? '</a>' : '') + '</div>' +
'<div class="bcas__hit-meta">' + (ch ? '<span>Chapter ' + esc(ch) + '</span>' : '') + '<span>passage ' + esc(h.title.split('/').pop()) + '</span><span>' + link(h.title, 'segment record') + '</span></div>' +
'<div class="bcas__hit-meta">' + (ch ? '<span>Chapter ' + esc(ch) + '</span>' : '') + '<span>passage ' + esc(h.title.split('/').pop()) + '</span>' + (href ? '<span>bilingual view</span>' : '') + '</div>' +
(h.snippet ? '<div class="bcas__snip">…' + h.snippet + '…</div>' : '') + '</div>';
(h.snippet ? '<div class="bcas__snip">…' + h.snippet + '…</div>' : '') + '</div>';
}).join('');
}).join('');
Line 202: Line 225:
$('#bcas-more').prop('hidden', true);
$('#bcas-more').prop('hidden', true);
$('#bcas-status').text('Searching…');
$('#bcas-status').text('Searching…');
search(g, g.id === 'library' ? state.cls : '', state.offset, PAGE).then(function (r) {
var key = state.q + '|' + state.cls;
var cached = (g.id === 'library' && state.cls && state.offset === 0 && firstPages[key]);
return (cached ? $.Deferred().resolve(cached).promise() : search(g, g.id === 'library' ? state.cls : '', state.offset, PAGE)).then(function (r) {
if (my !== token) return;
if (my !== token) return;
var hits = r.search || [];
var hits = r.search || [];
Line 210: Line 235:
var p;
var p;
if (g.id === 'library') {
if (g.id === 'library') {
// Covers load lazily from Special:Redirect, so the rows do not wait on an
// image lookup (the files live on Commons, which can be slow).
p = ask(titles, '|?Citation|?Class|?Pubdate|?Title|?FrontCoverImg').then(function (data) {
p = ask(titles, '|?Citation|?Class|?Pubdate|?Title|?FrontCoverImg').then(function (data) {
var files = []; titles.forEach(function (t) { var f = first(((data[t] || {}).printouts) || {}, 'FrontCoverImg'); if (f) files.push(f); });
var th = {};
return covers(files).then(function (th) { return renderLibrary(hits, data, th); });
titles.forEach(function (t) { var f = first(((data[t] || {}).printouts) || {}, 'FrontCoverImg'); if (f) th[f] = mw.util.getUrl('Special:Redirect/file/' + f.replace(/^File:/, ''), { width: 120 }); });
return renderLibrary(hits, data, th);
});
});
} else if (g.id === 'passages') {
} else if (g.id === 'passages') {
p = ask(titles, '|?TranslationWikiPage|?TranslationChapter|?SegmentOrder').then(function (data) { return renderPassages(hits, data); });
p = ask(titles, '|?TranslationWikiPage|?TranslationChapter|?SegmentOrder|?SourceSegmentOrder|?TransMemID|?SourceWikiPage').then(function (data) { return renderPassages(hits, data); });
} else {
} else {
p = $.Deferred().resolve(renderPlain(hits)).promise();
p = $.Deferred().resolve(renderPlain(hits)).promise();
Line 256: Line 284:
counts = {};
counts = {};
renderTabs();
renderTabs();
var my = token + 1;
// The results come first; the counts follow once they are on screen, so the
// Counts for every group, then for each library class, all in parallel.
// first page is not queued behind eleven count searches (and a class button
$.when.apply($, GROUPS.map(function (g) {
// clicked early does not wait behind them either).
var listDone = loadList(false) || $.Deferred().resolve().promise();
listDone.always(function () { $.when.apply($, GROUPS.map(function (g) {
return search(g, '', 0, 1).then(function (r) { counts[g.id] = r.searchinfo.totalhits; }, function () { counts[g.id] = 0; });
return search(g, '', 0, 1).then(function (r) { counts[g.id] = r.searchinfo.totalhits; }, function () { counts[g.id] = 0; });
})).always(function () {
})).always(function () {
Line 265: Line 295:
var cc = {};
var cc = {};
$.when.apply($, CLASSES.map(function (c) {
$.when.apply($, CLASSES.map(function (c) {
return search(GROUPS[0], c, 0, 1).then(function (r) { cc[c] = r.searchinfo.totalhits; }, function () {});
return search(GROUPS[0], c, 0, PAGE).then(function (r) { cc[c] = r.searchinfo.totalhits; firstPages[state.q + '|' + c] = r; }, function () {});
})).always(function () { renderPills(cc); });
})).always(function () { renderPills(cc); });
}
}
});
}); });
loadList(false);
}
}


Line 278: Line 307:
$('#bcas-q').val(params.get('q') || '');
$('#bcas-q').val(params.get('q') || '');
$('#bcas-form').on('submit', function (e) { e.preventDefault(); state.cls = ''; run(); });
$('#bcas-form').on('submit', function (e) { e.preventDefault(); state.cls = ''; run(); });
// Clearing the box (its x, or deleting the text) returns to the browse panels.
$('#bcas-q').on('input search', function () { if (!this.value.trim() && state.q) { state.cls = ''; state.tab = 'library'; run(); } });
$('.bcas__tips').on('click', 'a[data-q]', function () { $('#bcas-q').val($(this).attr('data-q')); state.cls = ''; run(); });
$('#bcas-hint').on('click', 'a[data-q]', function () { $('#bcas-q').val($(this).attr('data-q')); state.cls = ''; run(); });
$('#bcas-hint').on('click', 'a[data-q]', function () { $('#bcas-q').val($(this).attr('data-q')); state.cls = ''; run(); });
$('#bcas-tabs').on('click', '.bcas__tab', function () { state.tab = $(this).data('tab'); state.cls = ''; writeUrl(); renderTabs(); $('#bcas-pills').prop('hidden', true); if (state.tab === 'library') run(); else loadList(false); });
$('#bcas-tabs').on('click', '.bcas__tab', function () { state.tab = $(this).data('tab'); state.cls = ''; writeUrl(); renderTabs(); $('#bcas-pills').prop('hidden', true); if (state.tab === 'library') run(); else loadList(false); });

Latest revision as of 17:41, 8 October 2026

Site search for the Bodhicitta wiki (preview). Used on Advanced Search/Preview. Full-text search through CirrusSearch, results grouped (library, passages in the aligned texts, essays, topics, people), class filters with counts, the library's bibliographic rows, and the search kept in the page address so it can be shared.