14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
const Chat = (function(){
const cs = {
e:{/*map of certain DOM elements.*/
messageInjectPoint: E1('#message-inject-point'),
pageTitle: E1('head title'),
loadOlderToolbar: undefined /* the load-posts toolbar (dynamically created) */,
inputWrapper: E1("#chat-input-area"),
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
const ForceResizeKludge = 0 ? function(){} : (function(){
/* Workaround for Safari mayhem regarding use of vh CSS units....
We tried to use vh units to set the content area size for the
chat layout, but Safari chokes on that, so we calculate that
height here: 85% when in "normal" mode and 95% in chat-only
mode. Larger than ~95% is too big for Firefox on Android,
causing the input area to move off-screen. */
const contentArea = E1('div.content'),
bcl = document.body.classList;
const resized = function(){
const wh = window.innerHeight,
mult = bcl.contains('chat-only-mode') ? 0.95 : 0.85;
contentArea.style.maxHeight = (wh * mult)+"px";
console.debug("resized.",wh, mult, window.getComputedStyle(contentArea).maxHeight);
};
var doit;
window.addEventListener('resize',function(ev){
clearTimeout(doit);
doit = setTimeout(resized, 100);
}, false);
resized();
return resized;
})();
const Chat = (function(){
const cs = {
e:{/*map of certain DOM elements.*/
messageInjectPoint: E1('#message-inject-point'),
pageTitle: E1('head title'),
loadOlderToolbar: undefined /* the load-posts toolbar (dynamically created) */,
inputWrapper: E1("#chat-input-area"),
|
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
to avoid various race conditions in the UI and long-running
network requests. */
],
/* Injects element e as a new row in the chat, at the top of the
list if atEnd is falsy, else at the end of the list, before
the load-history widget. */
injectMessageElem: function f(e, atEnd){
const mip = atEnd ? this.e.loadOlderToolbar : this.e.messageInjectPoint,
holder = this.e.messagesWrapper;
if(atEnd){
const fe = mip.nextElementSibling;
if(fe) mip.parentNode.insertBefore(e, fe);
else D.append(mip.parentNode, e);
}else{
D.append(holder,e);
}
if(!atEnd && !this.isMassLoading
&& e.dataset.xfrom!==Chat.me && !isInViewport(e)){
/* If a new non-history message arrives while the user is
scrolled elsewhere, do not scroll to the latest
message, but gently alert the user that a new message
has arrived. */
F.toast.message("New message has arrived.");
}
},
/** Returns true if chat-only mode is enabled. */
isChatOnlyMode: ()=>document.body.classList.contains('chat-only-mode'),
/**
Enters (if passed a truthy value or no arguments) or leaves
"chat-only" mode. That mode hides the page's header and
|
|
>
|
>
>
>
<
<
>
>
|
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
to avoid various race conditions in the UI and long-running
network requests. */
],
/* Injects element e as a new row in the chat, at the top of the
list if atEnd is falsy, else at the end of the list, before
the load-history widget. */
injectMessageElem: function f(e, atEnd){
const mip = atEnd ? this.e.loadOlderToolbar : this.e.messageInjectPoint;
/* Reminder: this placement is kinda odd because of the
flex-direction:column-reverse in this.e.messagesWrapper,
which reverses our directions. */
if(atEnd){
mip.parentNode.insertBefore(e, mip);
}else{
const fe = mip.nextElementSibling;
if(fe) mip.parentNode.insertBefore(e, fe);
else D.append(mip.parentNode, e);
}
if(!atEnd && !this.isMassLoading
&& e.dataset.xfrom!==Chat.me && !isInViewport(e)){
/* If a new non-history message arrives while the user is
scrolled elsewhere, do not scroll to the latest
message, but gently alert the user that a new message
has arrived. */
F.toast.message("New message has arrived.");
}else if(e.dataset.xfrom===Chat.me){
e.scrollIntoView();
}
},
/** Returns true if chat-only mode is enabled. */
isChatOnlyMode: ()=>document.body.classList.contains('chat-only-mode'),
/**
Enters (if passed a truthy value or no arguments) or leaves
"chat-only" mode. That mode hides the page's header and
|
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
document.body.scroll(0,document.body.height);
}else{
D.removeClass(f.elemsToToggle, 'hidden');
D.removeClass(document.body, 'chat-only-mode');
}
const msg = document.querySelector('.message-widget');
if(msg) setTimeout(()=>msg.scrollIntoView(),0);
return this;
},
toggleChatOnlyMode: function(){
return this.chatOnlyMode(!this.isChatOnlyMode());
},
settings:{
get: (k,dflt)=>F.storage.get(k,dflt),
|
>
|
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
document.body.scroll(0,document.body.height);
}else{
D.removeClass(f.elemsToToggle, 'hidden');
D.removeClass(document.body, 'chat-only-mode');
}
const msg = document.querySelector('.message-widget');
if(msg) setTimeout(()=>msg.scrollIntoView(),0);
ForceResizeKludge();
return this;
},
toggleChatOnlyMode: function(){
return this.chatOnlyMode(!this.isChatOnlyMode());
},
settings:{
get: (k,dflt)=>F.storage.get(k,dflt),
|