Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Moved chat.c inline CSS style to default.css. Various chat layout tweaks. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
467dbc8fd7881af4b2ea01eb23c2633f |
| User & Date: | stephan 2020-12-25 11:06:31.708 |
Context
|
2020-12-25
| ||
| 11:32 | chat setting: toggle whether 'my' messages are on the right or left, with the default depending on whether the window is wider than it is tall. ... (check-in: f1e91a200a user: stephan tags: trunk) | |
| 11:06 | Moved chat.c inline CSS style to default.css. Various chat layout tweaks. ... (check-in: 467dbc8fd7 user: stephan tags: trunk) | |
| 10:04 | Added settings popup to chat. Currently only 1 setting - toggling the page header/footer on/off. ... (check-in: 617e23bea3 user: stephan tags: trunk) | |
Changes
Changes to src/chat.c.
| ︙ | ︙ | |||
90 91 92 93 94 95 96 |
return;
}
iPingTcp = atoi(PD("ping","0"));
if( iPingTcp<1000 || iPingTcp>65535 ) iPingTcp = 0;
if( iPingTcp ) style_disable_csp();
style_set_current_feature("chat");
style_header("Chat");
| < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
return;
}
iPingTcp = atoi(PD("ping","0"));
if( iPingTcp<1000 || iPingTcp>65535 ) iPingTcp = 0;
if( iPingTcp ) style_disable_csp();
style_set_current_feature("chat");
style_header("Chat");
@ <div id='chat-input-area'>
@ <form accept-encoding="utf-8" id="chat-form" autocomplete="off">
@ <div id='chat-input-line'>
@ <input type="text" name="msg" id="sbox" \
@ placeholder="Type message here.">
@ <input type="submit" value="Send">
@ <span id="chat-settings-button" class="settings-icon"></span>
@ </div>
@ <div id='chat-input-file-area'>
@ <div class='file-selection-wrapper'>
@ <div class='help-buttonlet'>
@ Select a file to upload, drag/drop a file into this spot,
@ or paste an image from the clipboard if supported by
@ your environment.
@ </div>
@ <input type="file" name="file" id="chat-input-file">
@ </div>
@ <div id="chat-drop-details"></div>
@ </div>
@ </form>
@ </div>
/* New chat messages get inserted immediately after this element */
@ <div id='chat-messages-wrapper'>
@ <span id='message-inject-point'></span>
@ </div>
builtin_fossil_js_bundle_or("popupwidget", NULL);
/* Always in-line the javascript for the chat page */
@ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
/* We need an onload handler to ensure that window.fossil is
initialized before the chat init code runs. */
@ window.addEventListener('load', function(){
|
| ︙ | ︙ |
Changes to src/chat.js.
1 2 3 4 5 6 7 8 9 10 |
/**
This file contains the client-side implementation of fossil's /chat
application.
*/
(function(){
const form = document.querySelector('#chat-form');
const F = window.fossil, D = F.dom;
const Chat = (function(){
const cs = {
e:{/*map of certain DOM elements.*/
| > > > > > | | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/**
This file contains the client-side implementation of fossil's /chat
application.
*/
(function(){
const form = document.querySelector('#chat-form');
const F = window.fossil, D = F.dom;
const E1 = function(selector){
const e = document.querySelector(selector);
if(!e) throw new Error("missing required DOM element: "+selector);
return e;
};
const Chat = (function(){
const cs = {
e:{/*map of certain DOM elements.*/
messageInjectPoint: E1('#message-inject-point'),
pageTitle: E1('head title'),
loadToolbar: undefined /* the load-posts toolbar (dynamically created) */,
messagesWrapper: E1('#chat-messages-wrapper')
},
me: F.user.name,
mxMsg: F.config.chatInitSize ? -F.config.chatInitSize : -50,
mnMsg: undefined/*lowest message ID we've seen so far (for history loading)*/,
pageIsActive: 'visible'===document.visibilityState,
changesSincePageHidden: 0,
notificationBubbleColor: 'white',
|
| ︙ | ︙ | |||
353 354 355 356 357 358 359 |
(function(){/*Set up #chat-settings-button */
const settingsButton = document.querySelector('#chat-settings-button');
var popupSize = undefined/*placement workaround*/;
const settingsPopup = new F.PopupWidget({
cssClass: ['fossil-tooltip', 'chat-settings-popup'],
adjustY: function(y){
const rect = settingsButton.getBoundingClientRect();
| | > | > > | > > | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 |
(function(){/*Set up #chat-settings-button */
const settingsButton = document.querySelector('#chat-settings-button');
var popupSize = undefined/*placement workaround*/;
const settingsPopup = new F.PopupWidget({
cssClass: ['fossil-tooltip', 'chat-settings-popup'],
adjustY: function(y){
const rect = settingsButton.getBoundingClientRect();
return rect.top + rect.height + 2;
}
});
settingsPopup.installClickToHide();
const btnToggleBody = D.button("Toggle page body");
D.append(settingsPopup.e, btnToggleBody);
const toggleBody = function f(){
if(f.isHidden){
D.removeClass(f.elemsToToggle, 'hidden');
D.removeClass(document.body, 'chat-only-mode');
}else{
D.addClass(f.elemsToToggle, 'hidden');
D.addClass(document.body, 'chat-only-mode');
}
f.isHidden = !f.isHidden;
};
toggleBody.elemsToToggle = [];
toggleBody.isHidden = false;
document.body.childNodes.forEach(function(e){
if(!e.classList) return/*TEXT nodes and such*/;
else if(!e.classList.contains('content')){
|
| ︙ | ︙ | |||
384 385 386 387 388 389 390 |
/* Find an ideal X position for the popup, directly under the settings
button, based on the size of the popup... */
settingsPopup.show(document.body);
popupSize = settingsPopup.e.getBoundingClientRect();
settingsPopup.hide();
settingsPopup.options.adjustX = function(x){
const rect = settingsButton.getBoundingClientRect();
| < | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
/* Find an ideal X position for the popup, directly under the settings
button, based on the size of the popup... */
settingsPopup.show(document.body);
popupSize = settingsPopup.e.getBoundingClientRect();
settingsPopup.hide();
settingsPopup.options.adjustX = function(x){
const rect = settingsButton.getBoundingClientRect();
return rect.right - popupSize.width;
};
})()/*#chat-settings-button setup*/;
/** Callback for poll() to inject new content into the page. jx ==
the response from /chat-poll. If atEnd is true, the message is
|
| ︙ | ︙ | |||
482 483 484 485 486 487 488 |
Chat.pageTitleOrig;
}
if(jx.msgs.length && F.config.pingTcp){
fetch("http:/"+"/localhost:"+window.fossil.config.pingTcp+"/chat-ping");
}
}/*newcontent()*/;
| | | | | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
Chat.pageTitleOrig;
}
if(jx.msgs.length && F.config.pingTcp){
fetch("http:/"+"/localhost:"+window.fossil.config.pingTcp+"/chat-ping");
}
}/*newcontent()*/;
(function(){
/** Add toolbar for loading older messages. We use a FIELDSET here
because a fieldset is the only parent element type which can
automatically enable/disable its children by
enabling/disabling the parent element. */
const loadLegend = D.legend("Load...");
const toolbar = Chat.e.loadToolbar = D.attr(
D.fieldset(loadLegend), "id", "load-msg-toolbar"
);
Chat.disableDuringAjax.push(toolbar);
/* Loads the next n oldest messages, or all previous history if n is negative. */
const loadOldMessages = function(n){
Chat.ajaxStart();
var gotMessages = false;
fetch("chat-poll?before="+Chat.mnMsg+"&n="+n)
|
| ︙ | ︙ | |||
533 534 535 536 537 538 539 |
D.append(toolbar, wrapper);
var btn = D.button("Previous "+Chat.loadMessageCount+" messages");
D.append(wrapper, btn);
btn.addEventListener('click',()=>loadOldMessages(Chat.loadMessageCount));
btn = D.button("All previous messages");
D.append(wrapper, btn);
btn.addEventListener('click',()=>loadOldMessages(-1));
| | | | | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 |
D.append(toolbar, wrapper);
var btn = D.button("Previous "+Chat.loadMessageCount+" messages");
D.append(wrapper, btn);
btn.addEventListener('click',()=>loadOldMessages(Chat.loadMessageCount));
btn = D.button("All previous messages");
D.append(wrapper, btn);
btn.addEventListener('click',()=>loadOldMessages(-1));
D.append(Chat.e.messagesWrapper, toolbar);
toolbar.disabled = true /*will be enabled when msg load finishes */;
})()/*end history loading widget setup*/;
async function poll(isFirstCall){
if(poll.running) return;
poll.running = true;
if(isFirstCall) Chat.ajaxStart();
var p = fetch("chat-poll?name=" + Chat.mxMsg);
p.then(x=>x.json())
|
| ︙ | ︙ |
Changes to src/default.css.
| ︙ | ︙ | |||
1527 1528 1529 1530 1531 1532 1533 |
justify-content: stretch;
flex-wrap: wrap;
}
body.chat .chat-message-popup > .toolbar > button {
flex: 1 1 auto;
}
| | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 |
justify-content: stretch;
flex-wrap: wrap;
}
body.chat .chat-message-popup > .toolbar > button {
flex: 1 1 auto;
}
body.chat #load-msg-toolbar {
border-radius: 0.25em;
padding: 0.1em 0.2em;
margin-bottom: 1em;
}
body.chat #load-msg-toolbar.all-done {
opacity: 0.5;
}
body.chat #load-msg-toolbar > div {
display: flex;
flex-direction: row;
justify-content: stretch;
flex-wrap: wrap;
}
body.chat #load-msg-toolbar > div > button {
flex: 1 1 auto;
}
.settings-icon {
/* Icon source: https://de.wikipedia.org/wiki/Datei:OOjs_UI_icon_settings.svg
MIT License. */
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0, 0, 24, 24'%3e%3cg id='settings'%3e%3cpath id='gear' d='M3 4h3v2h-3zM12 4h9v2h-9zM8 3h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 11h9v2h-9zM18 11h3v2h-3zM14 10h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 18h6v2h-6zM15 18h6v2h-6zM11 17h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1z'/%3e%3c/g%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: center;
display: inline-block;
min-height: 1em;
max-height: 1em;
min-width: 1em;
max-width: 1em;
margin: 0;
padding: 0.2em/*needed to avoid image truncation*/;
}
body.fossil-dark-style .settings-icon {
filter: invert(100%);
}
body.chat #chat-settings-button {
}
body.chat .chat-settings-popup {
font-size: 0.8em;
text-align: left;
opacity: 0.8;
display: flex;
flex-direction: column;
align-items: stretch;
padding: 0.25em;
}
body.chat #chat-messages-wrapper {
display: flex;
flex-direction: column;
}
body.chat.chat-only-mode{
}
body.chat.chat-only-mode > div.content {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: stretch;
}
body.chat.chat-only-mode #chat-input-area {
/* would like to pin this to the top so that it stays in place when
scrolling, but doing so causes #chat-messages-wrapper to scroll
behind it visibly, which is really ugly. Only current workaround is
to force an opaque background color on this element, but that's not
skin-friendly. */
/*position: fixed;
top: 0;
left: 0;*/
padding: 0.5em 1em;
}
body.chat.chat-only-mode #chat-messages-wrapper {
}
body.chat #chat-input-area {
display: flex;
flex-direction: column;
border-bottom: 1px solid black;
margin-bottom: 0.5em;
}
body.chat #chat-input-line {
display: flex;
flex-direction: row;
margin-bottom: 0.25em;
align-items: center;
}
body.chat #chat-input-line > input[type=submit] {
flex: 1 5 auto;
max-width: 6em;
margin-right: 1em;
}
body.chat #chat-input-line > input[type=text] {
flex: 5 1 auto;
}
body.chat #chat-input-file-area {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: wrap;
}
body.chat #chat-input-file-area > .file-selection-wrapper {
align-self: flex-start;
margin-right: 0.5em;
flex: 0 1 auto;
padding: 0.25em 0.25em 0.25em 0;
}
body.chat #chat-input-file-area .file-selection-wrapper > * {
vertical-align: middle;
margin: 0;
}
body.chat #chat-input-file {
border:1px solid rgba(0,0,0,0);/*avoid UI shift during drop-targeting*/
border-radius: 0.25em;
padding: 0.25em;
}
body.chat #chat-input-file > input {
flex: 1 0 auto;
}
body.chat #chat-input-file.dragover {
border: 1px dashed green;
}
body.chat #chat-drop-details {
flex: 0 1 auto;
padding: 0.5em 1em;
margin-left: 0.5em;
white-space: pre;
font-family: monospace;
max-width: 50%;
}
|