Widget:BcaSearch: Difference between revisions

From Bodhicitta
(Start panel: two columns)
(Search: passages open in the bilingual view, faster class buttons, search tips)
Line 25: Line 25:
.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{cursor:pointer}
/* 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 41: Line 46:
.bcas-start__chips--small a{padding:.15rem .6rem;font-size:.82rem}
.bcas-start__chips--small a{padding:.15rem .6rem;font-size:.82rem}
.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 65:
</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>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 100:


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 133:
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 150:
}).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 170:
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 221:
$('#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]);
(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 231:
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 265: Line 289:
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); });
}
}
Line 278: Line 302:
$('#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(); });
$('.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); });

Revision as of 19:45, 2 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.