Fossil SCM

Chat: hide message home/end buttons by default in portrait mode and add a menu toggle for them, and swapped the button positions (seems more natural). Minor tweak to the div.content resize algo to make use of CSS calc().

stephan 2020-12-27 17:42 trunk
Commit deb9963ac6daca869b43a48ad266e2514b867de8741ad82e2b0682b0a3225f38
+1 -1
--- src/chat.c
+++ src/chat.c
@@ -120,12 +120,12 @@
120120
@ <input type="text" name="msg" id="chat-input-single" \
121121
@ placeholder="Type message here." autocomplete="off">
122122
@ <textarea rows="8" id="chat-input-multi" \
123123
@ placeholder="Type message here" class="hidden"></textarea>
124124
@ <input type="submit" value="Send" id="chat-message-submit">
125
- @ <button id="chat-scroll-bottom">&darr;</button>
126125
@ <button id="chat-scroll-top">&uarr;</button>
126
+ @ <button id="chat-scroll-bottom">&darr;</button>
127127
@ <span id="chat-settings-button" class="settings-icon" \
128128
@ aria-label="Settings..." aria-haspopup="true" ></span>
129129
@ </div>
130130
@ <div id='chat-input-file-area'>
131131
@ <div class='file-selection-wrapper'>
132132
--- src/chat.c
+++ src/chat.c
@@ -120,12 +120,12 @@
120 @ <input type="text" name="msg" id="chat-input-single" \
121 @ placeholder="Type message here." autocomplete="off">
122 @ <textarea rows="8" id="chat-input-multi" \
123 @ placeholder="Type message here" class="hidden"></textarea>
124 @ <input type="submit" value="Send" id="chat-message-submit">
125 @ <button id="chat-scroll-bottom">&darr;</button>
126 @ <button id="chat-scroll-top">&uarr;</button>
 
127 @ <span id="chat-settings-button" class="settings-icon" \
128 @ aria-label="Settings..." aria-haspopup="true" ></span>
129 @ </div>
130 @ <div id='chat-input-file-area'>
131 @ <div class='file-selection-wrapper'>
132
--- src/chat.c
+++ src/chat.c
@@ -120,12 +120,12 @@
120 @ <input type="text" name="msg" id="chat-input-single" \
121 @ placeholder="Type message here." autocomplete="off">
122 @ <textarea rows="8" id="chat-input-multi" \
123 @ placeholder="Type message here" class="hidden"></textarea>
124 @ <input type="submit" value="Send" id="chat-message-submit">
 
125 @ <button id="chat-scroll-top">&uarr;</button>
126 @ <button id="chat-scroll-bottom">&darr;</button>
127 @ <span id="chat-settings-button" class="settings-icon" \
128 @ aria-label="Settings..." aria-haspopup="true" ></span>
129 @ </div>
130 @ <div id='chat-input-file-area'>
131 @ <div class='file-selection-wrapper'>
132
+22 -4
--- src/chat.js
+++ src/chat.js
@@ -51,18 +51,21 @@
5151
const resized = function(){
5252
const wh = window.innerHeight,
5353
com = bcl.contains('chat-only-mode');
5454
var ht;
5555
if(com){
56
- ht = wh - 10/*fudge value*/;
56
+ ht = wh;
5757
}else{
5858
f.extra = 0;
5959
[f.eHead, f.eMenu, f.eFoot].forEach(f.measure);
60
- ht = wh - f.extra - 10/*fudge value*/;
60
+ ht = wh - f.extra;
6161
}
6262
f.contentArea.style.height =
63
- f.contentArea.style.maxHeight = (ht>=100 ? ht : 100)+"px";
63
+ f.contentArea.style.maxHeight = [
64
+ "calc(", (ht>=100 ? ht : 100), "px",
65
+ " - 1em"/*fudge value*/,")"
66
+ ].join('');
6467
if(false){
6568
console.debug("resized.",wh, f.extra, ht,
6669
window.getComputedStyle(f.contentArea).maxHeight,
6770
f.contentArea);
6871
}
@@ -89,11 +92,13 @@
8992
btnSubmit: E1('#chat-message-submit'),
9093
inputSingle: E1('#chat-input-single'),
9194
inputMulti: E1('#chat-input-multi'),
9295
inputCurrent: undefined/*one of inputSingle or inputMulti*/,
9396
inputFile: E1('#chat-input-file'),
94
- contentDiv: E1('div.content')
97
+ contentDiv: E1('div.content'),
98
+ btnMsgHome: E1('#chat-scroll-top'),
99
+ btnMsgEnd: E1('#chat-scroll-bottom')
95100
},
96101
me: F.user.name,
97102
mxMsg: F.config.chat.initSize ? -F.config.chat.initSize : -50,
98103
mnMsg: undefined/*lowest message ID we've seen so far (for history loading)*/,
99104
pageIsActive: 'visible'===document.visibilityState,
@@ -295,10 +300,18 @@
295300
}
296301
},
297302
toggleChatOnlyMode: function(){
298303
return this.chatOnlyMode(!this.isChatOnlyMode());
299304
},
305
+ /* Turn the message area top/bottom buttons on (yes===true), off
306
+ (yes==false), or toggle them (no arguments). Returns this. */
307
+ toggleNavButtons: function(yes){
308
+ const e = [this.e.btnMsgHome, this.e.btnMsgEnd], c = 'hidden';
309
+ if(0===arguments.length) D.toggleClass(e, c);
310
+ else if(!arguments[0]) D.addClass(e, c);
311
+ else D.removeClass(e, c);
312
+ },
300313
settings:{
301314
get: (k,dflt)=>F.storage.get(k,dflt),
302315
getBool: (k,dflt)=>F.storage.getBool(k,dflt),
303316
set: (k,v)=>F.storage.set(k,v),
304317
defaults:{
@@ -317,10 +330,11 @@
317330
for mobile chat apps but can be difficult to read in wide
318331
windows (desktop/tablet landscape mode), so we default to a
319332
layout based on the apparently "orientation" of the window:
320333
tall vs wide. Can be toggled via settings popup. */
321334
document.body.classList.add('my-messages-right');
335
+ cs.toggleNavButtons(false);
322336
}
323337
if(cs.settings.getBool('monospace-messages',false)){
324338
document.body.classList.add('monospace-messages');
325339
}
326340
cs.e.inputCurrent = cs.e.inputSingle;
@@ -785,10 +799,14 @@
785799
boolValue: ()=>!document.body.classList.contains('my-messages-right'),
786800
callback: function f(){
787801
document.body.classList.toggle('my-messages-right');
788802
}
789803
},{
804
+ label: "Message home/end buttons",
805
+ boolValue: ()=>!Chat.e.btnMsgHome.classList.contains('hidden'),
806
+ callback: ()=>Chat.toggleNavButtons()
807
+ },{
790808
label: "Images inline",
791809
boolValue: ()=>Chat.settings.getBool('images-inline'),
792810
callback: function(){
793811
const v = Chat.settings.getBool('images-inline',true);
794812
Chat.settings.set('images-inline', !v);
795813
--- src/chat.js
+++ src/chat.js
@@ -51,18 +51,21 @@
51 const resized = function(){
52 const wh = window.innerHeight,
53 com = bcl.contains('chat-only-mode');
54 var ht;
55 if(com){
56 ht = wh - 10/*fudge value*/;
57 }else{
58 f.extra = 0;
59 [f.eHead, f.eMenu, f.eFoot].forEach(f.measure);
60 ht = wh - f.extra - 10/*fudge value*/;
61 }
62 f.contentArea.style.height =
63 f.contentArea.style.maxHeight = (ht>=100 ? ht : 100)+"px";
 
 
 
64 if(false){
65 console.debug("resized.",wh, f.extra, ht,
66 window.getComputedStyle(f.contentArea).maxHeight,
67 f.contentArea);
68 }
@@ -89,11 +92,13 @@
89 btnSubmit: E1('#chat-message-submit'),
90 inputSingle: E1('#chat-input-single'),
91 inputMulti: E1('#chat-input-multi'),
92 inputCurrent: undefined/*one of inputSingle or inputMulti*/,
93 inputFile: E1('#chat-input-file'),
94 contentDiv: E1('div.content')
 
 
95 },
96 me: F.user.name,
97 mxMsg: F.config.chat.initSize ? -F.config.chat.initSize : -50,
98 mnMsg: undefined/*lowest message ID we've seen so far (for history loading)*/,
99 pageIsActive: 'visible'===document.visibilityState,
@@ -295,10 +300,18 @@
295 }
296 },
297 toggleChatOnlyMode: function(){
298 return this.chatOnlyMode(!this.isChatOnlyMode());
299 },
 
 
 
 
 
 
 
 
300 settings:{
301 get: (k,dflt)=>F.storage.get(k,dflt),
302 getBool: (k,dflt)=>F.storage.getBool(k,dflt),
303 set: (k,v)=>F.storage.set(k,v),
304 defaults:{
@@ -317,10 +330,11 @@
317 for mobile chat apps but can be difficult to read in wide
318 windows (desktop/tablet landscape mode), so we default to a
319 layout based on the apparently "orientation" of the window:
320 tall vs wide. Can be toggled via settings popup. */
321 document.body.classList.add('my-messages-right');
 
322 }
323 if(cs.settings.getBool('monospace-messages',false)){
324 document.body.classList.add('monospace-messages');
325 }
326 cs.e.inputCurrent = cs.e.inputSingle;
@@ -785,10 +799,14 @@
785 boolValue: ()=>!document.body.classList.contains('my-messages-right'),
786 callback: function f(){
787 document.body.classList.toggle('my-messages-right');
788 }
789 },{
 
 
 
 
790 label: "Images inline",
791 boolValue: ()=>Chat.settings.getBool('images-inline'),
792 callback: function(){
793 const v = Chat.settings.getBool('images-inline',true);
794 Chat.settings.set('images-inline', !v);
795
--- src/chat.js
+++ src/chat.js
@@ -51,18 +51,21 @@
51 const resized = function(){
52 const wh = window.innerHeight,
53 com = bcl.contains('chat-only-mode');
54 var ht;
55 if(com){
56 ht = wh;
57 }else{
58 f.extra = 0;
59 [f.eHead, f.eMenu, f.eFoot].forEach(f.measure);
60 ht = wh - f.extra;
61 }
62 f.contentArea.style.height =
63 f.contentArea.style.maxHeight = [
64 "calc(", (ht>=100 ? ht : 100), "px",
65 " - 1em"/*fudge value*/,")"
66 ].join('');
67 if(false){
68 console.debug("resized.",wh, f.extra, ht,
69 window.getComputedStyle(f.contentArea).maxHeight,
70 f.contentArea);
71 }
@@ -89,11 +92,13 @@
92 btnSubmit: E1('#chat-message-submit'),
93 inputSingle: E1('#chat-input-single'),
94 inputMulti: E1('#chat-input-multi'),
95 inputCurrent: undefined/*one of inputSingle or inputMulti*/,
96 inputFile: E1('#chat-input-file'),
97 contentDiv: E1('div.content'),
98 btnMsgHome: E1('#chat-scroll-top'),
99 btnMsgEnd: E1('#chat-scroll-bottom')
100 },
101 me: F.user.name,
102 mxMsg: F.config.chat.initSize ? -F.config.chat.initSize : -50,
103 mnMsg: undefined/*lowest message ID we've seen so far (for history loading)*/,
104 pageIsActive: 'visible'===document.visibilityState,
@@ -295,10 +300,18 @@
300 }
301 },
302 toggleChatOnlyMode: function(){
303 return this.chatOnlyMode(!this.isChatOnlyMode());
304 },
305 /* Turn the message area top/bottom buttons on (yes===true), off
306 (yes==false), or toggle them (no arguments). Returns this. */
307 toggleNavButtons: function(yes){
308 const e = [this.e.btnMsgHome, this.e.btnMsgEnd], c = 'hidden';
309 if(0===arguments.length) D.toggleClass(e, c);
310 else if(!arguments[0]) D.addClass(e, c);
311 else D.removeClass(e, c);
312 },
313 settings:{
314 get: (k,dflt)=>F.storage.get(k,dflt),
315 getBool: (k,dflt)=>F.storage.getBool(k,dflt),
316 set: (k,v)=>F.storage.set(k,v),
317 defaults:{
@@ -317,10 +330,11 @@
330 for mobile chat apps but can be difficult to read in wide
331 windows (desktop/tablet landscape mode), so we default to a
332 layout based on the apparently "orientation" of the window:
333 tall vs wide. Can be toggled via settings popup. */
334 document.body.classList.add('my-messages-right');
335 cs.toggleNavButtons(false);
336 }
337 if(cs.settings.getBool('monospace-messages',false)){
338 document.body.classList.add('monospace-messages');
339 }
340 cs.e.inputCurrent = cs.e.inputSingle;
@@ -785,10 +799,14 @@
799 boolValue: ()=>!document.body.classList.contains('my-messages-right'),
800 callback: function f(){
801 document.body.classList.toggle('my-messages-right');
802 }
803 },{
804 label: "Message home/end buttons",
805 boolValue: ()=>!Chat.e.btnMsgHome.classList.contains('hidden'),
806 callback: ()=>Chat.toggleNavButtons()
807 },{
808 label: "Images inline",
809 boolValue: ()=>Chat.settings.getBool('images-inline'),
810 callback: function(){
811 const v = Chat.settings.getBool('images-inline',true);
812 Chat.settings.set('images-inline', !v);
813
+4 -1
--- src/default.css
+++ src/default.css
@@ -1615,17 +1615,19 @@
16151615
vertical-align: middle;
16161616
}
16171617
body.chat .chat-settings-popup > span.menu-entry{
16181618
white-space: nowrap;
16191619
cursor: pointer;
1620
- border: 1px outset;
1620
+ border: 1px solid;
16211621
border-radius: 0.25em;
16221622
padding: 0.25em 0.5em;
16231623
display: flex;
16241624
flex-direction: row;
16251625
align-items: center;
16261626
justify-content: space-between;
1627
+}
1628
+body.chat .chat-settings-popup > span.menu-entry:hover {
16271629
}
16281630
body.chat .chat-settings-popup > span.menu-entry > .help-buttonlet {
16291631
vertical-align: middle;
16301632
}
16311633
body.chat .chat-settings-popup > span.menu-entry > span.button {
@@ -1696,10 +1698,11 @@
16961698
body.chat #chat-input-line > button {
16971699
max-width: 4em;
16981700
}
16991701
body.chat #chat-input-line > #chat-settings-button{
17001702
margin: 0 0 0 0.25em;
1703
+ max-width: 2em;
17011704
}
17021705
body.chat #chat-input-line > input[type=text],
17031706
body.chat #chat-input-line > textarea {
17041707
flex: 5 1 auto;
17051708
}
17061709
--- src/default.css
+++ src/default.css
@@ -1615,17 +1615,19 @@
1615 vertical-align: middle;
1616 }
1617 body.chat .chat-settings-popup > span.menu-entry{
1618 white-space: nowrap;
1619 cursor: pointer;
1620 border: 1px outset;
1621 border-radius: 0.25em;
1622 padding: 0.25em 0.5em;
1623 display: flex;
1624 flex-direction: row;
1625 align-items: center;
1626 justify-content: space-between;
 
 
1627 }
1628 body.chat .chat-settings-popup > span.menu-entry > .help-buttonlet {
1629 vertical-align: middle;
1630 }
1631 body.chat .chat-settings-popup > span.menu-entry > span.button {
@@ -1696,10 +1698,11 @@
1696 body.chat #chat-input-line > button {
1697 max-width: 4em;
1698 }
1699 body.chat #chat-input-line > #chat-settings-button{
1700 margin: 0 0 0 0.25em;
 
1701 }
1702 body.chat #chat-input-line > input[type=text],
1703 body.chat #chat-input-line > textarea {
1704 flex: 5 1 auto;
1705 }
1706
--- src/default.css
+++ src/default.css
@@ -1615,17 +1615,19 @@
1615 vertical-align: middle;
1616 }
1617 body.chat .chat-settings-popup > span.menu-entry{
1618 white-space: nowrap;
1619 cursor: pointer;
1620 border: 1px solid;
1621 border-radius: 0.25em;
1622 padding: 0.25em 0.5em;
1623 display: flex;
1624 flex-direction: row;
1625 align-items: center;
1626 justify-content: space-between;
1627 }
1628 body.chat .chat-settings-popup > span.menu-entry:hover {
1629 }
1630 body.chat .chat-settings-popup > span.menu-entry > .help-buttonlet {
1631 vertical-align: middle;
1632 }
1633 body.chat .chat-settings-popup > span.menu-entry > span.button {
@@ -1696,10 +1698,11 @@
1698 body.chat #chat-input-line > button {
1699 max-width: 4em;
1700 }
1701 body.chat #chat-input-line > #chat-settings-button{
1702 margin: 0 0 0 0.25em;
1703 max-width: 2em;
1704 }
1705 body.chat #chat-input-line > input[type=text],
1706 body.chat #chat-input-line > textarea {
1707 flex: 5 1 auto;
1708 }
1709
--- src/fossil.dom.js
+++ src/fossil.dom.js
@@ -630,12 +630,12 @@
630630
631631
/**
632632
"Blinks" the given element a single time for the given number of
633633
milliseconds, defaulting (if the 2nd argument is falsy or not a
634634
number) to flashOnce.defaultTimeMs. If a 3rd argument is passed
635
- in, it must be a function, and it gets callback back at the end
636
- of the asynchronous flashing processes.
635
+ in, it must be a function, and it gets called at the end of the
636
+ asynchronous flashing processes.
637637
638638
This will only activate once per element during that timeframe -
639639
further calls will become no-ops until the blink is
640640
completed. This routine adds a dataset member to the element for
641641
the duration of the blink, to allow it to block multiple blinks.
642642
--- src/fossil.dom.js
+++ src/fossil.dom.js
@@ -630,12 +630,12 @@
630
631 /**
632 "Blinks" the given element a single time for the given number of
633 milliseconds, defaulting (if the 2nd argument is falsy or not a
634 number) to flashOnce.defaultTimeMs. If a 3rd argument is passed
635 in, it must be a function, and it gets callback back at the end
636 of the asynchronous flashing processes.
637
638 This will only activate once per element during that timeframe -
639 further calls will become no-ops until the blink is
640 completed. This routine adds a dataset member to the element for
641 the duration of the blink, to allow it to block multiple blinks.
642
--- src/fossil.dom.js
+++ src/fossil.dom.js
@@ -630,12 +630,12 @@
630
631 /**
632 "Blinks" the given element a single time for the given number of
633 milliseconds, defaulting (if the 2nd argument is falsy or not a
634 number) to flashOnce.defaultTimeMs. If a 3rd argument is passed
635 in, it must be a function, and it gets called at the end of the
636 asynchronous flashing processes.
637
638 This will only activate once per element during that timeframe -
639 further calls will become no-ops until the blink is
640 completed. This routine adds a dataset member to the element for
641 the duration of the blink, to allow it to block multiple blinks.
642

Keyboard Shortcuts

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