Fossil SCM
Initial go at a "bottom-up" (mobile-like) layout for chat, but it is only active in chat-only mode where we have more control over the layout. The default mode works like before, top-down. There are still minor usability/scrolling issues left to resolve but it seems to essentially work.
Commit
cffd66ffe9ed970d831383df282397ace7b61addade191e076ae4eb098658893
Parent
ca42098af0af041…
2 files changed
+78
-48
+28
-23
+78
-48
| --- src/chat.js | ||
| +++ src/chat.js | ||
| @@ -7,10 +7,11 @@ | ||
| 7 | 7 | const E1 = function(selector){ |
| 8 | 8 | const e = document.querySelector(selector); |
| 9 | 9 | if(!e) throw new Error("missing required DOM element: "+selector); |
| 10 | 10 | return e; |
| 11 | 11 | }; |
| 12 | + //document.body.classList.add('chat-only-mode'); | |
| 12 | 13 | const Chat = (function(){ |
| 13 | 14 | const cs = { |
| 14 | 15 | e:{/*map of certain DOM elements.*/ |
| 15 | 16 | messageInjectPoint: E1('#message-inject-point'), |
| 16 | 17 | pageTitle: E1('head title'), |
| @@ -112,17 +113,60 @@ | ||
| 112 | 113 | injectMessageElem: function f(e, atEnd){ |
| 113 | 114 | const mip = atEnd ? this.e.loadToolbar : this.e.messageInjectPoint; |
| 114 | 115 | if(atEnd){ |
| 115 | 116 | mip.parentNode.insertBefore(e, mip); |
| 116 | 117 | }else{ |
| 117 | - if(mip.nextSibling){ | |
| 118 | - mip.parentNode.insertBefore(e, mip.nextSibling); | |
| 118 | + if(mip.nextSibling) mip.parentNode.insertBefore(e, mip.nextSibling); | |
| 119 | + else mip.parentNode.appendChild(e); | |
| 120 | + if(this.isChatOnlyMode()){ | |
| 121 | + e.scrollIntoView(); | |
| 119 | 122 | }else{ |
| 120 | - mip.parentNode.appendChild(e); | |
| 123 | + //const rect = e.getBoundingClientRect(); | |
| 124 | + //const rect = this.e.inputWrapper.getBoundingClientRect(); | |
| 125 | + //window.scrollBy(0, -cs.height); | |
| 126 | + //console.debug("rect =",rect); | |
| 127 | + //window.scrollBy(0,rect.height); | |
| 128 | + //window.scrollTo(0,rect.top); | |
| 129 | + //e.querySelector('.message-widget-tab').scrollIntoView(); | |
| 121 | 130 | } |
| 122 | 131 | } |
| 123 | 132 | }, |
| 133 | + isChatOnlyMode: function(){ | |
| 134 | + return document.body.classList.contains('chat-only-mode'); | |
| 135 | + }, | |
| 136 | + chatOnlyMode: function f(yes){ | |
| 137 | + if(undefined === f.elemsToToggle){ | |
| 138 | + f.elemsToToggle = []; | |
| 139 | + document.body.childNodes.forEach(function(e){ | |
| 140 | + if(!e.classList) return/*TEXT nodes and such*/; | |
| 141 | + else if(!e.classList.contains('content') | |
| 142 | + && !e.classList.contains('fossil-PopupWidget') | |
| 143 | + /*kludge^^^ for settingsPopup click handling!*/){ | |
| 144 | + f.elemsToToggle.push(e); | |
| 145 | + } | |
| 146 | + }); | |
| 147 | + } | |
| 148 | + if(!arguments.length) yes = true; | |
| 149 | + if(yes === this.isChatOnlyMode()) return this; | |
| 150 | + if(yes){ | |
| 151 | + D.addClass(f.elemsToToggle, 'hidden'); | |
| 152 | + D.addClass(document.body, 'chat-only-mode'); | |
| 153 | + document.body.scroll(0,document.body.height); | |
| 154 | + }else{ | |
| 155 | + D.removeClass(f.elemsToToggle, 'hidden'); | |
| 156 | + D.removeClass(document.body, 'chat-only-mode'); | |
| 157 | + setTimeout(()=>document.body.scrollIntoView( | |
| 158 | + /*moves to (0,0), whereas scrollTo(0,0) does not!*/ | |
| 159 | + ), 0); | |
| 160 | + } | |
| 161 | + const msg = document.querySelector('.message-widget'); | |
| 162 | + if(msg) msg.scrollIntoView(); | |
| 163 | + return this; | |
| 164 | + }, | |
| 165 | + toggleChatOnlyMode: function(){ | |
| 166 | + return this.chatOnlyMode(!this.isChatOnlyMode()); | |
| 167 | + }, | |
| 124 | 168 | settings:{ |
| 125 | 169 | get: (k,dflt)=>F.storage.get(k,dflt), |
| 126 | 170 | getBool: (k,dflt)=>F.storage.getBool(k,dflt), |
| 127 | 171 | set: (k,v)=>F.storage.set(k,v), |
| 128 | 172 | defaults:{ |
| @@ -145,10 +189,28 @@ | ||
| 145 | 189 | if(cs.settings.getBool('monospace-messages',false)){ |
| 146 | 190 | document.body.classList.add('monospace-messages'); |
| 147 | 191 | } |
| 148 | 192 | cs.e.inputCurrent = cs.e.inputSingle; |
| 149 | 193 | cs.pageTitleOrig = cs.e.pageTitle.innerText; |
| 194 | + | |
| 195 | + if(true){ | |
| 196 | + /* In order to make the input area opaque, such that the message | |
| 197 | + list scrolls under it without being visible, we have to | |
| 198 | + ensure that the input area has a non-transparent background | |
| 199 | + color. Ideally we'd select the color of div.content, but that | |
| 200 | + is not necessarily set, so we fall back to using the body's | |
| 201 | + background color and hope it's been explicitly set | |
| 202 | + somewhere. If we rely on the input area having its own color | |
| 203 | + specified in CSS then all skins would have to define an | |
| 204 | + appropriate color. Thus our selection of the body color, | |
| 205 | + while slightly unfortunate, is in the interest of keeping | |
| 206 | + skins from being forced to define an opaque bg color. | |
| 207 | + */ | |
| 208 | + const bodyStyle = window.getComputedStyle(document.body); | |
| 209 | + cs.e.inputWrapper.style.backgroundColor = bodyStyle.backgroundColor; | |
| 210 | + } | |
| 211 | + | |
| 150 | 212 | const qs = (e)=>document.querySelector(e); |
| 151 | 213 | const argsToArray = function(args){ |
| 152 | 214 | return Array.prototype.slice.call(args,0); |
| 153 | 215 | }; |
| 154 | 216 | cs.reportError = function(/*msg args*/){ |
| @@ -517,15 +579,11 @@ | ||
| 517 | 579 | |
| 518 | 580 | (function(){/*Set up #chat-settings-button */ |
| 519 | 581 | const settingsButton = document.querySelector('#chat-settings-button'); |
| 520 | 582 | var popupSize = undefined/*placement workaround*/; |
| 521 | 583 | const settingsPopup = new F.PopupWidget({ |
| 522 | - cssClass: ['fossil-tooltip', 'chat-settings-popup'], | |
| 523 | - adjustY: function(y){ | |
| 524 | - const rect = settingsButton.getBoundingClientRect(); | |
| 525 | - return rect.top + rect.height + 2; | |
| 526 | - } | |
| 584 | + cssClass: ['fossil-tooltip', 'chat-settings-popup'] | |
| 527 | 585 | }); |
| 528 | 586 | /* Settings menu entries... */ |
| 529 | 587 | const settingsOps = [{ |
| 530 | 588 | label: "Multi-line input", |
| 531 | 589 | boolValue: ()=>Chat.inputElement()===Chat.e.inputMulti, |
| @@ -540,49 +598,13 @@ | ||
| 540 | 598 | Chat.settings.set('monospace-messages', |
| 541 | 599 | document.body.classList.contains('monospace-messages')); |
| 542 | 600 | } |
| 543 | 601 | },{ |
| 544 | 602 | label: "Chat-only mode", |
| 545 | - boolValue: ()=>!!document.body.classList.contains('chat-only-mode'), | |
| 546 | - callback: function f(){ | |
| 547 | - if(undefined === f.isHidden){ | |
| 548 | - f.isHidden = false; | |
| 549 | - f.elemsToToggle = []; | |
| 550 | - document.body.childNodes.forEach(function(e){ | |
| 551 | - if(!e.classList) return/*TEXT nodes and such*/; | |
| 552 | - else if(!e.classList.contains('content') | |
| 553 | - && !e.classList.contains('fossil-PopupWidget') | |
| 554 | - /*kludge^^^ for settingsPopup click handling!*/){ | |
| 555 | - f.elemsToToggle.push(e); | |
| 556 | - } | |
| 557 | - }); | |
| 558 | - /* In order to make the input area opaque, such that the | |
| 559 | - message list scrolls under it without being visible, we | |
| 560 | - have to ensure that the input area has a non-inherited | |
| 561 | - background color. Ideally we'd select the color of | |
| 562 | - div.content, but that is not necessarily set, so we fall | |
| 563 | - back to using the body's background color. If we rely on | |
| 564 | - the input area having its own color specified in CSS then | |
| 565 | - all skins would have to define an appropriate color. | |
| 566 | - Thus our selection of the body color, while slightly unfortunate, | |
| 567 | - is in the interest of keeping skins from being forced to | |
| 568 | - define an opaque bg color. | |
| 569 | - */ | |
| 570 | - f.initialBg = Chat.e.messagesWrapper.style.backgroundColor; | |
| 571 | - const cs = window.getComputedStyle(document.body); | |
| 572 | - f.inheritedBg = cs.backgroundColor; | |
| 573 | - } | |
| 574 | - const iws = Chat.e.inputWrapper.style; | |
| 575 | - if((f.isHidden = !f.isHidden)){ | |
| 576 | - D.addClass(f.elemsToToggle, 'hidden'); | |
| 577 | - D.addClass(document.body, 'chat-only-mode'); | |
| 578 | - iws.backgroundColor = f.inheritedBg; | |
| 579 | - }else{ | |
| 580 | - D.removeClass(f.elemsToToggle, 'hidden'); | |
| 581 | - D.removeClass(document.body, 'chat-only-mode'); | |
| 582 | - iws.backgroundColor = f.initialBg; | |
| 583 | - } | |
| 603 | + boolValue: ()=>Chat.isChatOnlyMode(), | |
| 604 | + callback: function(){ | |
| 605 | + Chat.toggleChatOnlyMode(); | |
| 584 | 606 | } |
| 585 | 607 | },{ |
| 586 | 608 | label: "Left-align my posts", |
| 587 | 609 | boolValue: ()=>!document.body.classList.contains('my-messages-right'), |
| 588 | 610 | callback: function f(){ |
| @@ -635,18 +657,26 @@ | ||
| 635 | 657 | else settingsPopup.show(settingsButton); |
| 636 | 658 | /* Reminder: we cannot toggle the visibility from her |
| 637 | 659 | */ |
| 638 | 660 | }, false); |
| 639 | 661 | |
| 640 | - /* Find an ideal X position for the popup, directly under the settings | |
| 662 | + /* Find an ideal X/Y position for the popup, directly above the settings | |
| 641 | 663 | button, based on the size of the popup... */ |
| 642 | 664 | settingsPopup.show(document.body); |
| 643 | 665 | popupSize = settingsPopup.e.getBoundingClientRect(); |
| 644 | 666 | settingsPopup.hide(); |
| 645 | 667 | settingsPopup.options.adjustX = function(x){ |
| 646 | 668 | const rect = settingsButton.getBoundingClientRect(); |
| 647 | 669 | return rect.right - popupSize.width; |
| 670 | + }; | |
| 671 | + settingsPopup.options.adjustY = function(y){ | |
| 672 | + const rect = settingsButton.getBoundingClientRect(); | |
| 673 | + if(Chat.isChatOnlyMode()){ | |
| 674 | + return rect.top - popupSize.height -2; | |
| 675 | + }else{ | |
| 676 | + return rect.bottom + 2; | |
| 677 | + } | |
| 648 | 678 | }; |
| 649 | 679 | })()/*#chat-settings-button setup*/; |
| 650 | 680 | |
| 651 | 681 | |
| 652 | 682 | /** Callback for poll() to inject new content into the page. jx == |
| 653 | 683 |
| --- src/chat.js | |
| +++ src/chat.js | |
| @@ -7,10 +7,11 @@ | |
| 7 | const E1 = function(selector){ |
| 8 | const e = document.querySelector(selector); |
| 9 | if(!e) throw new Error("missing required DOM element: "+selector); |
| 10 | return e; |
| 11 | }; |
| 12 | const Chat = (function(){ |
| 13 | const cs = { |
| 14 | e:{/*map of certain DOM elements.*/ |
| 15 | messageInjectPoint: E1('#message-inject-point'), |
| 16 | pageTitle: E1('head title'), |
| @@ -112,17 +113,60 @@ | |
| 112 | injectMessageElem: function f(e, atEnd){ |
| 113 | const mip = atEnd ? this.e.loadToolbar : this.e.messageInjectPoint; |
| 114 | if(atEnd){ |
| 115 | mip.parentNode.insertBefore(e, mip); |
| 116 | }else{ |
| 117 | if(mip.nextSibling){ |
| 118 | mip.parentNode.insertBefore(e, mip.nextSibling); |
| 119 | }else{ |
| 120 | mip.parentNode.appendChild(e); |
| 121 | } |
| 122 | } |
| 123 | }, |
| 124 | settings:{ |
| 125 | get: (k,dflt)=>F.storage.get(k,dflt), |
| 126 | getBool: (k,dflt)=>F.storage.getBool(k,dflt), |
| 127 | set: (k,v)=>F.storage.set(k,v), |
| 128 | defaults:{ |
| @@ -145,10 +189,28 @@ | |
| 145 | if(cs.settings.getBool('monospace-messages',false)){ |
| 146 | document.body.classList.add('monospace-messages'); |
| 147 | } |
| 148 | cs.e.inputCurrent = cs.e.inputSingle; |
| 149 | cs.pageTitleOrig = cs.e.pageTitle.innerText; |
| 150 | const qs = (e)=>document.querySelector(e); |
| 151 | const argsToArray = function(args){ |
| 152 | return Array.prototype.slice.call(args,0); |
| 153 | }; |
| 154 | cs.reportError = function(/*msg args*/){ |
| @@ -517,15 +579,11 @@ | |
| 517 | |
| 518 | (function(){/*Set up #chat-settings-button */ |
| 519 | const settingsButton = document.querySelector('#chat-settings-button'); |
| 520 | var popupSize = undefined/*placement workaround*/; |
| 521 | const settingsPopup = new F.PopupWidget({ |
| 522 | cssClass: ['fossil-tooltip', 'chat-settings-popup'], |
| 523 | adjustY: function(y){ |
| 524 | const rect = settingsButton.getBoundingClientRect(); |
| 525 | return rect.top + rect.height + 2; |
| 526 | } |
| 527 | }); |
| 528 | /* Settings menu entries... */ |
| 529 | const settingsOps = [{ |
| 530 | label: "Multi-line input", |
| 531 | boolValue: ()=>Chat.inputElement()===Chat.e.inputMulti, |
| @@ -540,49 +598,13 @@ | |
| 540 | Chat.settings.set('monospace-messages', |
| 541 | document.body.classList.contains('monospace-messages')); |
| 542 | } |
| 543 | },{ |
| 544 | label: "Chat-only mode", |
| 545 | boolValue: ()=>!!document.body.classList.contains('chat-only-mode'), |
| 546 | callback: function f(){ |
| 547 | if(undefined === f.isHidden){ |
| 548 | f.isHidden = false; |
| 549 | f.elemsToToggle = []; |
| 550 | document.body.childNodes.forEach(function(e){ |
| 551 | if(!e.classList) return/*TEXT nodes and such*/; |
| 552 | else if(!e.classList.contains('content') |
| 553 | && !e.classList.contains('fossil-PopupWidget') |
| 554 | /*kludge^^^ for settingsPopup click handling!*/){ |
| 555 | f.elemsToToggle.push(e); |
| 556 | } |
| 557 | }); |
| 558 | /* In order to make the input area opaque, such that the |
| 559 | message list scrolls under it without being visible, we |
| 560 | have to ensure that the input area has a non-inherited |
| 561 | background color. Ideally we'd select the color of |
| 562 | div.content, but that is not necessarily set, so we fall |
| 563 | back to using the body's background color. If we rely on |
| 564 | the input area having its own color specified in CSS then |
| 565 | all skins would have to define an appropriate color. |
| 566 | Thus our selection of the body color, while slightly unfortunate, |
| 567 | is in the interest of keeping skins from being forced to |
| 568 | define an opaque bg color. |
| 569 | */ |
| 570 | f.initialBg = Chat.e.messagesWrapper.style.backgroundColor; |
| 571 | const cs = window.getComputedStyle(document.body); |
| 572 | f.inheritedBg = cs.backgroundColor; |
| 573 | } |
| 574 | const iws = Chat.e.inputWrapper.style; |
| 575 | if((f.isHidden = !f.isHidden)){ |
| 576 | D.addClass(f.elemsToToggle, 'hidden'); |
| 577 | D.addClass(document.body, 'chat-only-mode'); |
| 578 | iws.backgroundColor = f.inheritedBg; |
| 579 | }else{ |
| 580 | D.removeClass(f.elemsToToggle, 'hidden'); |
| 581 | D.removeClass(document.body, 'chat-only-mode'); |
| 582 | iws.backgroundColor = f.initialBg; |
| 583 | } |
| 584 | } |
| 585 | },{ |
| 586 | label: "Left-align my posts", |
| 587 | boolValue: ()=>!document.body.classList.contains('my-messages-right'), |
| 588 | callback: function f(){ |
| @@ -635,18 +657,26 @@ | |
| 635 | else settingsPopup.show(settingsButton); |
| 636 | /* Reminder: we cannot toggle the visibility from her |
| 637 | */ |
| 638 | }, false); |
| 639 | |
| 640 | /* Find an ideal X position for the popup, directly under the settings |
| 641 | button, based on the size of the popup... */ |
| 642 | settingsPopup.show(document.body); |
| 643 | popupSize = settingsPopup.e.getBoundingClientRect(); |
| 644 | settingsPopup.hide(); |
| 645 | settingsPopup.options.adjustX = function(x){ |
| 646 | const rect = settingsButton.getBoundingClientRect(); |
| 647 | return rect.right - popupSize.width; |
| 648 | }; |
| 649 | })()/*#chat-settings-button setup*/; |
| 650 | |
| 651 | |
| 652 | /** Callback for poll() to inject new content into the page. jx == |
| 653 |
| --- src/chat.js | |
| +++ src/chat.js | |
| @@ -7,10 +7,11 @@ | |
| 7 | const E1 = function(selector){ |
| 8 | const e = document.querySelector(selector); |
| 9 | if(!e) throw new Error("missing required DOM element: "+selector); |
| 10 | return e; |
| 11 | }; |
| 12 | //document.body.classList.add('chat-only-mode'); |
| 13 | const Chat = (function(){ |
| 14 | const cs = { |
| 15 | e:{/*map of certain DOM elements.*/ |
| 16 | messageInjectPoint: E1('#message-inject-point'), |
| 17 | pageTitle: E1('head title'), |
| @@ -112,17 +113,60 @@ | |
| 113 | injectMessageElem: function f(e, atEnd){ |
| 114 | const mip = atEnd ? this.e.loadToolbar : this.e.messageInjectPoint; |
| 115 | if(atEnd){ |
| 116 | mip.parentNode.insertBefore(e, mip); |
| 117 | }else{ |
| 118 | if(mip.nextSibling) mip.parentNode.insertBefore(e, mip.nextSibling); |
| 119 | else mip.parentNode.appendChild(e); |
| 120 | if(this.isChatOnlyMode()){ |
| 121 | e.scrollIntoView(); |
| 122 | }else{ |
| 123 | //const rect = e.getBoundingClientRect(); |
| 124 | //const rect = this.e.inputWrapper.getBoundingClientRect(); |
| 125 | //window.scrollBy(0, -cs.height); |
| 126 | //console.debug("rect =",rect); |
| 127 | //window.scrollBy(0,rect.height); |
| 128 | //window.scrollTo(0,rect.top); |
| 129 | //e.querySelector('.message-widget-tab').scrollIntoView(); |
| 130 | } |
| 131 | } |
| 132 | }, |
| 133 | isChatOnlyMode: function(){ |
| 134 | return document.body.classList.contains('chat-only-mode'); |
| 135 | }, |
| 136 | chatOnlyMode: function f(yes){ |
| 137 | if(undefined === f.elemsToToggle){ |
| 138 | f.elemsToToggle = []; |
| 139 | document.body.childNodes.forEach(function(e){ |
| 140 | if(!e.classList) return/*TEXT nodes and such*/; |
| 141 | else if(!e.classList.contains('content') |
| 142 | && !e.classList.contains('fossil-PopupWidget') |
| 143 | /*kludge^^^ for settingsPopup click handling!*/){ |
| 144 | f.elemsToToggle.push(e); |
| 145 | } |
| 146 | }); |
| 147 | } |
| 148 | if(!arguments.length) yes = true; |
| 149 | if(yes === this.isChatOnlyMode()) return this; |
| 150 | if(yes){ |
| 151 | D.addClass(f.elemsToToggle, 'hidden'); |
| 152 | D.addClass(document.body, 'chat-only-mode'); |
| 153 | document.body.scroll(0,document.body.height); |
| 154 | }else{ |
| 155 | D.removeClass(f.elemsToToggle, 'hidden'); |
| 156 | D.removeClass(document.body, 'chat-only-mode'); |
| 157 | setTimeout(()=>document.body.scrollIntoView( |
| 158 | /*moves to (0,0), whereas scrollTo(0,0) does not!*/ |
| 159 | ), 0); |
| 160 | } |
| 161 | const msg = document.querySelector('.message-widget'); |
| 162 | if(msg) msg.scrollIntoView(); |
| 163 | return this; |
| 164 | }, |
| 165 | toggleChatOnlyMode: function(){ |
| 166 | return this.chatOnlyMode(!this.isChatOnlyMode()); |
| 167 | }, |
| 168 | settings:{ |
| 169 | get: (k,dflt)=>F.storage.get(k,dflt), |
| 170 | getBool: (k,dflt)=>F.storage.getBool(k,dflt), |
| 171 | set: (k,v)=>F.storage.set(k,v), |
| 172 | defaults:{ |
| @@ -145,10 +189,28 @@ | |
| 189 | if(cs.settings.getBool('monospace-messages',false)){ |
| 190 | document.body.classList.add('monospace-messages'); |
| 191 | } |
| 192 | cs.e.inputCurrent = cs.e.inputSingle; |
| 193 | cs.pageTitleOrig = cs.e.pageTitle.innerText; |
| 194 | |
| 195 | if(true){ |
| 196 | /* In order to make the input area opaque, such that the message |
| 197 | list scrolls under it without being visible, we have to |
| 198 | ensure that the input area has a non-transparent background |
| 199 | color. Ideally we'd select the color of div.content, but that |
| 200 | is not necessarily set, so we fall back to using the body's |
| 201 | background color and hope it's been explicitly set |
| 202 | somewhere. If we rely on the input area having its own color |
| 203 | specified in CSS then all skins would have to define an |
| 204 | appropriate color. Thus our selection of the body color, |
| 205 | while slightly unfortunate, is in the interest of keeping |
| 206 | skins from being forced to define an opaque bg color. |
| 207 | */ |
| 208 | const bodyStyle = window.getComputedStyle(document.body); |
| 209 | cs.e.inputWrapper.style.backgroundColor = bodyStyle.backgroundColor; |
| 210 | } |
| 211 | |
| 212 | const qs = (e)=>document.querySelector(e); |
| 213 | const argsToArray = function(args){ |
| 214 | return Array.prototype.slice.call(args,0); |
| 215 | }; |
| 216 | cs.reportError = function(/*msg args*/){ |
| @@ -517,15 +579,11 @@ | |
| 579 | |
| 580 | (function(){/*Set up #chat-settings-button */ |
| 581 | const settingsButton = document.querySelector('#chat-settings-button'); |
| 582 | var popupSize = undefined/*placement workaround*/; |
| 583 | const settingsPopup = new F.PopupWidget({ |
| 584 | cssClass: ['fossil-tooltip', 'chat-settings-popup'] |
| 585 | }); |
| 586 | /* Settings menu entries... */ |
| 587 | const settingsOps = [{ |
| 588 | label: "Multi-line input", |
| 589 | boolValue: ()=>Chat.inputElement()===Chat.e.inputMulti, |
| @@ -540,49 +598,13 @@ | |
| 598 | Chat.settings.set('monospace-messages', |
| 599 | document.body.classList.contains('monospace-messages')); |
| 600 | } |
| 601 | },{ |
| 602 | label: "Chat-only mode", |
| 603 | boolValue: ()=>Chat.isChatOnlyMode(), |
| 604 | callback: function(){ |
| 605 | Chat.toggleChatOnlyMode(); |
| 606 | } |
| 607 | },{ |
| 608 | label: "Left-align my posts", |
| 609 | boolValue: ()=>!document.body.classList.contains('my-messages-right'), |
| 610 | callback: function f(){ |
| @@ -635,18 +657,26 @@ | |
| 657 | else settingsPopup.show(settingsButton); |
| 658 | /* Reminder: we cannot toggle the visibility from her |
| 659 | */ |
| 660 | }, false); |
| 661 | |
| 662 | /* Find an ideal X/Y position for the popup, directly above the settings |
| 663 | button, based on the size of the popup... */ |
| 664 | settingsPopup.show(document.body); |
| 665 | popupSize = settingsPopup.e.getBoundingClientRect(); |
| 666 | settingsPopup.hide(); |
| 667 | settingsPopup.options.adjustX = function(x){ |
| 668 | const rect = settingsButton.getBoundingClientRect(); |
| 669 | return rect.right - popupSize.width; |
| 670 | }; |
| 671 | settingsPopup.options.adjustY = function(y){ |
| 672 | const rect = settingsButton.getBoundingClientRect(); |
| 673 | if(Chat.isChatOnlyMode()){ |
| 674 | return rect.top - popupSize.height -2; |
| 675 | }else{ |
| 676 | return rect.bottom + 2; |
| 677 | } |
| 678 | }; |
| 679 | })()/*#chat-settings-button setup*/; |
| 680 | |
| 681 | |
| 682 | /** Callback for poll() to inject new content into the page. jx == |
| 683 |
+28
-23
| --- src/default.css | ||
| +++ src/default.css | ||
| @@ -1597,10 +1597,14 @@ | ||
| 1597 | 1597 | .settings-icon:hover { |
| 1598 | 1598 | border: 1px outset rgba(127,127,127,1); |
| 1599 | 1599 | } |
| 1600 | 1600 | body.fossil-dark-style .settings-icon { |
| 1601 | 1601 | filter: invert(100%); |
| 1602 | +} | |
| 1603 | +/* "Chat-only mode" hides the site header/footer, showing only | |
| 1604 | + the chat app. */ | |
| 1605 | +body.chat.chat-only-mode{ | |
| 1602 | 1606 | } |
| 1603 | 1607 | body.chat #chat-settings-button { |
| 1604 | 1608 | } |
| 1605 | 1609 | /** Popup widget for the /chat settings. */ |
| 1606 | 1610 | body.chat .chat-settings-popup { |
| @@ -1640,48 +1644,49 @@ | ||
| 1640 | 1644 | /** Container for the list of /chat messages. */ |
| 1641 | 1645 | body.chat #chat-messages-wrapper { |
| 1642 | 1646 | display: flex; |
| 1643 | 1647 | flex-direction: column; |
| 1644 | 1648 | } |
| 1645 | -/* "Chat-only mode" hides the site header/footer, showing only | |
| 1646 | - the chat app. */ | |
| 1647 | -body.chat.chat-only-mode{ | |
| 1649 | +body.chat.chat-only-mode #chat-messages-wrapper { | |
| 1650 | + flex-direction: column-reverse; | |
| 1651 | + position: relative; | |
| 1652 | + top: 0; | |
| 1653 | + z-index: 99 /* so that it scrolls under input area. If it's | |
| 1654 | + lower than div.content then mouse events to it | |
| 1655 | + are blocked!*/; | |
| 1648 | 1656 | } |
| 1649 | 1657 | body.chat.chat-only-mode > div.content { |
| 1650 | 1658 | margin: 0; |
| 1651 | 1659 | padding: 0; |
| 1652 | 1660 | display: flex; |
| 1653 | 1661 | flex-direction: column; |
| 1654 | 1662 | align-items: stretch; |
| 1655 | 1663 | } |
| 1656 | -body.chat.chat-only-mode #chat-input-area { | |
| 1657 | - /* would like to pin this to the top so that it stays in place when | |
| 1658 | - scrolling, but doing so causes #chat-messages-wrapper to scroll | |
| 1659 | - behind it visibly, which is really ugly. Only current workaround is | |
| 1660 | - to force an opaque background color on this element, but that's not | |
| 1661 | - skin-friendly. */ | |
| 1662 | - position: sticky; | |
| 1663 | - position: -webkit-sticky /* supposedly some versions of Safari */; | |
| 1664 | - top: 0; | |
| 1665 | - padding: 0.5em 1em; | |
| 1666 | - z-index: 100 | |
| 1667 | - /* see notes in #chat-messages-wrapper. The various popups require a | |
| 1668 | - z-index higher than this one. */ | |
| 1669 | -} | |
| 1670 | -body.chat.chat-only-mode #chat-messages-wrapper { | |
| 1671 | - position: relative; | |
| 1672 | - top: 0; | |
| 1673 | - z-index: 99 /* so that it scrolls under input area. If it's | |
| 1674 | - lower than div.content then mouse events to it | |
| 1675 | - are blocked!*/; | |
| 1664 | +body.chat.chat-only-mode > div.content { | |
| 1665 | + flex-direction: column-reverse; | |
| 1676 | 1666 | } |
| 1677 | 1667 | /* Wrapper for /chat user input controls */ |
| 1678 | 1668 | body.chat #chat-input-area { |
| 1679 | 1669 | display: flex; |
| 1680 | 1670 | flex-direction: column; |
| 1681 | 1671 | border-bottom: 1px solid black; |
| 1672 | + padding: 0.5em 1em; | |
| 1682 | 1673 | margin-bottom: 0.5em; |
| 1674 | + /*position: sticky; top: 0;*/ | |
| 1675 | + /*position: -webkit-sticky*/ /* supposedly some versions of Safari */; | |
| 1676 | +} | |
| 1677 | +body.chat.chat-only-mode #chat-input-area { | |
| 1678 | + z-index: 100 | |
| 1679 | + /* see notes in #chat-messages-wrapper. The various popups require a | |
| 1680 | + z-index higher than this one. */; | |
| 1681 | + border-bottom: none; | |
| 1682 | + border-top: 1px solid black; | |
| 1683 | + margin-bottom: 0; | |
| 1684 | + margin-top: 0.5em; | |
| 1685 | + position: sticky; | |
| 1686 | + position: -webkit-sticky/* supposedly some versions of Safari */; | |
| 1687 | + bottom: 0; | |
| 1683 | 1688 | } |
| 1684 | 1689 | body.chat #chat-input-line { |
| 1685 | 1690 | display: flex; |
| 1686 | 1691 | flex-direction: row; |
| 1687 | 1692 | margin-bottom: 0.25em; |
| 1688 | 1693 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -1597,10 +1597,14 @@ | |
| 1597 | .settings-icon:hover { |
| 1598 | border: 1px outset rgba(127,127,127,1); |
| 1599 | } |
| 1600 | body.fossil-dark-style .settings-icon { |
| 1601 | filter: invert(100%); |
| 1602 | } |
| 1603 | body.chat #chat-settings-button { |
| 1604 | } |
| 1605 | /** Popup widget for the /chat settings. */ |
| 1606 | body.chat .chat-settings-popup { |
| @@ -1640,48 +1644,49 @@ | |
| 1640 | /** Container for the list of /chat messages. */ |
| 1641 | body.chat #chat-messages-wrapper { |
| 1642 | display: flex; |
| 1643 | flex-direction: column; |
| 1644 | } |
| 1645 | /* "Chat-only mode" hides the site header/footer, showing only |
| 1646 | the chat app. */ |
| 1647 | body.chat.chat-only-mode{ |
| 1648 | } |
| 1649 | body.chat.chat-only-mode > div.content { |
| 1650 | margin: 0; |
| 1651 | padding: 0; |
| 1652 | display: flex; |
| 1653 | flex-direction: column; |
| 1654 | align-items: stretch; |
| 1655 | } |
| 1656 | body.chat.chat-only-mode #chat-input-area { |
| 1657 | /* would like to pin this to the top so that it stays in place when |
| 1658 | scrolling, but doing so causes #chat-messages-wrapper to scroll |
| 1659 | behind it visibly, which is really ugly. Only current workaround is |
| 1660 | to force an opaque background color on this element, but that's not |
| 1661 | skin-friendly. */ |
| 1662 | position: sticky; |
| 1663 | position: -webkit-sticky /* supposedly some versions of Safari */; |
| 1664 | top: 0; |
| 1665 | padding: 0.5em 1em; |
| 1666 | z-index: 100 |
| 1667 | /* see notes in #chat-messages-wrapper. The various popups require a |
| 1668 | z-index higher than this one. */ |
| 1669 | } |
| 1670 | body.chat.chat-only-mode #chat-messages-wrapper { |
| 1671 | position: relative; |
| 1672 | top: 0; |
| 1673 | z-index: 99 /* so that it scrolls under input area. If it's |
| 1674 | lower than div.content then mouse events to it |
| 1675 | are blocked!*/; |
| 1676 | } |
| 1677 | /* Wrapper for /chat user input controls */ |
| 1678 | body.chat #chat-input-area { |
| 1679 | display: flex; |
| 1680 | flex-direction: column; |
| 1681 | border-bottom: 1px solid black; |
| 1682 | margin-bottom: 0.5em; |
| 1683 | } |
| 1684 | body.chat #chat-input-line { |
| 1685 | display: flex; |
| 1686 | flex-direction: row; |
| 1687 | margin-bottom: 0.25em; |
| 1688 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -1597,10 +1597,14 @@ | |
| 1597 | .settings-icon:hover { |
| 1598 | border: 1px outset rgba(127,127,127,1); |
| 1599 | } |
| 1600 | body.fossil-dark-style .settings-icon { |
| 1601 | filter: invert(100%); |
| 1602 | } |
| 1603 | /* "Chat-only mode" hides the site header/footer, showing only |
| 1604 | the chat app. */ |
| 1605 | body.chat.chat-only-mode{ |
| 1606 | } |
| 1607 | body.chat #chat-settings-button { |
| 1608 | } |
| 1609 | /** Popup widget for the /chat settings. */ |
| 1610 | body.chat .chat-settings-popup { |
| @@ -1640,48 +1644,49 @@ | |
| 1644 | /** Container for the list of /chat messages. */ |
| 1645 | body.chat #chat-messages-wrapper { |
| 1646 | display: flex; |
| 1647 | flex-direction: column; |
| 1648 | } |
| 1649 | body.chat.chat-only-mode #chat-messages-wrapper { |
| 1650 | flex-direction: column-reverse; |
| 1651 | position: relative; |
| 1652 | top: 0; |
| 1653 | z-index: 99 /* so that it scrolls under input area. If it's |
| 1654 | lower than div.content then mouse events to it |
| 1655 | are blocked!*/; |
| 1656 | } |
| 1657 | body.chat.chat-only-mode > div.content { |
| 1658 | margin: 0; |
| 1659 | padding: 0; |
| 1660 | display: flex; |
| 1661 | flex-direction: column; |
| 1662 | align-items: stretch; |
| 1663 | } |
| 1664 | body.chat.chat-only-mode > div.content { |
| 1665 | flex-direction: column-reverse; |
| 1666 | } |
| 1667 | /* Wrapper for /chat user input controls */ |
| 1668 | body.chat #chat-input-area { |
| 1669 | display: flex; |
| 1670 | flex-direction: column; |
| 1671 | border-bottom: 1px solid black; |
| 1672 | padding: 0.5em 1em; |
| 1673 | margin-bottom: 0.5em; |
| 1674 | /*position: sticky; top: 0;*/ |
| 1675 | /*position: -webkit-sticky*/ /* supposedly some versions of Safari */; |
| 1676 | } |
| 1677 | body.chat.chat-only-mode #chat-input-area { |
| 1678 | z-index: 100 |
| 1679 | /* see notes in #chat-messages-wrapper. The various popups require a |
| 1680 | z-index higher than this one. */; |
| 1681 | border-bottom: none; |
| 1682 | border-top: 1px solid black; |
| 1683 | margin-bottom: 0; |
| 1684 | margin-top: 0.5em; |
| 1685 | position: sticky; |
| 1686 | position: -webkit-sticky/* supposedly some versions of Safari */; |
| 1687 | bottom: 0; |
| 1688 | } |
| 1689 | body.chat #chat-input-line { |
| 1690 | display: flex; |
| 1691 | flex-direction: row; |
| 1692 | margin-bottom: 0.25em; |
| 1693 |