Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | chat: refactored the messages from fieldsets to a custom widget. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | chat-widget-rework |
| Files: | files | file ages | folders |
| SHA3-256: |
852bda77bd5e4326144bab68ad1e7d94 |
| User & Date: | stephan 2020-12-25 22:35:35.708 |
Context
|
2020-12-25
| ||
| 22:37 | Removed some dead CSS. ... (Closed-Leaf check-in: c9ca5198be user: stephan tags: chat-widget-rework) | |
| 22:35 | chat: refactored the messages from fieldsets to a custom widget. ... (check-in: 852bda77bd user: stephan tags: chat-widget-rework) | |
| 20:30 | For the chat function, the server-to-client JSON uses strict ISO8601 time strings, including the "T" in the middle and the "Z" at the end. ... (check-in: 13c95f0c75 user: drh tags: trunk) | |
Changes
Changes to src/chat.js.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 |
mnMsg: undefined/*lowest message ID we've seen so far (for history loading)*/,
pageIsActive: 'visible'===document.visibilityState,
changesSincePageHidden: 0,
notificationBubbleColor: 'white',
totalMessageCount: 0, // total # of inbound messages
//! Number of messages to load for the history buttons
loadMessageCount: Math.abs(F.config.chat.initSize || 20),
| < < < < < | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
mnMsg: undefined/*lowest message ID we've seen so far (for history loading)*/,
pageIsActive: 'visible'===document.visibilityState,
changesSincePageHidden: 0,
notificationBubbleColor: 'white',
totalMessageCount: 0, // total # of inbound messages
//! Number of messages to load for the history buttons
loadMessageCount: Math.abs(F.config.chat.initSize || 20),
ajaxInflight: 0,
/** Gets (no args) or sets (1 arg) the current input text field value,
taking into account single- vs multi-line input. The getter returns
a string and the setter returns this object. */
inputValue: function(){
const e = this.inputElement();
if(arguments.length){
|
| ︙ | ︙ | |||
136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
}
}
};
Object.keys(cs.settings.defaults).forEach(function f(k){
const v = cs.settings.get(k,f);
if(f===v) cs.settings.set(k,cs.settings.defaults[k]);
});
if(cs.settings.getBool('monospace-messages',false)){
document.body.classList.add('monospace-messages');
}
cs.e.inputCurrent = cs.e.inputSingle;
cs.pageTitleOrig = cs.e.pageTitle.innerText;
const qs = (e)=>document.querySelector(e);
const argsToArray = function(args){
| > > > > > > > | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
}
}
};
Object.keys(cs.settings.defaults).forEach(function f(k){
const v = cs.settings.get(k,f);
if(f===v) cs.settings.set(k,cs.settings.defaults[k]);
});
if(window.innerWidth<window.innerHeight){
/* Alignment of 'my' messages: right alignment is conventional
for mobile chat apps but can be difficult to read in wide
windows (desktop/tablet landscape mode). Can be toggled via
settings popup. */
document.body.classList.add('my-messages-right');
}
if(cs.settings.getBool('monospace-messages',false)){
document.body.classList.add('monospace-messages');
}
cs.e.inputCurrent = cs.e.inputSingle;
cs.pageTitleOrig = cs.e.pageTitle.innerText;
const qs = (e)=>document.querySelector(e);
const argsToArray = function(args){
|
| ︙ | ︙ | |||
221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
if(cs.pageIsActive){
cs.e.pageTitle.innerText = cs.pageTitleOrig;
}
}, true);
return cs;
})()/*Chat initialization*/;
const BlobXferState = (function(){/*drag/drop bits...*/
/* State for paste and drag/drop */
const bxs = {
dropDetails: document.querySelector('#chat-drop-details'),
blob: undefined,
clear: function(){
this.blob = undefined;
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
if(cs.pageIsActive){
cs.e.pageTitle.innerText = cs.pageTitleOrig;
}
}, true);
return cs;
})()/*Chat initialization*/;
/**
Custom widget type for rendering messages (one message per
instance). These are modelled after FIELDSET elements but we
don't use FIELDSET because of cross-browser inconsistencies in
features of the FIELDSET/LEGEND combination, e.g. inability to
align legends via CSS in Firefox and clicking-related
deficiencies in Safari.
*/
const MessageWidget = (function(){
const cf = function(){
this.e = {
body: D.addClass(D.div(), 'message-widget'),
tab: D.addClass(D.span(), 'message-widget-tab'),
content: D.addClass(D.div(), 'message-widget-content')
};
D.append(this.e.body, this.e.tab);
D.append(this.e.body, this.e.content);
this.e.tab.setAttribute('role', 'button');
};
cf.prototype = {
setLabel: function(label){
return this;
},
setPopupCallback: function(callback){
this.e.tab.addEventListener('click', callback, false);
return this;
},
setMessage: function(m){
const ds = this.e.body.dataset;
ds.timestamp = m.mtime;
ds.msgid = m.msgid;
ds.xfrom = m.xfrom;
if(m.xfrom === Chat.me){
D.addClass(this.e.body, 'mine');
}
this.e.content.style.backgroundColor = m.uclr;
this.e.tab.style.backgroundColor = m.uclr;
const d = new Date(m.mtime);
D.append(
D.clearElement(this.e.tab), D.text(
m.xfrom+' @ '+d.getHours()+":"+(d.getMinutes()+100).toString().slice(1,3))
);
var contentTarget = this.e.content;
if( m.fsize>0 ){
if( m.fmime
&& m.fmime.startsWith("image/")
&& Chat.settings.getBool('images-inline',true)
){
contentTarget.appendChild(D.img("chat-download/" + m.msgid));
}else{
const a = D.a(
window.fossil.rootPath+
'chat-download/' + m.msgid+'/'+encodeURIComponent(m.fname),
// ^^^ add m.fname to URL to cause downloaded file to have that name.
"(" + m.fname + " " + m.fsize + " bytes)"
)
D.attr(a,'target','_blank');
contentTarget.appendChild(a);
}
contentTarget = D.div();
}
if(m.xmsg){
if(contentTarget !== this.e.content){
D.append(this.e.content, contentTarget);
}
// The m.xmsg text comes from the same server as this script and
// is guaranteed by that server to be "safe" HTML - safe in the
// sense that it is not possible for a malefactor to inject HTML
// or javascript or CSS. The m.xmsg content might contain
// hyperlinks, but otherwise it will be markup-free. See the
// chat_format_to_html() routine in the server for details.
//
// Hence, even though innerHTML is normally frowned upon, it is
// perfectly safe to use in this context.
contentTarget.innerHTML = m.xmsg;
}
return this;
}
};
return cf;
})();
const BlobXferState = (function(){/*drag/drop bits...*/
/* State for paste and drag/drop */
const bxs = {
dropDetails: document.querySelector('#chat-drop-details'),
blob: undefined,
clear: function(){
this.blob = undefined;
|
| ︙ | ︙ | |||
411 412 413 414 415 416 417 |
f.popup.hide = function(){
delete this._eMsg;
D.clearElement(this.e);
return this.show(false);
};
}/*end static init*/
const rect = ev.target.getBoundingClientRect();
| | > | > | | | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 |
f.popup.hide = function(){
delete this._eMsg;
D.clearElement(this.e);
return this.show(false);
};
}/*end static init*/
const rect = ev.target.getBoundingClientRect();
const eMsg = ev.target.parentNode/*the owning .message-widget element*/;
f.popup._eMsg = eMsg;
console.debug("eMsg, rect", eMsg, rect);
let x = rect.left, y = rect.topm;
f.popup.show(ev.target)/*so we can get its computed size*/;
if(eMsg.dataset.xfrom===Chat.me
&& document.body.classList.contains('my-messages-right')){
// Shift popup to the left for right-aligned messages to avoid
// truncation off the right edge of the page.
const pRect = f.popup.e.getBoundingClientRect();
x = rect.right - pRect.width;
}
f.popup.show(x, y);
}/*handleLegendClicked()*/;
(function(){/*Set up #chat-settings-button */
const settingsButton = document.querySelector('#chat-settings-button');
var popupSize = undefined/*placement workaround*/;
|
| ︙ | ︙ | |||
493 494 495 496 497 498 499 |
D.removeClass(f.elemsToToggle, 'hidden');
D.removeClass(document.body, 'chat-only-mode');
iws.backgroundColor = f.initialBg;
}
}
},{
label: "Left-align my posts",
| | < | < < < < < < < | 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 |
D.removeClass(f.elemsToToggle, 'hidden');
D.removeClass(document.body, 'chat-only-mode');
iws.backgroundColor = f.initialBg;
}
}
},{
label: "Left-align my posts",
boolValue: ()=>!document.body.classList.contains('my-messages-right'),
callback: function f(){
document.body.classList.toggle('my-messages-right');
}
},{
label: "Images inline",
boolValue: ()=>Chat.settings.getBool('images-inline'),
callback: function(){
const v = Chat.settings.getBool('images-inline',true);
Chat.settings.set('images-inline', !v);
|
| ︙ | ︙ | |||
584 585 586 587 588 589 590 |
if( m.msgid>Chat.mxMsg ) Chat.mxMsg = m.msgid;
if( !Chat.mnMsg || m.msgid<Chat.mnMsg) Chat.mnMsg = m.msgid;
if( m.mdel ){
/* A record deletion notice. */
Chat.deleteMessageElem(m.mdel);
return;
}
| | < | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 |
if( m.msgid>Chat.mxMsg ) Chat.mxMsg = m.msgid;
if( !Chat.mnMsg || m.msgid<Chat.mnMsg) Chat.mnMsg = m.msgid;
if( m.mdel ){
/* A record deletion notice. */
Chat.deleteMessageElem(m.mdel);
return;
}
const row = new MessageWidget()
row.setMessage(m);
row.setPopupCallback(handleLegendClicked);
Chat.injectMessageElem(row.e.body,atEnd);
}/*processPost()*/;
}/*end static init*/
jx.msgs.forEach((m)=>f.processPost(m,atEnd));
if('visible'===document.visibilityState){
if(Chat.changesSincePageHidden){
Chat.changesSincePageHidden = 0;
Chat.e.pageTitle.innerText = Chat.pageTitleOrig;
|
| ︙ | ︙ |
Changes to src/default.css.
| ︙ | ︙ | |||
1471 1472 1473 1474 1475 1476 1477 |
/* Chat-related */
body.chat span.at-name { /* for @USERNAME references */
text-decoration: underline;
font-weight: bold;
}
/* A wrapper for a single single message (one row of the UI) */
| | | | < < < < > > > > | | | | | | > > > > > > | 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 |
/* Chat-related */
body.chat span.at-name { /* for @USERNAME references */
text-decoration: underline;
font-weight: bold;
}
/* A wrapper for a single single message (one row of the UI) */
body.chat .message-widget {
margin-bottom: 0.75em;
border: none;
display: flex;
flex-direction: column;
border: none;
align-items: flex-start;
}
body.chat.my-messages-right .message-widget.mine {
align-items: flex-end;
}
/* The content area of a message (the body element of a FIELDSET) */
body.chat .message-widget-content {
display: inline-block;
border-radius: 0.25em;
border: 1px solid rgba(0,0,0,0.2);
box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);
padding: 0.25em 0.5em;
margin-top: 0;
min-width: 9em /*avoid unsightly "underlap" with the user name label*/;
white-space: pre-wrap/*needed for multi-line edits*/;
}
body.chat.monospace-messages .message-widget-content,
body.chat.monospace-messages textarea,
body.chat.monospace-messages input[type=text]{
font-family: monospace;
}
/* User name for the post (a LEGEND element) */
body.chat .message-widget .message-widget-tab {
border-radius: 0.25em 0.25em 0 0;
padding: 0 0.5em;
/*text-align: left; Firefox requires the 'align' attribute */
margin: 0 0.25em 0em 0.15em;
padding: 0 0.5em 0.15em 0.5em;
cursor: pointer;
}
/*body.chat.my-messages-right .message-widget-tab {
}*/
body.chat .message-widget .message-widget-tab a {
text-decoration: none;
color: inherit;
}
body.chat .fossil-tooltip.help-buttonlet-content {
font-size: 80%;
}
body.chat .chat-message-popup {
|
| ︙ | ︙ |