Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Ensure that chat search results get placed in the proper parent DOM element (this fixes some layout unsightliness). Remove the DOM elements related to loading more search result context when they have no more results to load. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | fts5-chat-search |
| Files: | files | file ages | folders |
| SHA3-256: |
2e8f1a9a15eceed342c4690007b1cbd0 |
| User & Date: | stephan 2024-07-01 18:36:24.892 |
Context
|
2024-07-01
| ||
| 18:40 | Clean up some harmless stray tokens. ... (check-in: 417bb15064 user: stephan tags: fts5-chat-search) | |
| 18:36 | Ensure that chat search results get placed in the proper parent DOM element (this fixes some layout unsightliness). Remove the DOM elements related to loading more search result context when they have no more results to load. ... (check-in: 2e8f1a9a15 user: stephan tags: fts5-chat-search) | |
| 17:25 | Teach /chat search to use the same tokenizer as the main search index, defaulting to porter if the main search index is off, and reindex chat if the tokenizer is changed. The search config should arguably be expanded to provide the option of disabling chat search altogether, but that is beyond today's ambitions. Minor search result layout tweaks but there are still some fixes to do there. ... (check-in: 778efb30f7 user: stephan tags: fts5-chat-search) | |
Changes
Changes to src/chat.c.
| ︙ | ︙ | |||
216 217 218 219 220 221 222 | @ </span> @ <span>Active users (sorted by last message time)</span> @ </div> @ <div id='chat-user-list'></div> @ </div> @ <div id='chat-preview' class='hidden chat-view'> @ <header>Preview: (<a href='%R/md_rules' target='_blank'>markdown reference</a>)</header> | | | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
@ </span>
@ <span>Active users (sorted by last message time)</span>
@ </div>
@ <div id='chat-user-list'></div>
@ </div>
@ <div id='chat-preview' class='hidden chat-view'>
@ <header>Preview: (<a href='%R/md_rules' target='_blank'>markdown reference</a>)</header>
@ <div id='chat-preview-content'></div>
@ <div class='button-bar'><button class='action-close'>Close Preview</button></div>
@ </div>
@ <div id='chat-config' class='hidden chat-view'>
@ <div id='chat-config-options'></div>
/* ^^^populated client-side */
@ <div class='button-bar'><button class='action-close'>Close Settings</button></div>
@ </div>
@ <div id='chat-search' class='hidden chat-view'>
@ <div id='chat-search-content'></div>
/* ^^^populated client-side */
@ <div class='button-bar'>
@ <button class='action-clear'>Clear results</button>
@ <button class='action-close'>Close Search</button>
@ </div>
@ </div>
@ <div id='chat-messages-wrapper' class='chat-view'>
|
| ︙ | ︙ |
Changes to src/fossil.dom.js.
| ︙ | ︙ | |||
59 60 61 62 63 64 65 |
*/
dom.splitClassList = function f(str){
if(!f.rx){
f.rx = /(\s+|\s*,\s*)/;
}
return str ? str.split(f.rx) : [str];
};
| | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
*/
dom.splitClassList = function f(str){
if(!f.rx){
f.rx = /(\s+|\s*,\s*)/;
}
return str ? str.split(f.rx) : [str];
};
dom.div = dom.createElemFactory('div');
dom.p = dom.createElemFactory('p');
dom.code = dom.createElemFactory('code');
dom.pre = dom.createElemFactory('pre');
dom.header = dom.createElemFactory('header');
dom.footer = dom.createElemFactory('footer');
dom.section = dom.createElemFactory('section');
|
| ︙ | ︙ | |||
547 548 549 550 551 552 553 |
finally{
--f.counter;
}
if(!f.counter){
old.parentNode.removeChild(old);
}
};
| | | 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 |
finally{
--f.counter;
}
if(!f.counter){
old.parentNode.removeChild(old);
}
};
dom.replaceNode.counter = 0;
/**
Two args == getter: (e,key), returns value
Three or more == setter: (e,key,val[...,keyN,valN]), returns
e. If val===null or val===undefined then the attribute is
removed. If (e) has a forEach method then this routine is applied
to each element of that collection via that method. Each pair of
|
| ︙ | ︙ |
Changes to src/fossil.page.chat.js.
| ︙ | ︙ | |||
143 144 145 146 147 148 149 150 |
inputX: E1('#chat-input-field-x'),
input1: E1('#chat-input-field-single'),
inputM: E1('#chat-input-field-multi'),
inputFile: E1('#chat-input-file'),
contentDiv: E1('div.content'),
viewConfig: E1('#chat-config'),
viewPreview: E1('#chat-preview'),
viewSearch: E1('#chat-search'),
| > | | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
inputX: E1('#chat-input-field-x'),
input1: E1('#chat-input-field-single'),
inputM: E1('#chat-input-field-multi'),
inputFile: E1('#chat-input-file'),
contentDiv: E1('div.content'),
viewConfig: E1('#chat-config'),
viewPreview: E1('#chat-preview'),
previewContent: E1('#chat-preview-content'),
viewSearch: E1('#chat-search'),
searchContent: E1('#chat-search-content'),
btnPreview: E1('#chat-button-preview'),
views: document.querySelectorAll('.chat-view'),
activeUserListWrapper: E1('#chat-user-list-wrapper'),
activeUserList: E1('#chat-user-list')
},
me: F.user.name,
mxMsg: F.config.chat.initSize ? -F.config.chat.initSize : -50,
|
| ︙ | ︙ | |||
1338 1339 1340 1341 1342 1343 1344 |
** at any time.
*/
this.o = {
iFirstInTable: o.first,
iLastInTable: o.last,
iPrevId: o.previd,
iNextId: o.nextid,
| | < < < < < > | < > | | > | > < > > > | > > > > > > | > > > | > > > > > > > > | 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 |
** at any time.
*/
this.o = {
iFirstInTable: o.first,
iLastInTable: o.last,
iPrevId: o.previd,
iNextId: o.nextid,
bIgnoreClick: false
};
this.e = {
body: D.addClass(D.div(), 'spacer-widget'),
up: D.addClass(
D.button(zDownArrow+' Load '+nMsgContext+' more '+zDownArrow),
'up'
),
down: D.addClass(
D.button(zUpArrow+' Load '+nMsgContext+' more '+zUpArrow),
'down'
),
all: D.addClass(D.button('Load More'), 'all')
};
;
D.append( this.e.body, this.e.up, this.e.down, this.e.all );
const ms = this;
this.e.up.addEventListener('click', ()=>ms.load_messages(false));
this.e.down.addEventListener('click', ()=>ms.load_messages(true));
this.e.all.addEventListener('click', ()=>ms.load_messages( (ms.o.iPrevId==0) ));
this.set_button_visibility();
};
cf.prototype = {
set_button_visibility: function() {
if( !this.e ) return;
const o = this.o;
const iPrevId = (o.iPrevId!=0) ? o.iPrevId : o.iFirstInTable-1;
const iNextId = (o.iNextId!=0) ? o.iNextId : o.iLastInTable+1;
let nDiff = (iNextId - iPrevId) - 1;
for( const x of [this.e.up, this.e.down, this.e.all] ){
if( x ) D.addClass(x, 'hidden');
}
let nVisible = 0;
if( nDiff>0 ){
if( nDiff>nMsgContext && (o.iPrevId==0 || o.iNextId==0) ){
nDiff = nMsgContext;
}
if( nDiff<=nMsgContext && o.iPrevId!=0 && o.iNextId!=0 ){
D.removeClass(this.e.all, 'hidden');
++nVisible;
this.e.all.innerText = (
zUpArrow + " Load " + nDiff + " more " + zDownArrow
);
}else{
if( o.iPrevId!=0 ){
++nVisible;
D.removeClass(this.e.up, 'hidden');
}else if( this.e.up ){
if( this.e.up.parentNode ) D.remove(this.e.up);
delete this.e.up;
}
if( o.iNextId!=0 ){
++nVisible;
D.removeClass(this.e.down, 'hidden');
}else if( this.e.down ){
if( this.e.down.parentNode ) D.remove( this.e.down );
delete this.e.down;
}
}
}
if( !nVisible ){
/* The DOM elements can now be disposed of. */
for( const x of [this.e.up, this.e.down, this.e.all, this.e.body] ){
if( x?.parentNode ) D.remove(x);
}
delete this.e;
}
},
load_messages: function(bDown) {
if( this.bIgnoreClick ) return;
var iFirst = 0; /* msgid of first message to fetch */
|
| ︙ | ︙ | |||
1430 1431 1432 1433 1434 1435 1436 |
urlParams:{
q: '',
n: nFetch,
i: iFirst
},
responseType: "json",
onload:function(jx){
| | > > > > | > | | 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 |
urlParams:{
q: '',
n: nFetch,
i: iFirst
},
responseType: "json",
onload:function(jx){
if( bDown ) jx.msgs.reverse();
jx.msgs.forEach((m) => {
var mw = new Chat.MessageWidget(m);
if( bDown ){
/* Inject the message below this object's body, or
append it to Chat.e.searchContent if this element
is the final one in its parent (Chat.e.searchContent). */
const eAnchor = e.body.nextElementSibling;
if( eAnchor ) Chat.e.searchContent.insertBefore(mw.e.body, eAnchor);
else D.append(Chat.e.searchContent, mw.e.body);
}else{
Chat.e.searchContent.insertBefore(mw.e.body, e.body);
}
});
if( bDown ){
o.iNextId -= jx.msgs.length;
}else{
o.iPrevId += jx.msgs.length;
}
|
| ︙ | ︙ | |||
2345 2346 2347 2348 2349 2350 2351 2352 |
/**
Clears the search result view. If addInstructions is true it adds
text to that view instructing the user to enter their query into
the message-entry widget (noting that that widget has text
implying that it's only for submitting a message, which isn't
exactly true when the search view is active).
*/
| > > > | | < < | 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 |
/**
Clears the search result view. If addInstructions is true it adds
text to that view instructing the user to enter their query into
the message-entry widget (noting that that widget has text
implying that it's only for submitting a message, which isn't
exactly true when the search view is active).
Returns the DOM element which wraps all of the chat search
result elements.
*/
Chat.clearSearch = function f(addInstructions=false){
const e = D.clearElement( this.e.searchContent );
if(addInstructions){
D.append(e, "Enter search terms in the message field.");
}
return e;
};
Chat.clearSearch(true);
/**
|
| ︙ | ︙ | |||
2380 2381 2382 2383 2384 2385 2386 |
const mw = new Chat.MessageWidget(m);
const spacer = new Chat.SearchCtxLoader({
first: jx.first,
last: jx.last,
previd: previd,
nextid: m.msgid
});
| > | | | | 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 |
const mw = new Chat.MessageWidget(m);
const spacer = new Chat.SearchCtxLoader({
first: jx.first,
last: jx.last,
previd: previd,
nextid: m.msgid
});
if( spacer.e ) D.append( eMsgTgt, spacer.e.body );
D.append( eMsgTgt, mw.e.body );
previd = m.msgid;
});
if( jx.msgs.length ){
const spacer = new Chat.SearchCtxLoader({
first: jx.first,
last: jx.last,
previd: previd,
nextid: 0
});
if( spacer.e ) D.append( eMsgTgt, spacer.e.body );
}else{
D.append( D.clearElement(eMsgTgt),
'No search results found for: ',
term );
}
}
}
);
}/*Chat.submitSearch()*/;
const afterFetch = function f(){
if(true===f.isFirstCall){
f.isFirstCall = false;
Chat.ajaxEnd();
Chat.e.viewMessages.classList.remove('loading');
setTimeout(function(){
|
| ︙ | ︙ |
Changes to src/style.chat.css.
| ︙ | ︙ | |||
517 518 519 520 521 522 523 |
font-weight: normal;
white-space: pre-wrap;
display: inline-block;
opacity: 0.85;
}
body.chat #chat-config #chat-config-options .menu-entry select {
}
| | | | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 |
font-weight: normal;
white-space: pre-wrap;
display: inline-block;
opacity: 0.85;
}
body.chat #chat-config #chat-config-options .menu-entry select {
}
body.chat #chat-preview #chat-preview-content,
body.chat #chat-search #chat-search-content {
overflow: auto;
flex: 1 1 auto;
padding: 0.5em;
border: 1px dotted;
}
body.chat #chat-preview #chat-preview-content > * {
|
| ︙ | ︙ |