Fossil SCM
chat: changed layout from table-based to one fieldset per row of chat (fieldset rather than a custom construct because browsers have special support for placement of the LEGEND tag which we cannot easily reproduce in other element). The overall look is approximately the same, but saves some space.
Commit
a0ebe0ead1fa237c2ded9714650d65167a288a65732a61938190892ce7d81bd2
Parent
3a36b8e9c6c9857…
1 file changed
+75
-41
+75
-41
| --- tools/chat.tcl | ||
| +++ tools/chat.tcl | ||
| @@ -48,40 +48,19 @@ | ||
| 48 | 48 | <span>File:</span> |
| 49 | 49 | <input type="file" name="file"> |
| 50 | 50 | </div> |
| 51 | 51 | </div> |
| 52 | 52 | </form> |
| 53 | - | |
| 54 | 53 | <hr> |
| 55 | - <table id="dialog"> | |
| 56 | - </table> | |
| 57 | - </div> | |
| 54 | + <span id='message-inject-point'></span> | |
| 55 | + | |
| 56 | + </div><!-- .fossil-doc --> | |
| 58 | 57 | <hr> |
| 59 | 58 | <p> |
| 60 | 59 | <a href="chat/env">CGI environment</a> | |
| 61 | 60 | <a href="chat/self">Wapp script</a> |
| 62 | 61 | <style> |
| 63 | -.chat-message {/*style common to .chat-mx and .chat-ms*/ | |
| 64 | - padding: 0.5em; | |
| 65 | - border-radius: 0.5em; | |
| 66 | - border: 1px solid black; | |
| 67 | - box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29); | |
| 68 | - /* Bob Ross might approve of... */ | |
| 69 | - /* | |
| 70 | - background-image: linear-gradient(45deg, #FFC107 0%, #ff8b5f 100%); | |
| 71 | - border-bottom: solid 3px #c58668; | |
| 72 | - */ | |
| 73 | -} | |
| 74 | -.chat-mx { | |
| 75 | - float: left; | |
| 76 | - margin-right: 3em; | |
| 77 | -} | |
| 78 | -.chat-ms { | |
| 79 | - float: right; | |
| 80 | - margin-left: 3em; | |
| 81 | - background-color: #d2dde1; | |
| 82 | -} | |
| 83 | 62 | \#dialog { |
| 84 | 63 | width: 97%; |
| 85 | 64 | } |
| 86 | 65 | \#chat-input-area { |
| 87 | 66 | width: 100%; |
| @@ -110,10 +89,57 @@ | ||
| 110 | 89 | flex: 1 0 auto; |
| 111 | 90 | } |
| 112 | 91 | span.at-name { /* for @USERNAME references */ |
| 113 | 92 | text-decoration: underline; |
| 114 | 93 | font-weight: bold; |
| 94 | +} | |
| 95 | +/* A wrapper for a single single message (one row of the UI) */ | |
| 96 | +.message-row { | |
| 97 | + margin-bottom: 0.5em; | |
| 98 | + border: none; | |
| 99 | + display: flex; | |
| 100 | + flex-direction: row; | |
| 101 | + justify-content: flex-start; | |
| 102 | + /*border: 1px solid rgba(0,0,0,0.2); | |
| 103 | + border-radius: 0.25em; | |
| 104 | + box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);*/ | |
| 105 | + border: none; | |
| 106 | +} | |
| 107 | +/* Rows for the current user have the .user-is-me CSS class | |
| 108 | + and get right-aligned. */ | |
| 109 | +.message-row.user-is-me { | |
| 110 | + justify-content: flex-end; | |
| 111 | + /*background-color: #d2dde1;*/ | |
| 112 | +} | |
| 113 | +/* The content area of a message (the body element of a FIELDSET) */ | |
| 114 | +.message-content { | |
| 115 | + display: inline-block; | |
| 116 | + border-radius: 0.25em; | |
| 117 | + border: 1px solid rgba(0,0,0,0.2); | |
| 118 | + box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29); | |
| 119 | + padding: 0.25em 1em; | |
| 120 | + margin-top: -0.75em; | |
| 121 | +} | |
| 122 | +.message-row.user-is-me .message-content { | |
| 123 | + background-color: #d2dde1; | |
| 124 | +} | |
| 125 | +/* User name for the post (a LEGEND element) */ | |
| 126 | +.message-row .message-user { | |
| 127 | + background: inherit; | |
| 128 | + border-radius: 0.25em 0.25em 0 0; | |
| 129 | + padding: 0 0.5em; | |
| 130 | + /*text-align: left; Firefox requires the 'align' attribute */ | |
| 131 | + margin-left: 0.25em; | |
| 132 | + padding: 0 0.5em 0em 0.5em; | |
| 133 | + margin-bottom: 0.4em; | |
| 134 | + background-color: #d2dde1; | |
| 135 | +} | |
| 136 | +/* Reposition "my" posts to the right */ | |
| 137 | +.message-row.user-is-me .message-user { | |
| 138 | + /*text-align: right; Firefox requires the 'align' attribute */ | |
| 139 | + margin-left: 0; | |
| 140 | + margin-right: 0.25em; | |
| 115 | 141 | } |
| 116 | 142 | </style> |
| 117 | 143 | } |
| 118 | 144 | set nonce [wapp-param FOSSIL_NONCE] |
| 119 | 145 | set submiturl [wapp-param SCRIPT_NAME]/send |
| @@ -213,27 +239,40 @@ | ||
| 213 | 239 | span.appendChild(e); |
| 214 | 240 | }); |
| 215 | 241 | //console.debug("span =",span.innerHTML); |
| 216 | 242 | return span; |
| 217 | 243 | }/*end messageToDOM()*/; |
| 244 | + const injectMessage = function f(e){ | |
| 245 | + if(!f.injectPoint){ | |
| 246 | + f.injectPoint = document.querySelector('#message-inject-point'); | |
| 247 | + } | |
| 248 | + f.injectPoint.parentNode.insertBefore(e, f.injectPoint.nextSibling); | |
| 249 | + }; | |
| 218 | 250 | function newcontent(jx){ |
| 219 | - var tab = document.getElementById("dialog"); | |
| 220 | 251 | var i; |
| 221 | 252 | for(i=0; i<jx.msgs.length; ++i){ |
| 222 | 253 | let m = jx.msgs[i]; |
| 223 | - let r = document.createElement("tr"); | |
| 254 | + let row = document.createElement("fieldset"); | |
| 224 | 255 | if( m.msgid>mxMsg ) mxMsg = m.msgid; |
| 225 | - tab.insertBefore(r, tab.childNodes[0]); | |
| 226 | - let td = document.createElement("td"); | |
| 227 | - r.appendChild(td); | |
| 228 | - if( m.xfrom!=_me ){ | |
| 229 | - td.appendChild(document.createTextNode(m.xfrom)); | |
| 230 | - } | |
| 231 | - td = document.createElement("td"); | |
| 232 | - r.appendChild(td); | |
| 233 | - let span = document.createElement("span"); | |
| 234 | - td.appendChild(span); | |
| 256 | + row.classList.add('message-row'); | |
| 257 | + injectMessage(row); | |
| 258 | + const eWho = document.createElement('legend'); | |
| 259 | + eWho.setAttribute('align', (m.xfrom===_me ? 'right' : 'left')); | |
| 260 | + row.appendChild(eWho); | |
| 261 | + eWho.classList.add('message-user'); | |
| 262 | + let whoName; | |
| 263 | + if( m.xfrom===_me ){ | |
| 264 | + whoName = 'me'; | |
| 265 | + //eWho.classList.add('user-is-me'); | |
| 266 | + row.classList.add('user-is-me'); | |
| 267 | + }else{ | |
| 268 | + whoName = m.xfrom; | |
| 269 | + } | |
| 270 | + eWho.append(document.createTextNode(whoName)); | |
| 271 | + let span = document.createElement("div"); | |
| 272 | + span.classList.add('message-content'); | |
| 273 | + row.appendChild(span); | |
| 235 | 274 | if( m.fsize>0 ){ |
| 236 | 275 | if( m.fmime && m.fmime.startsWith("image/") ){ |
| 237 | 276 | let img = document.createElement("img"); |
| 238 | 277 | img.src = "%string($downloadurl)/" + m.msgid; |
| 239 | 278 | span.appendChild(img); |
| @@ -255,15 +294,10 @@ | ||
| 255 | 294 | if( m.xfrom!=_me ){ |
| 256 | 295 | span.classList.add('chat-mx'); |
| 257 | 296 | }else{ |
| 258 | 297 | span.classList.add('chat-ms'); |
| 259 | 298 | } |
| 260 | - td = document.createElement("td"); | |
| 261 | - r.appendChild(td); | |
| 262 | - if( m.xfrom==_me ){ | |
| 263 | - td.appendChild(document.createTextNode('me')) | |
| 264 | - } | |
| 265 | 299 | } |
| 266 | 300 | } |
| 267 | 301 | async function poll(){ |
| 268 | 302 | if(poll.running) return; |
| 269 | 303 | poll.running = true; |
| 270 | 304 |
| --- tools/chat.tcl | |
| +++ tools/chat.tcl | |
| @@ -48,40 +48,19 @@ | |
| 48 | <span>File:</span> |
| 49 | <input type="file" name="file"> |
| 50 | </div> |
| 51 | </div> |
| 52 | </form> |
| 53 | |
| 54 | <hr> |
| 55 | <table id="dialog"> |
| 56 | </table> |
| 57 | </div> |
| 58 | <hr> |
| 59 | <p> |
| 60 | <a href="chat/env">CGI environment</a> | |
| 61 | <a href="chat/self">Wapp script</a> |
| 62 | <style> |
| 63 | .chat-message {/*style common to .chat-mx and .chat-ms*/ |
| 64 | padding: 0.5em; |
| 65 | border-radius: 0.5em; |
| 66 | border: 1px solid black; |
| 67 | box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29); |
| 68 | /* Bob Ross might approve of... */ |
| 69 | /* |
| 70 | background-image: linear-gradient(45deg, #FFC107 0%, #ff8b5f 100%); |
| 71 | border-bottom: solid 3px #c58668; |
| 72 | */ |
| 73 | } |
| 74 | .chat-mx { |
| 75 | float: left; |
| 76 | margin-right: 3em; |
| 77 | } |
| 78 | .chat-ms { |
| 79 | float: right; |
| 80 | margin-left: 3em; |
| 81 | background-color: #d2dde1; |
| 82 | } |
| 83 | \#dialog { |
| 84 | width: 97%; |
| 85 | } |
| 86 | \#chat-input-area { |
| 87 | width: 100%; |
| @@ -110,10 +89,57 @@ | |
| 110 | flex: 1 0 auto; |
| 111 | } |
| 112 | span.at-name { /* for @USERNAME references */ |
| 113 | text-decoration: underline; |
| 114 | font-weight: bold; |
| 115 | } |
| 116 | </style> |
| 117 | } |
| 118 | set nonce [wapp-param FOSSIL_NONCE] |
| 119 | set submiturl [wapp-param SCRIPT_NAME]/send |
| @@ -213,27 +239,40 @@ | |
| 213 | span.appendChild(e); |
| 214 | }); |
| 215 | //console.debug("span =",span.innerHTML); |
| 216 | return span; |
| 217 | }/*end messageToDOM()*/; |
| 218 | function newcontent(jx){ |
| 219 | var tab = document.getElementById("dialog"); |
| 220 | var i; |
| 221 | for(i=0; i<jx.msgs.length; ++i){ |
| 222 | let m = jx.msgs[i]; |
| 223 | let r = document.createElement("tr"); |
| 224 | if( m.msgid>mxMsg ) mxMsg = m.msgid; |
| 225 | tab.insertBefore(r, tab.childNodes[0]); |
| 226 | let td = document.createElement("td"); |
| 227 | r.appendChild(td); |
| 228 | if( m.xfrom!=_me ){ |
| 229 | td.appendChild(document.createTextNode(m.xfrom)); |
| 230 | } |
| 231 | td = document.createElement("td"); |
| 232 | r.appendChild(td); |
| 233 | let span = document.createElement("span"); |
| 234 | td.appendChild(span); |
| 235 | if( m.fsize>0 ){ |
| 236 | if( m.fmime && m.fmime.startsWith("image/") ){ |
| 237 | let img = document.createElement("img"); |
| 238 | img.src = "%string($downloadurl)/" + m.msgid; |
| 239 | span.appendChild(img); |
| @@ -255,15 +294,10 @@ | |
| 255 | if( m.xfrom!=_me ){ |
| 256 | span.classList.add('chat-mx'); |
| 257 | }else{ |
| 258 | span.classList.add('chat-ms'); |
| 259 | } |
| 260 | td = document.createElement("td"); |
| 261 | r.appendChild(td); |
| 262 | if( m.xfrom==_me ){ |
| 263 | td.appendChild(document.createTextNode('me')) |
| 264 | } |
| 265 | } |
| 266 | } |
| 267 | async function poll(){ |
| 268 | if(poll.running) return; |
| 269 | poll.running = true; |
| 270 |
| --- tools/chat.tcl | |
| +++ tools/chat.tcl | |
| @@ -48,40 +48,19 @@ | |
| 48 | <span>File:</span> |
| 49 | <input type="file" name="file"> |
| 50 | </div> |
| 51 | </div> |
| 52 | </form> |
| 53 | <hr> |
| 54 | <span id='message-inject-point'></span> |
| 55 | |
| 56 | </div><!-- .fossil-doc --> |
| 57 | <hr> |
| 58 | <p> |
| 59 | <a href="chat/env">CGI environment</a> | |
| 60 | <a href="chat/self">Wapp script</a> |
| 61 | <style> |
| 62 | \#dialog { |
| 63 | width: 97%; |
| 64 | } |
| 65 | \#chat-input-area { |
| 66 | width: 100%; |
| @@ -110,10 +89,57 @@ | |
| 89 | flex: 1 0 auto; |
| 90 | } |
| 91 | span.at-name { /* for @USERNAME references */ |
| 92 | text-decoration: underline; |
| 93 | font-weight: bold; |
| 94 | } |
| 95 | /* A wrapper for a single single message (one row of the UI) */ |
| 96 | .message-row { |
| 97 | margin-bottom: 0.5em; |
| 98 | border: none; |
| 99 | display: flex; |
| 100 | flex-direction: row; |
| 101 | justify-content: flex-start; |
| 102 | /*border: 1px solid rgba(0,0,0,0.2); |
| 103 | border-radius: 0.25em; |
| 104 | box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29);*/ |
| 105 | border: none; |
| 106 | } |
| 107 | /* Rows for the current user have the .user-is-me CSS class |
| 108 | and get right-aligned. */ |
| 109 | .message-row.user-is-me { |
| 110 | justify-content: flex-end; |
| 111 | /*background-color: #d2dde1;*/ |
| 112 | } |
| 113 | /* The content area of a message (the body element of a FIELDSET) */ |
| 114 | .message-content { |
| 115 | display: inline-block; |
| 116 | border-radius: 0.25em; |
| 117 | border: 1px solid rgba(0,0,0,0.2); |
| 118 | box-shadow: 0.2em 0.2em 0.2em rgba(0, 0, 0, 0.29); |
| 119 | padding: 0.25em 1em; |
| 120 | margin-top: -0.75em; |
| 121 | } |
| 122 | .message-row.user-is-me .message-content { |
| 123 | background-color: #d2dde1; |
| 124 | } |
| 125 | /* User name for the post (a LEGEND element) */ |
| 126 | .message-row .message-user { |
| 127 | background: inherit; |
| 128 | border-radius: 0.25em 0.25em 0 0; |
| 129 | padding: 0 0.5em; |
| 130 | /*text-align: left; Firefox requires the 'align' attribute */ |
| 131 | margin-left: 0.25em; |
| 132 | padding: 0 0.5em 0em 0.5em; |
| 133 | margin-bottom: 0.4em; |
| 134 | background-color: #d2dde1; |
| 135 | } |
| 136 | /* Reposition "my" posts to the right */ |
| 137 | .message-row.user-is-me .message-user { |
| 138 | /*text-align: right; Firefox requires the 'align' attribute */ |
| 139 | margin-left: 0; |
| 140 | margin-right: 0.25em; |
| 141 | } |
| 142 | </style> |
| 143 | } |
| 144 | set nonce [wapp-param FOSSIL_NONCE] |
| 145 | set submiturl [wapp-param SCRIPT_NAME]/send |
| @@ -213,27 +239,40 @@ | |
| 239 | span.appendChild(e); |
| 240 | }); |
| 241 | //console.debug("span =",span.innerHTML); |
| 242 | return span; |
| 243 | }/*end messageToDOM()*/; |
| 244 | const injectMessage = function f(e){ |
| 245 | if(!f.injectPoint){ |
| 246 | f.injectPoint = document.querySelector('#message-inject-point'); |
| 247 | } |
| 248 | f.injectPoint.parentNode.insertBefore(e, f.injectPoint.nextSibling); |
| 249 | }; |
| 250 | function newcontent(jx){ |
| 251 | var i; |
| 252 | for(i=0; i<jx.msgs.length; ++i){ |
| 253 | let m = jx.msgs[i]; |
| 254 | let row = document.createElement("fieldset"); |
| 255 | if( m.msgid>mxMsg ) mxMsg = m.msgid; |
| 256 | row.classList.add('message-row'); |
| 257 | injectMessage(row); |
| 258 | const eWho = document.createElement('legend'); |
| 259 | eWho.setAttribute('align', (m.xfrom===_me ? 'right' : 'left')); |
| 260 | row.appendChild(eWho); |
| 261 | eWho.classList.add('message-user'); |
| 262 | let whoName; |
| 263 | if( m.xfrom===_me ){ |
| 264 | whoName = 'me'; |
| 265 | //eWho.classList.add('user-is-me'); |
| 266 | row.classList.add('user-is-me'); |
| 267 | }else{ |
| 268 | whoName = m.xfrom; |
| 269 | } |
| 270 | eWho.append(document.createTextNode(whoName)); |
| 271 | let span = document.createElement("div"); |
| 272 | span.classList.add('message-content'); |
| 273 | row.appendChild(span); |
| 274 | if( m.fsize>0 ){ |
| 275 | if( m.fmime && m.fmime.startsWith("image/") ){ |
| 276 | let img = document.createElement("img"); |
| 277 | img.src = "%string($downloadurl)/" + m.msgid; |
| 278 | span.appendChild(img); |
| @@ -255,15 +294,10 @@ | |
| 294 | if( m.xfrom!=_me ){ |
| 295 | span.classList.add('chat-mx'); |
| 296 | }else{ |
| 297 | span.classList.add('chat-ms'); |
| 298 | } |
| 299 | } |
| 300 | } |
| 301 | async function poll(){ |
| 302 | if(poll.running) return; |
| 303 | poll.running = true; |
| 304 |