Fossil SCM
Merged in trunk for latest /chat features.
Commit
49689e1c70ca5a919dffac94ebb190a4125e100c181ef7969ac52fe61d9d6826
Parent
4f68a1306f7236f…
2 files changed
+51
-26
+51
-26
+51
-26
| --- src/fossil.page.chat.js | ||
| +++ src/fossil.page.chat.js | ||
| @@ -63,61 +63,69 @@ | ||
| 63 | 63 | /* This can inadvertently influence our flexbox layouts, so move |
| 64 | 64 | it out of the way. */ |
| 65 | 65 | D.append(document.body,dbg); |
| 66 | 66 | } |
| 67 | 67 | })(); |
| 68 | - const ForceResizeKludge = 0 ? function(){} : (function f(){ | |
| 68 | + const ForceResizeKludge = (function(){ | |
| 69 | 69 | /* Workaround for Safari mayhem regarding use of vh CSS units.... |
| 70 | 70 | We tried to use vh units to set the content area size for the |
| 71 | 71 | chat layout, but Safari chokes on that, so we calculate that |
| 72 | 72 | height here: 85% when in "normal" mode and 95% in chat-only |
| 73 | 73 | mode. Larger than ~95% is too big for Firefox on Android, |
| 74 | - causing the input area to move off-screen. */ | |
| 75 | - if(!f.elemsToCount){ | |
| 76 | - f.elemsToCount = [ | |
| 77 | - document.querySelector('body > div.header'), | |
| 78 | - document.querySelector('body > div.mainmenu'), | |
| 79 | - document.querySelector('body > #hbdrop'), | |
| 80 | - document.querySelector('body > div.footer') | |
| 81 | - ]; | |
| 82 | - f.contentArea = E1('div.content'); | |
| 83 | - } | |
| 84 | - const resized = function(){ | |
| 74 | + causing the input area to move off-screen. | |
| 75 | + | |
| 76 | + While we're here, we also use this to cap the max-height | |
| 77 | + of the input field so that pasting huge text does not scroll | |
| 78 | + the upper area of the input widget off-screen. */ | |
| 79 | + const elemsToCount = [ | |
| 80 | + document.querySelector('body > div.header'), | |
| 81 | + document.querySelector('body > div.mainmenu'), | |
| 82 | + document.querySelector('body > #hbdrop'), | |
| 83 | + document.querySelector('body > div.footer') | |
| 84 | + ]; | |
| 85 | + const contentArea = E1('div.content'); | |
| 86 | + const resized = function f(){ | |
| 87 | + if(f.$disabled) return; | |
| 85 | 88 | const wh = window.innerHeight, |
| 86 | 89 | com = document.body.classList.contains('chat-only-mode'); |
| 87 | 90 | var ht; |
| 88 | 91 | var extra = 0; |
| 89 | 92 | if(com){ |
| 90 | 93 | ht = wh; |
| 91 | 94 | }else{ |
| 92 | - f.elemsToCount.forEach((e)=>e ? extra += D.effectiveHeight(e) : false); | |
| 95 | + elemsToCount.forEach((e)=>e ? extra += D.effectiveHeight(e) : false); | |
| 93 | 96 | ht = wh - extra; |
| 94 | 97 | } |
| 95 | - f.contentArea.style.height = | |
| 96 | - f.contentArea.style.maxHeight = [ | |
| 98 | + f.chat.e.inputField.style.maxHeight = (ht/2)+"px"; | |
| 99 | + /* ^^^^ this is a middle ground between having no size cap | |
| 100 | + on the input field and having a fixed arbitrary cap. */; | |
| 101 | + contentArea.style.height = | |
| 102 | + contentArea.style.maxHeight = [ | |
| 97 | 103 | "calc(", (ht>=100 ? ht : 100), "px", |
| 98 | 104 | " - 0.75em"/*fudge value*/,")" |
| 99 | 105 | /* ^^^^ hypothetically not needed, but both Chrome/FF on |
| 100 | 106 | Linux will force scrollbars on the body if this value is |
| 101 | 107 | too small (<0.75em in my tests). */ |
| 102 | 108 | ].join(''); |
| 103 | 109 | if(false){ |
| 104 | 110 | console.debug("resized.",wh, extra, ht, |
| 105 | - window.getComputedStyle(f.contentArea).maxHeight, | |
| 106 | - f.contentArea); | |
| 111 | + window.getComputedStyle(contentArea).maxHeight, | |
| 112 | + contentArea); | |
| 113 | + console.debug("Set input max height to: ", | |
| 114 | + f.chat.e.inputField.style.maxHeight); | |
| 107 | 115 | } |
| 108 | 116 | }; |
| 109 | 117 | var doit; |
| 110 | 118 | window.addEventListener('resize',function(ev){ |
| 111 | 119 | clearTimeout(doit); |
| 112 | 120 | doit = setTimeout(resized, 100); |
| 113 | 121 | }, false); |
| 114 | - resized(); | |
| 115 | 122 | return resized; |
| 116 | 123 | })(); |
| 124 | + ForceResizeKludge.$disabled = true/*gets deleted when setup is finished*/; | |
| 117 | 125 | fossil.FRK = ForceResizeKludge/*for debugging*/; |
| 118 | - const Chat = (function(){ | |
| 126 | + const Chat = ForceResizeKludge.chat = (function(){ | |
| 119 | 127 | const cs = { |
| 120 | 128 | verboseErrors: false /* if true then certain, mostly extraneous, |
| 121 | 129 | error messages may be sent to the console. */, |
| 122 | 130 | e:{/*map of certain DOM elements.*/ |
| 123 | 131 | messageInjectPoint: E1('#message-inject-point'), |
| @@ -1168,18 +1176,33 @@ | ||
| 1168 | 1176 | self.hide(); |
| 1169 | 1177 | Chat.deleteMessage(eMsg); |
| 1170 | 1178 | } |
| 1171 | 1179 | }); |
| 1172 | 1180 | } |
| 1181 | + const toolbar3 = D.addClass(D.div(), 'toolbar'); | |
| 1182 | + D.append(this.e, toolbar3); | |
| 1183 | + D.append(toolbar3, D.button( | |
| 1184 | + "Locally remove all previous messages", | |
| 1185 | + function(){ | |
| 1186 | + self.hide(); | |
| 1187 | + Chat.mnMsg = +eMsg.dataset.msgid; | |
| 1188 | + var e = eMsg.previousElementSibling; | |
| 1189 | + while(e && e.classList.contains('message-widget')){ | |
| 1190 | + const n = e.previousElementSibling; | |
| 1191 | + D.remove(e); | |
| 1192 | + e = n; | |
| 1193 | + } | |
| 1194 | + eMsg.scrollIntoView(); | |
| 1195 | + } | |
| 1196 | + )); | |
| 1173 | 1197 | const toolbar2 = D.addClass(D.div(), 'toolbar'); |
| 1174 | 1198 | D.append(this.e, toolbar2); |
| 1175 | - const btnToggleText = D.button("Toggle text mode"); | |
| 1176 | - btnToggleText.addEventListener('click', function(){ | |
| 1177 | - self.hide(); | |
| 1178 | - Chat.toggleTextMode(eMsg); | |
| 1179 | - },false); | |
| 1180 | - D.append(toolbar2, btnToggleText); | |
| 1199 | + D.append(toolbar2, D.button( | |
| 1200 | + "Toggle text mode", function(){ | |
| 1201 | + self.hide(); | |
| 1202 | + Chat.toggleTextMode(eMsg); | |
| 1203 | + })); | |
| 1181 | 1204 | if(eMsg.dataset.xfrom){ |
| 1182 | 1205 | /* Add a link to the /timeline filtered on this user. */ |
| 1183 | 1206 | const timelineLink = D.attr( |
| 1184 | 1207 | D.a(F.repoUrl('timeline',{ |
| 1185 | 1208 | u: eMsg.dataset.xfrom, |
| @@ -1992,9 +2015,11 @@ | ||
| 1992 | 2015 | const flip = (ev)=>Chat.animate(ev.target,'anim-flip-h'); |
| 1993 | 2016 | document.querySelectorAll('#chat-buttons-wrapper .cbutton').forEach(function(e){ |
| 1994 | 2017 | e.addEventListener('click',flip, false); |
| 1995 | 2018 | }); |
| 1996 | 2019 | } |
| 1997 | - setTimeout( ()=>Chat.inputFocus(), 0 ); | |
| 2020 | + delete ForceResizeKludge.$disabled; | |
| 2021 | + ForceResizeKludge(); | |
| 1998 | 2022 | Chat.animate.$disabled = false; |
| 2023 | + setTimeout( ()=>Chat.inputFocus(), 0 ); | |
| 1999 | 2024 | F.page.chat = Chat/* enables testing the APIs via the dev tools */; |
| 2000 | 2025 | }); |
| 2001 | 2026 |
| --- src/fossil.page.chat.js | |
| +++ src/fossil.page.chat.js | |
| @@ -63,61 +63,69 @@ | |
| 63 | /* This can inadvertently influence our flexbox layouts, so move |
| 64 | it out of the way. */ |
| 65 | D.append(document.body,dbg); |
| 66 | } |
| 67 | })(); |
| 68 | const ForceResizeKludge = 0 ? function(){} : (function f(){ |
| 69 | /* Workaround for Safari mayhem regarding use of vh CSS units.... |
| 70 | We tried to use vh units to set the content area size for the |
| 71 | chat layout, but Safari chokes on that, so we calculate that |
| 72 | height here: 85% when in "normal" mode and 95% in chat-only |
| 73 | mode. Larger than ~95% is too big for Firefox on Android, |
| 74 | causing the input area to move off-screen. */ |
| 75 | if(!f.elemsToCount){ |
| 76 | f.elemsToCount = [ |
| 77 | document.querySelector('body > div.header'), |
| 78 | document.querySelector('body > div.mainmenu'), |
| 79 | document.querySelector('body > #hbdrop'), |
| 80 | document.querySelector('body > div.footer') |
| 81 | ]; |
| 82 | f.contentArea = E1('div.content'); |
| 83 | } |
| 84 | const resized = function(){ |
| 85 | const wh = window.innerHeight, |
| 86 | com = document.body.classList.contains('chat-only-mode'); |
| 87 | var ht; |
| 88 | var extra = 0; |
| 89 | if(com){ |
| 90 | ht = wh; |
| 91 | }else{ |
| 92 | f.elemsToCount.forEach((e)=>e ? extra += D.effectiveHeight(e) : false); |
| 93 | ht = wh - extra; |
| 94 | } |
| 95 | f.contentArea.style.height = |
| 96 | f.contentArea.style.maxHeight = [ |
| 97 | "calc(", (ht>=100 ? ht : 100), "px", |
| 98 | " - 0.75em"/*fudge value*/,")" |
| 99 | /* ^^^^ hypothetically not needed, but both Chrome/FF on |
| 100 | Linux will force scrollbars on the body if this value is |
| 101 | too small (<0.75em in my tests). */ |
| 102 | ].join(''); |
| 103 | if(false){ |
| 104 | console.debug("resized.",wh, extra, ht, |
| 105 | window.getComputedStyle(f.contentArea).maxHeight, |
| 106 | f.contentArea); |
| 107 | } |
| 108 | }; |
| 109 | var doit; |
| 110 | window.addEventListener('resize',function(ev){ |
| 111 | clearTimeout(doit); |
| 112 | doit = setTimeout(resized, 100); |
| 113 | }, false); |
| 114 | resized(); |
| 115 | return resized; |
| 116 | })(); |
| 117 | fossil.FRK = ForceResizeKludge/*for debugging*/; |
| 118 | const Chat = (function(){ |
| 119 | const cs = { |
| 120 | verboseErrors: false /* if true then certain, mostly extraneous, |
| 121 | error messages may be sent to the console. */, |
| 122 | e:{/*map of certain DOM elements.*/ |
| 123 | messageInjectPoint: E1('#message-inject-point'), |
| @@ -1168,18 +1176,33 @@ | |
| 1168 | self.hide(); |
| 1169 | Chat.deleteMessage(eMsg); |
| 1170 | } |
| 1171 | }); |
| 1172 | } |
| 1173 | const toolbar2 = D.addClass(D.div(), 'toolbar'); |
| 1174 | D.append(this.e, toolbar2); |
| 1175 | const btnToggleText = D.button("Toggle text mode"); |
| 1176 | btnToggleText.addEventListener('click', function(){ |
| 1177 | self.hide(); |
| 1178 | Chat.toggleTextMode(eMsg); |
| 1179 | },false); |
| 1180 | D.append(toolbar2, btnToggleText); |
| 1181 | if(eMsg.dataset.xfrom){ |
| 1182 | /* Add a link to the /timeline filtered on this user. */ |
| 1183 | const timelineLink = D.attr( |
| 1184 | D.a(F.repoUrl('timeline',{ |
| 1185 | u: eMsg.dataset.xfrom, |
| @@ -1992,9 +2015,11 @@ | |
| 1992 | const flip = (ev)=>Chat.animate(ev.target,'anim-flip-h'); |
| 1993 | document.querySelectorAll('#chat-buttons-wrapper .cbutton').forEach(function(e){ |
| 1994 | e.addEventListener('click',flip, false); |
| 1995 | }); |
| 1996 | } |
| 1997 | setTimeout( ()=>Chat.inputFocus(), 0 ); |
| 1998 | Chat.animate.$disabled = false; |
| 1999 | F.page.chat = Chat/* enables testing the APIs via the dev tools */; |
| 2000 | }); |
| 2001 |
| --- src/fossil.page.chat.js | |
| +++ src/fossil.page.chat.js | |
| @@ -63,61 +63,69 @@ | |
| 63 | /* This can inadvertently influence our flexbox layouts, so move |
| 64 | it out of the way. */ |
| 65 | D.append(document.body,dbg); |
| 66 | } |
| 67 | })(); |
| 68 | const ForceResizeKludge = (function(){ |
| 69 | /* Workaround for Safari mayhem regarding use of vh CSS units.... |
| 70 | We tried to use vh units to set the content area size for the |
| 71 | chat layout, but Safari chokes on that, so we calculate that |
| 72 | height here: 85% when in "normal" mode and 95% in chat-only |
| 73 | mode. Larger than ~95% is too big for Firefox on Android, |
| 74 | causing the input area to move off-screen. |
| 75 | |
| 76 | While we're here, we also use this to cap the max-height |
| 77 | of the input field so that pasting huge text does not scroll |
| 78 | the upper area of the input widget off-screen. */ |
| 79 | const elemsToCount = [ |
| 80 | document.querySelector('body > div.header'), |
| 81 | document.querySelector('body > div.mainmenu'), |
| 82 | document.querySelector('body > #hbdrop'), |
| 83 | document.querySelector('body > div.footer') |
| 84 | ]; |
| 85 | const contentArea = E1('div.content'); |
| 86 | const resized = function f(){ |
| 87 | if(f.$disabled) return; |
| 88 | const wh = window.innerHeight, |
| 89 | com = document.body.classList.contains('chat-only-mode'); |
| 90 | var ht; |
| 91 | var extra = 0; |
| 92 | if(com){ |
| 93 | ht = wh; |
| 94 | }else{ |
| 95 | elemsToCount.forEach((e)=>e ? extra += D.effectiveHeight(e) : false); |
| 96 | ht = wh - extra; |
| 97 | } |
| 98 | f.chat.e.inputField.style.maxHeight = (ht/2)+"px"; |
| 99 | /* ^^^^ this is a middle ground between having no size cap |
| 100 | on the input field and having a fixed arbitrary cap. */; |
| 101 | contentArea.style.height = |
| 102 | contentArea.style.maxHeight = [ |
| 103 | "calc(", (ht>=100 ? ht : 100), "px", |
| 104 | " - 0.75em"/*fudge value*/,")" |
| 105 | /* ^^^^ hypothetically not needed, but both Chrome/FF on |
| 106 | Linux will force scrollbars on the body if this value is |
| 107 | too small (<0.75em in my tests). */ |
| 108 | ].join(''); |
| 109 | if(false){ |
| 110 | console.debug("resized.",wh, extra, ht, |
| 111 | window.getComputedStyle(contentArea).maxHeight, |
| 112 | contentArea); |
| 113 | console.debug("Set input max height to: ", |
| 114 | f.chat.e.inputField.style.maxHeight); |
| 115 | } |
| 116 | }; |
| 117 | var doit; |
| 118 | window.addEventListener('resize',function(ev){ |
| 119 | clearTimeout(doit); |
| 120 | doit = setTimeout(resized, 100); |
| 121 | }, false); |
| 122 | return resized; |
| 123 | })(); |
| 124 | ForceResizeKludge.$disabled = true/*gets deleted when setup is finished*/; |
| 125 | fossil.FRK = ForceResizeKludge/*for debugging*/; |
| 126 | const Chat = ForceResizeKludge.chat = (function(){ |
| 127 | const cs = { |
| 128 | verboseErrors: false /* if true then certain, mostly extraneous, |
| 129 | error messages may be sent to the console. */, |
| 130 | e:{/*map of certain DOM elements.*/ |
| 131 | messageInjectPoint: E1('#message-inject-point'), |
| @@ -1168,18 +1176,33 @@ | |
| 1176 | self.hide(); |
| 1177 | Chat.deleteMessage(eMsg); |
| 1178 | } |
| 1179 | }); |
| 1180 | } |
| 1181 | const toolbar3 = D.addClass(D.div(), 'toolbar'); |
| 1182 | D.append(this.e, toolbar3); |
| 1183 | D.append(toolbar3, D.button( |
| 1184 | "Locally remove all previous messages", |
| 1185 | function(){ |
| 1186 | self.hide(); |
| 1187 | Chat.mnMsg = +eMsg.dataset.msgid; |
| 1188 | var e = eMsg.previousElementSibling; |
| 1189 | while(e && e.classList.contains('message-widget')){ |
| 1190 | const n = e.previousElementSibling; |
| 1191 | D.remove(e); |
| 1192 | e = n; |
| 1193 | } |
| 1194 | eMsg.scrollIntoView(); |
| 1195 | } |
| 1196 | )); |
| 1197 | const toolbar2 = D.addClass(D.div(), 'toolbar'); |
| 1198 | D.append(this.e, toolbar2); |
| 1199 | D.append(toolbar2, D.button( |
| 1200 | "Toggle text mode", function(){ |
| 1201 | self.hide(); |
| 1202 | Chat.toggleTextMode(eMsg); |
| 1203 | })); |
| 1204 | if(eMsg.dataset.xfrom){ |
| 1205 | /* Add a link to the /timeline filtered on this user. */ |
| 1206 | const timelineLink = D.attr( |
| 1207 | D.a(F.repoUrl('timeline',{ |
| 1208 | u: eMsg.dataset.xfrom, |
| @@ -1992,9 +2015,11 @@ | |
| 2015 | const flip = (ev)=>Chat.animate(ev.target,'anim-flip-h'); |
| 2016 | document.querySelectorAll('#chat-buttons-wrapper .cbutton').forEach(function(e){ |
| 2017 | e.addEventListener('click',flip, false); |
| 2018 | }); |
| 2019 | } |
| 2020 | delete ForceResizeKludge.$disabled; |
| 2021 | ForceResizeKludge(); |
| 2022 | Chat.animate.$disabled = false; |
| 2023 | setTimeout( ()=>Chat.inputFocus(), 0 ); |
| 2024 | F.page.chat = Chat/* enables testing the APIs via the dev tools */; |
| 2025 | }); |
| 2026 |
+51
-26
| --- src/fossil.page.chat.js | ||
| +++ src/fossil.page.chat.js | ||
| @@ -63,61 +63,69 @@ | ||
| 63 | 63 | /* This can inadvertently influence our flexbox layouts, so move |
| 64 | 64 | it out of the way. */ |
| 65 | 65 | D.append(document.body,dbg); |
| 66 | 66 | } |
| 67 | 67 | })(); |
| 68 | - const ForceResizeKludge = 0 ? function(){} : (function f(){ | |
| 68 | + const ForceResizeKludge = (function(){ | |
| 69 | 69 | /* Workaround for Safari mayhem regarding use of vh CSS units.... |
| 70 | 70 | We tried to use vh units to set the content area size for the |
| 71 | 71 | chat layout, but Safari chokes on that, so we calculate that |
| 72 | 72 | height here: 85% when in "normal" mode and 95% in chat-only |
| 73 | 73 | mode. Larger than ~95% is too big for Firefox on Android, |
| 74 | - causing the input area to move off-screen. */ | |
| 75 | - if(!f.elemsToCount){ | |
| 76 | - f.elemsToCount = [ | |
| 77 | - document.querySelector('body > div.header'), | |
| 78 | - document.querySelector('body > div.mainmenu'), | |
| 79 | - document.querySelector('body > #hbdrop'), | |
| 80 | - document.querySelector('body > div.footer') | |
| 81 | - ]; | |
| 82 | - f.contentArea = E1('div.content'); | |
| 83 | - } | |
| 84 | - const resized = function(){ | |
| 74 | + causing the input area to move off-screen. | |
| 75 | + | |
| 76 | + While we're here, we also use this to cap the max-height | |
| 77 | + of the input field so that pasting huge text does not scroll | |
| 78 | + the upper area of the input widget off-screen. */ | |
| 79 | + const elemsToCount = [ | |
| 80 | + document.querySelector('body > div.header'), | |
| 81 | + document.querySelector('body > div.mainmenu'), | |
| 82 | + document.querySelector('body > #hbdrop'), | |
| 83 | + document.querySelector('body > div.footer') | |
| 84 | + ]; | |
| 85 | + const contentArea = E1('div.content'); | |
| 86 | + const resized = function f(){ | |
| 87 | + if(f.$disabled) return; | |
| 85 | 88 | const wh = window.innerHeight, |
| 86 | 89 | com = document.body.classList.contains('chat-only-mode'); |
| 87 | 90 | var ht; |
| 88 | 91 | var extra = 0; |
| 89 | 92 | if(com){ |
| 90 | 93 | ht = wh; |
| 91 | 94 | }else{ |
| 92 | - f.elemsToCount.forEach((e)=>e ? extra += D.effectiveHeight(e) : false); | |
| 95 | + elemsToCount.forEach((e)=>e ? extra += D.effectiveHeight(e) : false); | |
| 93 | 96 | ht = wh - extra; |
| 94 | 97 | } |
| 95 | - f.contentArea.style.height = | |
| 96 | - f.contentArea.style.maxHeight = [ | |
| 98 | + f.chat.e.inputField.style.maxHeight = (ht/2)+"px"; | |
| 99 | + /* ^^^^ this is a middle ground between having no size cap | |
| 100 | + on the input field and having a fixed arbitrary cap. */; | |
| 101 | + contentArea.style.height = | |
| 102 | + contentArea.style.maxHeight = [ | |
| 97 | 103 | "calc(", (ht>=100 ? ht : 100), "px", |
| 98 | 104 | " - 0.75em"/*fudge value*/,")" |
| 99 | 105 | /* ^^^^ hypothetically not needed, but both Chrome/FF on |
| 100 | 106 | Linux will force scrollbars on the body if this value is |
| 101 | 107 | too small (<0.75em in my tests). */ |
| 102 | 108 | ].join(''); |
| 103 | 109 | if(false){ |
| 104 | 110 | console.debug("resized.",wh, extra, ht, |
| 105 | - window.getComputedStyle(f.contentArea).maxHeight, | |
| 106 | - f.contentArea); | |
| 111 | + window.getComputedStyle(contentArea).maxHeight, | |
| 112 | + contentArea); | |
| 113 | + console.debug("Set input max height to: ", | |
| 114 | + f.chat.e.inputField.style.maxHeight); | |
| 107 | 115 | } |
| 108 | 116 | }; |
| 109 | 117 | var doit; |
| 110 | 118 | window.addEventListener('resize',function(ev){ |
| 111 | 119 | clearTimeout(doit); |
| 112 | 120 | doit = setTimeout(resized, 100); |
| 113 | 121 | }, false); |
| 114 | - resized(); | |
| 115 | 122 | return resized; |
| 116 | 123 | })(); |
| 124 | + ForceResizeKludge.$disabled = true/*gets deleted when setup is finished*/; | |
| 117 | 125 | fossil.FRK = ForceResizeKludge/*for debugging*/; |
| 118 | - const Chat = (function(){ | |
| 126 | + const Chat = ForceResizeKludge.chat = (function(){ | |
| 119 | 127 | const cs = { |
| 120 | 128 | verboseErrors: false /* if true then certain, mostly extraneous, |
| 121 | 129 | error messages may be sent to the console. */, |
| 122 | 130 | e:{/*map of certain DOM elements.*/ |
| 123 | 131 | messageInjectPoint: E1('#message-inject-point'), |
| @@ -1168,18 +1176,33 @@ | ||
| 1168 | 1176 | self.hide(); |
| 1169 | 1177 | Chat.deleteMessage(eMsg); |
| 1170 | 1178 | } |
| 1171 | 1179 | }); |
| 1172 | 1180 | } |
| 1181 | + const toolbar3 = D.addClass(D.div(), 'toolbar'); | |
| 1182 | + D.append(this.e, toolbar3); | |
| 1183 | + D.append(toolbar3, D.button( | |
| 1184 | + "Locally remove all previous messages", | |
| 1185 | + function(){ | |
| 1186 | + self.hide(); | |
| 1187 | + Chat.mnMsg = +eMsg.dataset.msgid; | |
| 1188 | + var e = eMsg.previousElementSibling; | |
| 1189 | + while(e && e.classList.contains('message-widget')){ | |
| 1190 | + const n = e.previousElementSibling; | |
| 1191 | + D.remove(e); | |
| 1192 | + e = n; | |
| 1193 | + } | |
| 1194 | + eMsg.scrollIntoView(); | |
| 1195 | + } | |
| 1196 | + )); | |
| 1173 | 1197 | const toolbar2 = D.addClass(D.div(), 'toolbar'); |
| 1174 | 1198 | D.append(this.e, toolbar2); |
| 1175 | - const btnToggleText = D.button("Toggle text mode"); | |
| 1176 | - btnToggleText.addEventListener('click', function(){ | |
| 1177 | - self.hide(); | |
| 1178 | - Chat.toggleTextMode(eMsg); | |
| 1179 | - },false); | |
| 1180 | - D.append(toolbar2, btnToggleText); | |
| 1199 | + D.append(toolbar2, D.button( | |
| 1200 | + "Toggle text mode", function(){ | |
| 1201 | + self.hide(); | |
| 1202 | + Chat.toggleTextMode(eMsg); | |
| 1203 | + })); | |
| 1181 | 1204 | if(eMsg.dataset.xfrom){ |
| 1182 | 1205 | /* Add a link to the /timeline filtered on this user. */ |
| 1183 | 1206 | const timelineLink = D.attr( |
| 1184 | 1207 | D.a(F.repoUrl('timeline',{ |
| 1185 | 1208 | u: eMsg.dataset.xfrom, |
| @@ -1992,9 +2015,11 @@ | ||
| 1992 | 2015 | const flip = (ev)=>Chat.animate(ev.target,'anim-flip-h'); |
| 1993 | 2016 | document.querySelectorAll('#chat-buttons-wrapper .cbutton').forEach(function(e){ |
| 1994 | 2017 | e.addEventListener('click',flip, false); |
| 1995 | 2018 | }); |
| 1996 | 2019 | } |
| 1997 | - setTimeout( ()=>Chat.inputFocus(), 0 ); | |
| 2020 | + delete ForceResizeKludge.$disabled; | |
| 2021 | + ForceResizeKludge(); | |
| 1998 | 2022 | Chat.animate.$disabled = false; |
| 2023 | + setTimeout( ()=>Chat.inputFocus(), 0 ); | |
| 1999 | 2024 | F.page.chat = Chat/* enables testing the APIs via the dev tools */; |
| 2000 | 2025 | }); |
| 2001 | 2026 |
| --- src/fossil.page.chat.js | |
| +++ src/fossil.page.chat.js | |
| @@ -63,61 +63,69 @@ | |
| 63 | /* This can inadvertently influence our flexbox layouts, so move |
| 64 | it out of the way. */ |
| 65 | D.append(document.body,dbg); |
| 66 | } |
| 67 | })(); |
| 68 | const ForceResizeKludge = 0 ? function(){} : (function f(){ |
| 69 | /* Workaround for Safari mayhem regarding use of vh CSS units.... |
| 70 | We tried to use vh units to set the content area size for the |
| 71 | chat layout, but Safari chokes on that, so we calculate that |
| 72 | height here: 85% when in "normal" mode and 95% in chat-only |
| 73 | mode. Larger than ~95% is too big for Firefox on Android, |
| 74 | causing the input area to move off-screen. */ |
| 75 | if(!f.elemsToCount){ |
| 76 | f.elemsToCount = [ |
| 77 | document.querySelector('body > div.header'), |
| 78 | document.querySelector('body > div.mainmenu'), |
| 79 | document.querySelector('body > #hbdrop'), |
| 80 | document.querySelector('body > div.footer') |
| 81 | ]; |
| 82 | f.contentArea = E1('div.content'); |
| 83 | } |
| 84 | const resized = function(){ |
| 85 | const wh = window.innerHeight, |
| 86 | com = document.body.classList.contains('chat-only-mode'); |
| 87 | var ht; |
| 88 | var extra = 0; |
| 89 | if(com){ |
| 90 | ht = wh; |
| 91 | }else{ |
| 92 | f.elemsToCount.forEach((e)=>e ? extra += D.effectiveHeight(e) : false); |
| 93 | ht = wh - extra; |
| 94 | } |
| 95 | f.contentArea.style.height = |
| 96 | f.contentArea.style.maxHeight = [ |
| 97 | "calc(", (ht>=100 ? ht : 100), "px", |
| 98 | " - 0.75em"/*fudge value*/,")" |
| 99 | /* ^^^^ hypothetically not needed, but both Chrome/FF on |
| 100 | Linux will force scrollbars on the body if this value is |
| 101 | too small (<0.75em in my tests). */ |
| 102 | ].join(''); |
| 103 | if(false){ |
| 104 | console.debug("resized.",wh, extra, ht, |
| 105 | window.getComputedStyle(f.contentArea).maxHeight, |
| 106 | f.contentArea); |
| 107 | } |
| 108 | }; |
| 109 | var doit; |
| 110 | window.addEventListener('resize',function(ev){ |
| 111 | clearTimeout(doit); |
| 112 | doit = setTimeout(resized, 100); |
| 113 | }, false); |
| 114 | resized(); |
| 115 | return resized; |
| 116 | })(); |
| 117 | fossil.FRK = ForceResizeKludge/*for debugging*/; |
| 118 | const Chat = (function(){ |
| 119 | const cs = { |
| 120 | verboseErrors: false /* if true then certain, mostly extraneous, |
| 121 | error messages may be sent to the console. */, |
| 122 | e:{/*map of certain DOM elements.*/ |
| 123 | messageInjectPoint: E1('#message-inject-point'), |
| @@ -1168,18 +1176,33 @@ | |
| 1168 | self.hide(); |
| 1169 | Chat.deleteMessage(eMsg); |
| 1170 | } |
| 1171 | }); |
| 1172 | } |
| 1173 | const toolbar2 = D.addClass(D.div(), 'toolbar'); |
| 1174 | D.append(this.e, toolbar2); |
| 1175 | const btnToggleText = D.button("Toggle text mode"); |
| 1176 | btnToggleText.addEventListener('click', function(){ |
| 1177 | self.hide(); |
| 1178 | Chat.toggleTextMode(eMsg); |
| 1179 | },false); |
| 1180 | D.append(toolbar2, btnToggleText); |
| 1181 | if(eMsg.dataset.xfrom){ |
| 1182 | /* Add a link to the /timeline filtered on this user. */ |
| 1183 | const timelineLink = D.attr( |
| 1184 | D.a(F.repoUrl('timeline',{ |
| 1185 | u: eMsg.dataset.xfrom, |
| @@ -1992,9 +2015,11 @@ | |
| 1992 | const flip = (ev)=>Chat.animate(ev.target,'anim-flip-h'); |
| 1993 | document.querySelectorAll('#chat-buttons-wrapper .cbutton').forEach(function(e){ |
| 1994 | e.addEventListener('click',flip, false); |
| 1995 | }); |
| 1996 | } |
| 1997 | setTimeout( ()=>Chat.inputFocus(), 0 ); |
| 1998 | Chat.animate.$disabled = false; |
| 1999 | F.page.chat = Chat/* enables testing the APIs via the dev tools */; |
| 2000 | }); |
| 2001 |
| --- src/fossil.page.chat.js | |
| +++ src/fossil.page.chat.js | |
| @@ -63,61 +63,69 @@ | |
| 63 | /* This can inadvertently influence our flexbox layouts, so move |
| 64 | it out of the way. */ |
| 65 | D.append(document.body,dbg); |
| 66 | } |
| 67 | })(); |
| 68 | const ForceResizeKludge = (function(){ |
| 69 | /* Workaround for Safari mayhem regarding use of vh CSS units.... |
| 70 | We tried to use vh units to set the content area size for the |
| 71 | chat layout, but Safari chokes on that, so we calculate that |
| 72 | height here: 85% when in "normal" mode and 95% in chat-only |
| 73 | mode. Larger than ~95% is too big for Firefox on Android, |
| 74 | causing the input area to move off-screen. |
| 75 | |
| 76 | While we're here, we also use this to cap the max-height |
| 77 | of the input field so that pasting huge text does not scroll |
| 78 | the upper area of the input widget off-screen. */ |
| 79 | const elemsToCount = [ |
| 80 | document.querySelector('body > div.header'), |
| 81 | document.querySelector('body > div.mainmenu'), |
| 82 | document.querySelector('body > #hbdrop'), |
| 83 | document.querySelector('body > div.footer') |
| 84 | ]; |
| 85 | const contentArea = E1('div.content'); |
| 86 | const resized = function f(){ |
| 87 | if(f.$disabled) return; |
| 88 | const wh = window.innerHeight, |
| 89 | com = document.body.classList.contains('chat-only-mode'); |
| 90 | var ht; |
| 91 | var extra = 0; |
| 92 | if(com){ |
| 93 | ht = wh; |
| 94 | }else{ |
| 95 | elemsToCount.forEach((e)=>e ? extra += D.effectiveHeight(e) : false); |
| 96 | ht = wh - extra; |
| 97 | } |
| 98 | f.chat.e.inputField.style.maxHeight = (ht/2)+"px"; |
| 99 | /* ^^^^ this is a middle ground between having no size cap |
| 100 | on the input field and having a fixed arbitrary cap. */; |
| 101 | contentArea.style.height = |
| 102 | contentArea.style.maxHeight = [ |
| 103 | "calc(", (ht>=100 ? ht : 100), "px", |
| 104 | " - 0.75em"/*fudge value*/,")" |
| 105 | /* ^^^^ hypothetically not needed, but both Chrome/FF on |
| 106 | Linux will force scrollbars on the body if this value is |
| 107 | too small (<0.75em in my tests). */ |
| 108 | ].join(''); |
| 109 | if(false){ |
| 110 | console.debug("resized.",wh, extra, ht, |
| 111 | window.getComputedStyle(contentArea).maxHeight, |
| 112 | contentArea); |
| 113 | console.debug("Set input max height to: ", |
| 114 | f.chat.e.inputField.style.maxHeight); |
| 115 | } |
| 116 | }; |
| 117 | var doit; |
| 118 | window.addEventListener('resize',function(ev){ |
| 119 | clearTimeout(doit); |
| 120 | doit = setTimeout(resized, 100); |
| 121 | }, false); |
| 122 | return resized; |
| 123 | })(); |
| 124 | ForceResizeKludge.$disabled = true/*gets deleted when setup is finished*/; |
| 125 | fossil.FRK = ForceResizeKludge/*for debugging*/; |
| 126 | const Chat = ForceResizeKludge.chat = (function(){ |
| 127 | const cs = { |
| 128 | verboseErrors: false /* if true then certain, mostly extraneous, |
| 129 | error messages may be sent to the console. */, |
| 130 | e:{/*map of certain DOM elements.*/ |
| 131 | messageInjectPoint: E1('#message-inject-point'), |
| @@ -1168,18 +1176,33 @@ | |
| 1176 | self.hide(); |
| 1177 | Chat.deleteMessage(eMsg); |
| 1178 | } |
| 1179 | }); |
| 1180 | } |
| 1181 | const toolbar3 = D.addClass(D.div(), 'toolbar'); |
| 1182 | D.append(this.e, toolbar3); |
| 1183 | D.append(toolbar3, D.button( |
| 1184 | "Locally remove all previous messages", |
| 1185 | function(){ |
| 1186 | self.hide(); |
| 1187 | Chat.mnMsg = +eMsg.dataset.msgid; |
| 1188 | var e = eMsg.previousElementSibling; |
| 1189 | while(e && e.classList.contains('message-widget')){ |
| 1190 | const n = e.previousElementSibling; |
| 1191 | D.remove(e); |
| 1192 | e = n; |
| 1193 | } |
| 1194 | eMsg.scrollIntoView(); |
| 1195 | } |
| 1196 | )); |
| 1197 | const toolbar2 = D.addClass(D.div(), 'toolbar'); |
| 1198 | D.append(this.e, toolbar2); |
| 1199 | D.append(toolbar2, D.button( |
| 1200 | "Toggle text mode", function(){ |
| 1201 | self.hide(); |
| 1202 | Chat.toggleTextMode(eMsg); |
| 1203 | })); |
| 1204 | if(eMsg.dataset.xfrom){ |
| 1205 | /* Add a link to the /timeline filtered on this user. */ |
| 1206 | const timelineLink = D.attr( |
| 1207 | D.a(F.repoUrl('timeline',{ |
| 1208 | u: eMsg.dataset.xfrom, |
| @@ -1992,9 +2015,11 @@ | |
| 2015 | const flip = (ev)=>Chat.animate(ev.target,'anim-flip-h'); |
| 2016 | document.querySelectorAll('#chat-buttons-wrapper .cbutton').forEach(function(e){ |
| 2017 | e.addEventListener('click',flip, false); |
| 2018 | }); |
| 2019 | } |
| 2020 | delete ForceResizeKludge.$disabled; |
| 2021 | ForceResizeKludge(); |
| 2022 | Chat.animate.$disabled = false; |
| 2023 | setTimeout( ()=>Chat.inputFocus(), 0 ); |
| 2024 | F.page.chat = Chat/* enables testing the APIs via the dev tools */; |
| 2025 | }); |
| 2026 |