Fossil

Check-in [0101325f9d]
Login

Check-in [0101325f9d]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Chat message precise timestamps are now shown via a tap/click popup, rather than hoverhelp, for mobile compatibility.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | chatroom-dev
Files: files | file ages | folders
SHA3-256: 0101325f9dcc55cbc8eb871cc1d855642fc3bfc548daa32b1b9a674cec36b9fd
User & Date: stephan 2020-12-23 06:26:40.872
Context
2020-12-23
07:09
Implemented paste image into chat from clipboard. Fixed posted file download link but the files download with the same name as their message ID, which isn't very friendly. Not sure how to resolve that bit. ... (check-in: eb7845f339 user: stephan tags: chatroom-dev)
06:26
Chat message precise timestamps are now shown via a tap/click popup, rather than hoverhelp, for mobile compatibility. ... (check-in: 0101325f9d user: stephan tags: chatroom-dev)
05:44
Import fossil bootstrapping JS into the chat app, add current login name to window.fossil.user.name, and use that name as the initial 'me' value in chat.js (resolves the FIXME in that latter part). ... (check-in: 4e832e9f40 user: stephan tags: chatroom-dev)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/chat.c.
85
86
87
88
89
90
91







92
93
94
95
96
97
98
  @   display: flex;
  @   flex-direction: row;
  @   align-items: center;
  @ }
  @ #chat-input-file > input {
  @   flex: 1 0 auto;
  @ }







  @ </style>
  @ <form accept-encoding="utf-8" id="chat-form">
  @ <div id='chat-input-area'>
  @   <div id='chat-input-line'>
  @     <input type="text" name="msg" id="sbox"\
  @      placeholder="Type message here.">
  @     <input type="submit" value="Send">







>
>
>
>
>
>
>







85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  @   display: flex;
  @   flex-direction: row;
  @   align-items: center;
  @ }
  @ #chat-input-file > input {
  @   flex: 1 0 auto;
  @ }
  @ .chat-timestamp {
  @    font-family: monospace;
  @    font-size: 0.8em;
  @    white-space: pre;
  @    text-align: left;
  @    opacity: 0.8;
  @ }
  @ </style>
  @ <form accept-encoding="utf-8" id="chat-form">
  @ <div id='chat-input-area'>
  @   <div id='chat-input-line'>
  @     <input type="text" name="msg" id="sbox"\
  @      placeholder="Type message here.">
  @     <input type="submit" value="Send">
107
108
109
110
111
112
113
114


115

116
117
118
119
120
121
122

  /* New chat messages get inserted immediately after this element */
  @ <span id='message-inject-point'></span>

  builtin_fossil_js_bundle_or("popupwidget", NULL);
  /* Always in-line the javascript for the chat page */
  @ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
  @ let _me = "%j(g.zLogin)";


  cgi_append_content(builtin_text("chat.js"),-1);

  @ </script>

  style_finish_page();
}

/* Definition of repository tables used by chat
*/







|
>
>

>







114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

  /* New chat messages get inserted immediately after this element */
  @ <span id='message-inject-point'></span>

  builtin_fossil_js_bundle_or("popupwidget", NULL);
  /* Always in-line the javascript for the chat page */
  @ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
  @ window.addEventListener('load', function(){
  /* We need an onload handler to ensure that window.fossil is
     loaded first. */
  cgi_append_content(builtin_text("chat.js"),-1);
  @ }, false);
  @ </script>

  style_finish_page();
}

/* Definition of repository tables used by chat
*/
Changes to src/chat.js.
1
2
3
4
5

6
7
8
9
10
11
12
(function(){
  const form = document.querySelector('#chat-form');
  let mxMsg = 0;
  // let _me = "%string($me)";
  let me = window.fossil.user.name;

  form.addEventListener('submit',(e)=>{
    e.preventDefault();
    if( form.msg.value.length>0 || form.file.value.length>0 ){
      fetch("chat-send",{
        method: 'POST',
        body: new FormData(form)
      });



<
|
>







1
2
3

4
5
6
7
8
9
10
11
12
(function(){
  const form = document.querySelector('#chat-form');
  let mxMsg = 0;

  const F = window.fossil;
  const _me = F.user.name;
  form.addEventListener('submit',(e)=>{
    e.preventDefault();
    if( form.msg.value.length>0 || form.file.value.length>0 ){
      fetch("chat-send",{
        method: 'POST',
        body: new FormData(form)
      });
37
38
39
40
41
42
43











































44
45
46
47
48
49
50
51
52


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
    return [
      d.getFullYear(),'-',ff.pad(d.getMonth()+1/*sigh*/),
      '-',ff.pad(d.getDate()),
      ' ',ff.pad(d.getHours()),':',ff.pad(d.getMinutes()),
      ':',ff.pad(d.getSeconds())
    ].join('');
  };











































  function newcontent(jx){
    var i;
    for(i=0; i<jx.msgs.length; ++i){
      let m = jx.msgs[i];
      let row = document.createElement("fieldset");
      if( m.msgid>mxMsg ) mxMsg = m.msgid;
      row.classList.add('message-row');
      injectMessage(row);
      const eWho = document.createElement('legend');


      eWho.setAttribute('align', (m.xfrom===_me ? 'right' : 'left'));
      eWho.style.backgroundColor = m.uclr;
      row.appendChild(eWho);
      eWho.classList.add('message-user');
      let whoName;
      if( m.xfrom===_me ){
        whoName = 'me';
        row.classList.add('user-is-me');
      }else{
        whoName = m.xfrom;
      }
      var d = new Date(m.mtime + "Z");
      if( d.getMinutes().toString()!="NaN" ){
        eWho.setAttribute('title',localTimeString(d)
                          +' client-local\n'
                          +d.toISOString()
                          .replace('T',' ')
                          .replace(/\.\d+/,'')
                          .replace('Z', ' GMT')
                         );
        /* Show local time when we can compute it */
        eWho.append(textNode(whoName+' @ '+
          d.getHours()+":"+(d.getMinutes()+100).toString().slice(1,3)
        ))
      }else{
        /* Show UTC on systems where Date() does not work */
        eWho.append(textNode(whoName+' @ '+m.mtime.slice(11,16)))







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









>
>













<
<
<
<
<
<
<







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110







111
112
113
114
115
116
117
    return [
      d.getFullYear(),'-',ff.pad(d.getMonth()+1/*sigh*/),
      '-',ff.pad(d.getDate()),
      ' ',ff.pad(d.getHours()),':',ff.pad(d.getMinutes()),
      ':',ff.pad(d.getSeconds())
    ].join('');
  };
  /* Returns an almost-ISO8601 form of Date object d. */
  const iso8601ish = function(d){
    return d.toISOString()
      .replace('T',' ').replace(/\.\d+/,'').replace('Z', ' GMT');
  };
  /* Timestampt popup widget */
  const tsPopup = new F.PopupWidget({
    cssClass: ['fossil-tooltip', 'chat-timestamp'],
    refresh:function(){
      const D = F.dom;
      D.clearElement(this.e);
      const d = new Date(this._timestamp+"Z");
      if(d.getMinutes().toString()!=="NaN"){
        // Date works, render informative timestamps
        D.append(this.e, localTimeString(d)," client-local", D.br(),
                 iso8601ish(d));
      }else{
        // Date doesn't work, so dumb it down...
        D.append(this.e, this._timestamp," GMT");
      }
    }
  });
  const hidePopup = ()=>tsPopup.hide();
  tsPopup.e.addEventListener('click', hidePopup, false);
  document.body.addEventListener('click', hidePopup, true);
  document.body.addEventListener('keydown', function(ev){
    if(tsPopup.isShown() && 27===ev.which) tsPopup.hide();
  }, true);
  /* Event handler for clicking .message-user elements to show their
     timestamps. */
  const handleLegendClicked = function(ev){
    const rect = ev.target.getBoundingClientRect();
    tsPopup._timestamp = ev.target.dataset.timestamp;
    let x = rect.left, y = rect.top - 10;
    tsPopup.show(ev.target)/*so we can get its computed size*/;
    // Shift to the left for right-aligned messages
    if('right'===ev.target.getAttribute('align')){
      const pRect = tsPopup.e.getBoundingClientRect();
      x -= pRect.width/3*2;
    }
    tsPopup.show(x, y);
  };

  function newcontent(jx){
    var i;
    for(i=0; i<jx.msgs.length; ++i){
      let m = jx.msgs[i];
      let row = document.createElement("fieldset");
      if( m.msgid>mxMsg ) mxMsg = m.msgid;
      row.classList.add('message-row');
      injectMessage(row);
      const eWho = document.createElement('legend');
      eWho.dataset.timestamp = m.mtime;
      eWho.addEventListener('click', handleLegendClicked, false);
      eWho.setAttribute('align', (m.xfrom===_me ? 'right' : 'left'));
      eWho.style.backgroundColor = m.uclr;
      row.appendChild(eWho);
      eWho.classList.add('message-user');
      let whoName;
      if( m.xfrom===_me ){
        whoName = 'me';
        row.classList.add('user-is-me');
      }else{
        whoName = m.xfrom;
      }
      var d = new Date(m.mtime + "Z");
      if( d.getMinutes().toString()!="NaN" ){







        /* Show local time when we can compute it */
        eWho.append(textNode(whoName+' @ '+
          d.getHours()+":"+(d.getMinutes()+100).toString().slice(1,3)
        ))
      }else{
        /* Show UTC on systems where Date() does not work */
        eWho.append(textNode(whoName+' @ '+m.mtime.slice(11,16)))
Changes to src/default.css.
1500
1501
1502
1503
1504
1505
1506

1507
1508
1509
1510
1511
1512
1513
.message-row .message-user {
  border-radius: 0.25em 0.25em 0 0;
  padding: 0 0.5em;
  /*text-align: left; Firefox requires the 'align' attribute */
  margin-left: 0.15em;
  padding: 0 0.5em 0em 0.5em;
  margin-bottom: 0.4em;

}
/* Reposition "my" posts to the right */
.message-row.user-is-me .message-user {
  /*text-align: right; Firefox requires the 'align' attribute */
  margin-left: 0;
  margin-right: 0.25em;
}







>







1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
.message-row .message-user {
  border-radius: 0.25em 0.25em 0 0;
  padding: 0 0.5em;
  /*text-align: left; Firefox requires the 'align' attribute */
  margin-left: 0.15em;
  padding: 0 0.5em 0em 0.5em;
  margin-bottom: 0.4em;
  cursor: pointer;
}
/* Reposition "my" posts to the right */
.message-row.user-is-me .message-user {
  /*text-align: right; Firefox requires the 'align' attribute */
  margin-left: 0;
  margin-right: 0.25em;
}