| | @@ -1,10 +1,10 @@ |
| 1 | 1 | (function(){ |
| 2 | 2 | const form = document.querySelector('#chat-form'); |
| 3 | 3 | let mxMsg = 0; |
| 4 | | - // let _me = "%string($me)"; |
| 5 | | - let me = window.fossil.user.name; |
| 4 | + const F = window.fossil; |
| 5 | + const _me = F.user.name; |
| 6 | 6 | form.addEventListener('submit',(e)=>{ |
| 7 | 7 | e.preventDefault(); |
| 8 | 8 | if( form.msg.value.length>0 || form.file.value.length>0 ){ |
| 9 | 9 | fetch("chat-send",{ |
| 10 | 10 | method: 'POST', |
| | @@ -39,19 +39,64 @@ |
| 39 | 39 | '-',ff.pad(d.getDate()), |
| 40 | 40 | ' ',ff.pad(d.getHours()),':',ff.pad(d.getMinutes()), |
| 41 | 41 | ':',ff.pad(d.getSeconds()) |
| 42 | 42 | ].join(''); |
| 43 | 43 | }; |
| 44 | + /* Returns an almost-ISO8601 form of Date object d. */ |
| 45 | + const iso8601ish = function(d){ |
| 46 | + return d.toISOString() |
| 47 | + .replace('T',' ').replace(/\.\d+/,'').replace('Z', ' GMT'); |
| 48 | + }; |
| 49 | + /* Timestampt popup widget */ |
| 50 | + const tsPopup = new F.PopupWidget({ |
| 51 | + cssClass: ['fossil-tooltip', 'chat-timestamp'], |
| 52 | + refresh:function(){ |
| 53 | + const D = F.dom; |
| 54 | + D.clearElement(this.e); |
| 55 | + const d = new Date(this._timestamp+"Z"); |
| 56 | + if(d.getMinutes().toString()!=="NaN"){ |
| 57 | + // Date works, render informative timestamps |
| 58 | + D.append(this.e, localTimeString(d)," client-local", D.br(), |
| 59 | + iso8601ish(d)); |
| 60 | + }else{ |
| 61 | + // Date doesn't work, so dumb it down... |
| 62 | + D.append(this.e, this._timestamp," GMT"); |
| 63 | + } |
| 64 | + } |
| 65 | + }); |
| 66 | + const hidePopup = ()=>tsPopup.hide(); |
| 67 | + tsPopup.e.addEventListener('click', hidePopup, false); |
| 68 | + document.body.addEventListener('click', hidePopup, true); |
| 69 | + document.body.addEventListener('keydown', function(ev){ |
| 70 | + if(tsPopup.isShown() && 27===ev.which) tsPopup.hide(); |
| 71 | + }, true); |
| 72 | + /* Event handler for clicking .message-user elements to show their |
| 73 | + timestamps. */ |
| 74 | + const handleLegendClicked = function(ev){ |
| 75 | + const rect = ev.target.getBoundingClientRect(); |
| 76 | + tsPopup._timestamp = ev.target.dataset.timestamp; |
| 77 | + let x = rect.left, y = rect.top - 10; |
| 78 | + tsPopup.show(ev.target)/*so we can get its computed size*/; |
| 79 | + // Shift to the left for right-aligned messages |
| 80 | + if('right'===ev.target.getAttribute('align')){ |
| 81 | + const pRect = tsPopup.e.getBoundingClientRect(); |
| 82 | + x -= pRect.width/3*2; |
| 83 | + } |
| 84 | + tsPopup.show(x, y); |
| 85 | + }; |
| 86 | + |
| 44 | 87 | function newcontent(jx){ |
| 45 | 88 | var i; |
| 46 | 89 | for(i=0; i<jx.msgs.length; ++i){ |
| 47 | 90 | let m = jx.msgs[i]; |
| 48 | 91 | let row = document.createElement("fieldset"); |
| 49 | 92 | if( m.msgid>mxMsg ) mxMsg = m.msgid; |
| 50 | 93 | row.classList.add('message-row'); |
| 51 | 94 | injectMessage(row); |
| 52 | 95 | const eWho = document.createElement('legend'); |
| 96 | + eWho.dataset.timestamp = m.mtime; |
| 97 | + eWho.addEventListener('click', handleLegendClicked, false); |
| 53 | 98 | eWho.setAttribute('align', (m.xfrom===_me ? 'right' : 'left')); |
| 54 | 99 | eWho.style.backgroundColor = m.uclr; |
| 55 | 100 | row.appendChild(eWho); |
| 56 | 101 | eWho.classList.add('message-user'); |
| 57 | 102 | let whoName; |
| | @@ -61,17 +106,10 @@ |
| 61 | 106 | }else{ |
| 62 | 107 | whoName = m.xfrom; |
| 63 | 108 | } |
| 64 | 109 | var d = new Date(m.mtime + "Z"); |
| 65 | 110 | if( d.getMinutes().toString()!="NaN" ){ |
| 66 | | - eWho.setAttribute('title',localTimeString(d) |
| 67 | | - +' client-local\n' |
| 68 | | - +d.toISOString() |
| 69 | | - .replace('T',' ') |
| 70 | | - .replace(/\.\d+/,'') |
| 71 | | - .replace('Z', ' GMT') |
| 72 | | - ); |
| 73 | 111 | /* Show local time when we can compute it */ |
| 74 | 112 | eWho.append(textNode(whoName+' @ '+ |
| 75 | 113 | d.getHours()+":"+(d.getMinutes()+100).toString().slice(1,3) |
| 76 | 114 | )) |
| 77 | 115 | }else{ |
| 78 | 116 | |