Fossil SCM

Hook up the event handlers for the /chat search UI. Next up: run the search.

stephan 2024-06-30 13:57 fts5-chat-search
Commit 7f745aa647fa6b068bf3e4527116ffaae41557f5f82a6b7e8c5958d03028b9ad
1 file changed +56 -26
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -175,21 +175,29 @@
175175
activeUser: undefined,
176176
match: function(uname){
177177
return this.activeUser===uname || !this.activeUser;
178178
}
179179
},
180
- /** Gets (no args) or sets (1 arg) the current input text field value,
181
- taking into account single- vs multi-line input. The getter returns
182
- a string and the setter returns this object. */
183
- inputValue: function(){
180
+ /** Gets (no args) or sets (1 arg) the current input text field
181
+ value, taking into account single- vs multi-line input. The
182
+ getter returns a string and the setter returns this
183
+ object. As a special case, if arguments[0] is a boolean
184
+ value, it behaves like a getter and, if arguments[0]===true
185
+ it clears the input field before returning. */
186
+ inputValue: function(/*string newValue | bool clearInputField*/){
184187
const e = this.inputElement();
185
- if(arguments.length){
188
+ if(arguments.length && 'boolean'!==typeof arguments[0]){
186189
if(e.isContentEditable) e.innerText = arguments[0];
187190
else e.value = arguments[0];
188191
return this;
189192
}
190
- return e.isContentEditable ? e.innerText : e.value;
193
+ const rc = e.isContentEditable ? e.innerText : e.value;
194
+ if( true===arguments[0] ){
195
+ if(e.isContentEditable) e.innerText = '';
196
+ else e.value = '';
197
+ }
198
+ return rc;
191199
},
192200
/** Asks the current user input field to take focus. Returns this. */
193201
inputFocus: function(){
194202
this.inputElement().focus();
195203
return this;
@@ -514,11 +522,11 @@
514522
const uDate = self.usersLastSeen[u];
515523
if(self.filterState.activeUser===u){
516524
uSpan.classList.add('selected');
517525
}
518526
uSpan.dataset.uname = u;
519
- D.append(uSpan, u, "\n",
527
+ D.append(uSpan, u, "\n",
520528
D.append(
521529
D.addClass(D.span(),'timestamp'),
522530
localTimeString(uDate)//.substr(5/*chop off year*/)
523531
));
524532
if(uDate.$uColor){
@@ -1426,16 +1434,23 @@
14261434
14271435
/**
14281436
Submits the contents of the message input field (if not empty)
14291437
and/or the file attachment field to the server. If both are
14301438
empty, this is a no-op.
1439
+
1440
+ If the current view is the history search, this instead sends the
1441
+ input text to that widget.
14311442
*/
14321443
Chat.submitMessage = function f(){
14331444
if(!f.spaces){
14341445
f.spaces = /\s+$/;
14351446
f.markdownContinuation = /\\\s+$/;
14361447
f.spaces2 = /\s{3,}$/;
1448
+ }
1449
+ if( this.e.currentView===this.e.viewSearch ){
1450
+ this.submitSearch();
1451
+ return;
14371452
}
14381453
this.setCurrentView(this.e.viewMessages);
14391454
const fd = new FormData();
14401455
const fallback = {msg: this.inputValue()};
14411456
var msg = fallback.msg;
@@ -1573,19 +1588,19 @@
15731588
tall vs wide. Can be toggled via settings. */
15741589
document.body.classList.add('my-messages-right');
15751590
}
15761591
const settingsButton = document.querySelector('#chat-button-settings');
15771592
const optionsMenu = E1('#chat-config-options');
1578
- const cbToggle = function(ev){
1593
+ const eToggleView = function(ev){
15791594
ev.preventDefault();
15801595
ev.stopPropagation();
15811596
Chat.setCurrentView(Chat.e.currentView===Chat.e.viewConfig
15821597
? Chat.e.viewMessages : Chat.e.viewConfig);
15831598
return false;
15841599
};
1585
- D.attr(settingsButton, 'role', 'button').addEventListener('click', cbToggle, false);
1586
- Chat.e.viewConfig.querySelector('button.action-close').addEventListener('click', cbToggle, false);
1600
+ D.attr(settingsButton, 'role', 'button').addEventListener('click', eToggleView, false);
1601
+ Chat.e.viewConfig.querySelector('button.action-close').addEventListener('click', eToggleView, false);
15871602
15881603
/** Internal acrobatics to allow certain settings toggles to access
15891604
related toggles. */
15901605
const namedOptions = {
15911606
activeUsers:{
@@ -1917,11 +1932,11 @@
19171932
s.value ? 'add' : 'remove'
19181933
]('compact');
19191934
Chat.e.inputFields[Chat.e.inputFields.$currentIndex].focus();
19201935
});
19211936
Chat.settings.addListener('edit-ctrl-send',function(s){
1922
- const label = (s.value ? "Ctrl-" : "")+"Enter submits messages.";
1937
+ const label = "Submit message ("+(s.value ? "Ctrl-" : "")+"Enter)";
19231938
Chat.e.inputFields.forEach((e)=>{
19241939
const v = e.dataset.placeholder0 + " " +label;
19251940
if(e.isContentEditable) e.dataset.placeholder = v;
19261941
else D.attr(e,'placeholder',v);
19271942
});
@@ -1997,22 +2012,30 @@
19972012
};
19982013
btnPreview.addEventListener('click', submit, false);
19992014
})()/*message preview setup*/;
20002015
20012016
(function(){/*Set up #chat-search and related bits */
2002
- const settingsButton = document.querySelector('#chat-button-search');
2003
- const eBody = E1('#chat-search-body');
2004
- const cbToggle = function(ev){
2017
+ const btn = document.querySelector('#chat-button-search');
2018
+ D.attr(btn, 'role', 'button').addEventListener('click', function(ev){
2019
+ ev.preventDefault();
2020
+ ev.stopPropagation();
2021
+ const msg = Chat.inputValue();
2022
+ if( Chat.e.currentView===Chat.e.viewSearch ){
2023
+ if( msg ) Chat.submitSearch();
2024
+ else Chat.setCurrentView(Chat.e.viewMessages);
2025
+ }else{
2026
+ Chat.setCurrentView(Chat.e.viewSearch);
2027
+ if( msg ) Chat.submitSearch();
2028
+ }
2029
+ return false;
2030
+ }, false);
2031
+ Chat.e.viewSearch.querySelector('button.action-close').addEventListener('click', function(ev){
20052032
ev.preventDefault();
20062033
ev.stopPropagation();
2007
- Chat.setCurrentView(Chat.e.currentView===Chat.e.viewSearch
2008
- ? Chat.e.viewMessages : Chat.e.viewSearch);
2034
+ Chat.setCurrentView(Chat.e.viewMessages);
20092035
return false;
2010
- };
2011
- D.attr(settingsButton, 'role', 'button').addEventListener('click', cbToggle, false);
2012
- Chat.e.viewSearch.querySelector('button.action-close').addEventListener('click', cbToggle, false);
2013
-
2036
+ }, false);
20142037
})()/*search view setup*/;
20152038
20162039
/** Callback for poll() to inject new content into the page. jx ==
20172040
the response from /chat-poll. If atEnd is true, the message is
20182041
appended to the end of the chat list (for loading older
@@ -2141,10 +2164,23 @@
21412164
D.append(wrapper, btn);
21422165
btn.addEventListener('click',()=>loadOldMessages(-1));
21432166
D.append(Chat.e.viewMessages, toolbar);
21442167
toolbar.disabled = true /*will be enabled when msg load finishes */;
21452168
})()/*end history loading widget setup*/;
2169
+
2170
+ /**
2171
+ Submits a history search using the main input field's current
2172
+ text. It is assumed that Chat.e.viewSearch===Chat.e.currentView.
2173
+ */
2174
+ Chat.submitSearch = function(){
2175
+ const term = this.inputValue(true);
2176
+ const eMWC = D.clearElement(
2177
+ this.e.viewSearch.querySelector('.message-widget-content')
2178
+ );
2179
+ if( !term ) return;
2180
+ D.append(eMWC, "TODO: search term = ", term);
2181
+ };
21462182
21472183
const afterFetch = function f(){
21482184
if(true===f.isFirstCall){
21492185
f.isFirstCall = false;
21502186
Chat.ajaxEnd();
@@ -2203,17 +2239,11 @@
22032239
Chat._gotServerError = poll.running = false;
22042240
if( window.fossil.config.chat.fromcli ){
22052241
Chat.chatOnlyMode(true);
22062242
}
22072243
Chat.intervalTimer = setInterval(poll, 1000);
2208
- if(0){
2209
- const flip = (ev)=>Chat.animate(ev.target,'anim-flip-h');
2210
- document.querySelectorAll('#chat-buttons-wrapper .cbutton').forEach(function(e){
2211
- e.addEventListener('click',flip, false);
2212
- });
2213
- }
22142244
delete ForceResizeKludge.$disabled;
22152245
ForceResizeKludge();
22162246
Chat.animate.$disabled = false;
22172247
setTimeout( ()=>Chat.inputFocus(), 0 );
22182248
F.page.chat = Chat/* enables testing the APIs via the dev tools */;
22192249
});
22202250
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -175,21 +175,29 @@
175 activeUser: undefined,
176 match: function(uname){
177 return this.activeUser===uname || !this.activeUser;
178 }
179 },
180 /** Gets (no args) or sets (1 arg) the current input text field value,
181 taking into account single- vs multi-line input. The getter returns
182 a string and the setter returns this object. */
183 inputValue: function(){
 
 
 
184 const e = this.inputElement();
185 if(arguments.length){
186 if(e.isContentEditable) e.innerText = arguments[0];
187 else e.value = arguments[0];
188 return this;
189 }
190 return e.isContentEditable ? e.innerText : e.value;
 
 
 
 
 
191 },
192 /** Asks the current user input field to take focus. Returns this. */
193 inputFocus: function(){
194 this.inputElement().focus();
195 return this;
@@ -514,11 +522,11 @@
514 const uDate = self.usersLastSeen[u];
515 if(self.filterState.activeUser===u){
516 uSpan.classList.add('selected');
517 }
518 uSpan.dataset.uname = u;
519 D.append(uSpan, u, "\n",
520 D.append(
521 D.addClass(D.span(),'timestamp'),
522 localTimeString(uDate)//.substr(5/*chop off year*/)
523 ));
524 if(uDate.$uColor){
@@ -1426,16 +1434,23 @@
1426
1427 /**
1428 Submits the contents of the message input field (if not empty)
1429 and/or the file attachment field to the server. If both are
1430 empty, this is a no-op.
 
 
 
1431 */
1432 Chat.submitMessage = function f(){
1433 if(!f.spaces){
1434 f.spaces = /\s+$/;
1435 f.markdownContinuation = /\\\s+$/;
1436 f.spaces2 = /\s{3,}$/;
 
 
 
 
1437 }
1438 this.setCurrentView(this.e.viewMessages);
1439 const fd = new FormData();
1440 const fallback = {msg: this.inputValue()};
1441 var msg = fallback.msg;
@@ -1573,19 +1588,19 @@
1573 tall vs wide. Can be toggled via settings. */
1574 document.body.classList.add('my-messages-right');
1575 }
1576 const settingsButton = document.querySelector('#chat-button-settings');
1577 const optionsMenu = E1('#chat-config-options');
1578 const cbToggle = function(ev){
1579 ev.preventDefault();
1580 ev.stopPropagation();
1581 Chat.setCurrentView(Chat.e.currentView===Chat.e.viewConfig
1582 ? Chat.e.viewMessages : Chat.e.viewConfig);
1583 return false;
1584 };
1585 D.attr(settingsButton, 'role', 'button').addEventListener('click', cbToggle, false);
1586 Chat.e.viewConfig.querySelector('button.action-close').addEventListener('click', cbToggle, false);
1587
1588 /** Internal acrobatics to allow certain settings toggles to access
1589 related toggles. */
1590 const namedOptions = {
1591 activeUsers:{
@@ -1917,11 +1932,11 @@
1917 s.value ? 'add' : 'remove'
1918 ]('compact');
1919 Chat.e.inputFields[Chat.e.inputFields.$currentIndex].focus();
1920 });
1921 Chat.settings.addListener('edit-ctrl-send',function(s){
1922 const label = (s.value ? "Ctrl-" : "")+"Enter submits messages.";
1923 Chat.e.inputFields.forEach((e)=>{
1924 const v = e.dataset.placeholder0 + " " +label;
1925 if(e.isContentEditable) e.dataset.placeholder = v;
1926 else D.attr(e,'placeholder',v);
1927 });
@@ -1997,22 +2012,30 @@
1997 };
1998 btnPreview.addEventListener('click', submit, false);
1999 })()/*message preview setup*/;
2000
2001 (function(){/*Set up #chat-search and related bits */
2002 const settingsButton = document.querySelector('#chat-button-search');
2003 const eBody = E1('#chat-search-body');
2004 const cbToggle = function(ev){
 
 
 
 
 
 
 
 
 
 
 
 
2005 ev.preventDefault();
2006 ev.stopPropagation();
2007 Chat.setCurrentView(Chat.e.currentView===Chat.e.viewSearch
2008 ? Chat.e.viewMessages : Chat.e.viewSearch);
2009 return false;
2010 };
2011 D.attr(settingsButton, 'role', 'button').addEventListener('click', cbToggle, false);
2012 Chat.e.viewSearch.querySelector('button.action-close').addEventListener('click', cbToggle, false);
2013
2014 })()/*search view setup*/;
2015
2016 /** Callback for poll() to inject new content into the page. jx ==
2017 the response from /chat-poll. If atEnd is true, the message is
2018 appended to the end of the chat list (for loading older
@@ -2141,10 +2164,23 @@
2141 D.append(wrapper, btn);
2142 btn.addEventListener('click',()=>loadOldMessages(-1));
2143 D.append(Chat.e.viewMessages, toolbar);
2144 toolbar.disabled = true /*will be enabled when msg load finishes */;
2145 })()/*end history loading widget setup*/;
 
 
 
 
 
 
 
 
 
 
 
 
 
2146
2147 const afterFetch = function f(){
2148 if(true===f.isFirstCall){
2149 f.isFirstCall = false;
2150 Chat.ajaxEnd();
@@ -2203,17 +2239,11 @@
2203 Chat._gotServerError = poll.running = false;
2204 if( window.fossil.config.chat.fromcli ){
2205 Chat.chatOnlyMode(true);
2206 }
2207 Chat.intervalTimer = setInterval(poll, 1000);
2208 if(0){
2209 const flip = (ev)=>Chat.animate(ev.target,'anim-flip-h');
2210 document.querySelectorAll('#chat-buttons-wrapper .cbutton').forEach(function(e){
2211 e.addEventListener('click',flip, false);
2212 });
2213 }
2214 delete ForceResizeKludge.$disabled;
2215 ForceResizeKludge();
2216 Chat.animate.$disabled = false;
2217 setTimeout( ()=>Chat.inputFocus(), 0 );
2218 F.page.chat = Chat/* enables testing the APIs via the dev tools */;
2219 });
2220
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -175,21 +175,29 @@
175 activeUser: undefined,
176 match: function(uname){
177 return this.activeUser===uname || !this.activeUser;
178 }
179 },
180 /** Gets (no args) or sets (1 arg) the current input text field
181 value, taking into account single- vs multi-line input. The
182 getter returns a string and the setter returns this
183 object. As a special case, if arguments[0] is a boolean
184 value, it behaves like a getter and, if arguments[0]===true
185 it clears the input field before returning. */
186 inputValue: function(/*string newValue | bool clearInputField*/){
187 const e = this.inputElement();
188 if(arguments.length && 'boolean'!==typeof arguments[0]){
189 if(e.isContentEditable) e.innerText = arguments[0];
190 else e.value = arguments[0];
191 return this;
192 }
193 const rc = e.isContentEditable ? e.innerText : e.value;
194 if( true===arguments[0] ){
195 if(e.isContentEditable) e.innerText = '';
196 else e.value = '';
197 }
198 return rc;
199 },
200 /** Asks the current user input field to take focus. Returns this. */
201 inputFocus: function(){
202 this.inputElement().focus();
203 return this;
@@ -514,11 +522,11 @@
522 const uDate = self.usersLastSeen[u];
523 if(self.filterState.activeUser===u){
524 uSpan.classList.add('selected');
525 }
526 uSpan.dataset.uname = u;
527 D.append(uSpan, u, "\n",
528 D.append(
529 D.addClass(D.span(),'timestamp'),
530 localTimeString(uDate)//.substr(5/*chop off year*/)
531 ));
532 if(uDate.$uColor){
@@ -1426,16 +1434,23 @@
1434
1435 /**
1436 Submits the contents of the message input field (if not empty)
1437 and/or the file attachment field to the server. If both are
1438 empty, this is a no-op.
1439
1440 If the current view is the history search, this instead sends the
1441 input text to that widget.
1442 */
1443 Chat.submitMessage = function f(){
1444 if(!f.spaces){
1445 f.spaces = /\s+$/;
1446 f.markdownContinuation = /\\\s+$/;
1447 f.spaces2 = /\s{3,}$/;
1448 }
1449 if( this.e.currentView===this.e.viewSearch ){
1450 this.submitSearch();
1451 return;
1452 }
1453 this.setCurrentView(this.e.viewMessages);
1454 const fd = new FormData();
1455 const fallback = {msg: this.inputValue()};
1456 var msg = fallback.msg;
@@ -1573,19 +1588,19 @@
1588 tall vs wide. Can be toggled via settings. */
1589 document.body.classList.add('my-messages-right');
1590 }
1591 const settingsButton = document.querySelector('#chat-button-settings');
1592 const optionsMenu = E1('#chat-config-options');
1593 const eToggleView = function(ev){
1594 ev.preventDefault();
1595 ev.stopPropagation();
1596 Chat.setCurrentView(Chat.e.currentView===Chat.e.viewConfig
1597 ? Chat.e.viewMessages : Chat.e.viewConfig);
1598 return false;
1599 };
1600 D.attr(settingsButton, 'role', 'button').addEventListener('click', eToggleView, false);
1601 Chat.e.viewConfig.querySelector('button.action-close').addEventListener('click', eToggleView, false);
1602
1603 /** Internal acrobatics to allow certain settings toggles to access
1604 related toggles. */
1605 const namedOptions = {
1606 activeUsers:{
@@ -1917,11 +1932,11 @@
1932 s.value ? 'add' : 'remove'
1933 ]('compact');
1934 Chat.e.inputFields[Chat.e.inputFields.$currentIndex].focus();
1935 });
1936 Chat.settings.addListener('edit-ctrl-send',function(s){
1937 const label = "Submit message ("+(s.value ? "Ctrl-" : "")+"Enter)";
1938 Chat.e.inputFields.forEach((e)=>{
1939 const v = e.dataset.placeholder0 + " " +label;
1940 if(e.isContentEditable) e.dataset.placeholder = v;
1941 else D.attr(e,'placeholder',v);
1942 });
@@ -1997,22 +2012,30 @@
2012 };
2013 btnPreview.addEventListener('click', submit, false);
2014 })()/*message preview setup*/;
2015
2016 (function(){/*Set up #chat-search and related bits */
2017 const btn = document.querySelector('#chat-button-search');
2018 D.attr(btn, 'role', 'button').addEventListener('click', function(ev){
2019 ev.preventDefault();
2020 ev.stopPropagation();
2021 const msg = Chat.inputValue();
2022 if( Chat.e.currentView===Chat.e.viewSearch ){
2023 if( msg ) Chat.submitSearch();
2024 else Chat.setCurrentView(Chat.e.viewMessages);
2025 }else{
2026 Chat.setCurrentView(Chat.e.viewSearch);
2027 if( msg ) Chat.submitSearch();
2028 }
2029 return false;
2030 }, false);
2031 Chat.e.viewSearch.querySelector('button.action-close').addEventListener('click', function(ev){
2032 ev.preventDefault();
2033 ev.stopPropagation();
2034 Chat.setCurrentView(Chat.e.viewMessages);
 
2035 return false;
2036 }, false);
 
 
 
2037 })()/*search view setup*/;
2038
2039 /** Callback for poll() to inject new content into the page. jx ==
2040 the response from /chat-poll. If atEnd is true, the message is
2041 appended to the end of the chat list (for loading older
@@ -2141,10 +2164,23 @@
2164 D.append(wrapper, btn);
2165 btn.addEventListener('click',()=>loadOldMessages(-1));
2166 D.append(Chat.e.viewMessages, toolbar);
2167 toolbar.disabled = true /*will be enabled when msg load finishes */;
2168 })()/*end history loading widget setup*/;
2169
2170 /**
2171 Submits a history search using the main input field's current
2172 text. It is assumed that Chat.e.viewSearch===Chat.e.currentView.
2173 */
2174 Chat.submitSearch = function(){
2175 const term = this.inputValue(true);
2176 const eMWC = D.clearElement(
2177 this.e.viewSearch.querySelector('.message-widget-content')
2178 );
2179 if( !term ) return;
2180 D.append(eMWC, "TODO: search term = ", term);
2181 };
2182
2183 const afterFetch = function f(){
2184 if(true===f.isFirstCall){
2185 f.isFirstCall = false;
2186 Chat.ajaxEnd();
@@ -2203,17 +2239,11 @@
2239 Chat._gotServerError = poll.running = false;
2240 if( window.fossil.config.chat.fromcli ){
2241 Chat.chatOnlyMode(true);
2242 }
2243 Chat.intervalTimer = setInterval(poll, 1000);
 
 
 
 
 
 
2244 delete ForceResizeKludge.$disabled;
2245 ForceResizeKludge();
2246 Chat.animate.$disabled = false;
2247 setTimeout( ()=>Chat.inputFocus(), 0 );
2248 F.page.chat = Chat/* enables testing the APIs via the dev tools */;
2249 });
2250

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button