Fossil SCM

/chat: be more restrictive in what mimetypes we enable embedding for because loading an iframe with an arbitrary mimetype might force the browser to prompt to download the content. Leave the Embed toggle enabled, even during loading, to avoid that such a download prompt leaves the toggle permanently disabled. That latter bit required some refactoring of the auto-iframe-resize to account for toggling while the content is still in transit.

stephan 2022-01-01 23:09 trunk
Commit 0423fb8d7b2a6423cc50799f816a7695130b526e0028814c3d7f685441cbe2a2
1 file changed +43 -17
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -894,18 +894,46 @@
894894
};
895895
896896
const canEmbedFile = function f(msg){
897897
if(!f.$rx){
898898
f.$rx = /\.((html?)|(txt))$/i;
899
+ f.$specificTypes = [
900
+ 'text/plain',
901
+ 'text/html'
902
+ // add more as we discover which ones Firefox won't
903
+ // force the user to try to download.
904
+ ];
899905
}
900906
if(msg.fmime){
901
- return (msg.fmime.startsWith("text/")
902
- || msg.fmime.startsWith("image/"));
907
+ return (msg.fmime.startsWith("image/")
908
+ || f.$specificTypes.indexOf(msg.fmime)>=0);
903909
}
904910
return msg.fname && f.$rx.test(msg.fname);
905911
};
906912
913
+ const adjustIFrameSize = function(msgObj){
914
+ const iframe = msgObj.e.iframe;
915
+ const body = iframe.contentWindow.document.querySelector('body');
916
+ if(body && !body.style.fontSize){
917
+ /** _Attempt_ to force the iframe to inherit the message's text size
918
+ if the body has no explicit size set. On desktop systems
919
+ the size is apparently being inherited in that case, but on mobile
920
+ not. */
921
+ body.style.fontSize = window.getComputedStyle(msgObj.e.content);
922
+ }
923
+ if('' === iframe.style.maxHeight){
924
+ /* Resize iframe height to fit the content. Workaround: if we
925
+ adjust the iframe height while it's hidden then its height
926
+ is 0, so we must briefly unhide it. */
927
+ const isHidden = iframe.classList.contains('hidden');
928
+ if(isHidden) D.removeClass(iframe, 'hidden');
929
+ iframe.style.maxHeight = iframe.style.height
930
+ = iframe.contentWindow.document.documentElement.scrollHeight + 'px';
931
+ if(isHidden) D.addClass(iframe, 'hidden');
932
+ }
933
+ };
934
+
907935
cf.prototype = {
908936
scrollIntoView: function(){
909937
this.e.content.scrollIntoView();
910938
},
911939
setMessage: function(m){
@@ -969,32 +997,30 @@
969997
const embedTarget = this.e.content;
970998
const self = this;
971999
const btnEmbed = D.attr(D.checkbox("1", false), 'id',
9721000
'embed-'+ds.msgid);
9731001
const btnLabel = D.label(btnEmbed, "Embed");
1002
+ /* Maintenance reminder: do not disable the toggle
1003
+ button while the content is loading because that will
1004
+ cause it to get stuck in disabled mode if the browser
1005
+ decides that loading the content should prompt the
1006
+ user to download it, rather than embed it in the
1007
+ iframe. */
9741008
btnEmbed.addEventListener('change',function(){
9751009
if(self.e.iframe){
976
- if(btnEmbed.checked) D.removeClass(self.e.iframe, 'hidden');
1010
+ if(btnEmbed.checked){
1011
+ D.removeClass(self.e.iframe, 'hidden');
1012
+ if(self.e.$iframeLoaded) adjustIFrameSize(self);
1013
+ }
9771014
else D.addClass(self.e.iframe, 'hidden');
9781015
return;
9791016
}
980
- D.disable(btnEmbed);
9811017
const iframe = self.e.iframe = document.createElement('iframe');
982
- D.append(embedTarget, iframe);
1018
+ D.append(embedTarget, iframe);
9831019
iframe.addEventListener('load', function(){
984
- D.enable(btnEmbed);
985
- const body = iframe.contentWindow.document.querySelector('body');
986
- if(body && !body.style.fontSize){
987
- /** _Attempt_ to force the iframe to inherit the message's text size
988
- if the body has no explicit size set. On desktop systems
989
- the size is apparently being inherited in that case, but on mobile
990
- not. */
991
- const cs = window.getComputedStyle(self.e.content);
992
- body.style.fontSize = cs.fontSize;
993
- }
994
- iframe.style.maxHeight = iframe.style.height
995
- = iframe.contentWindow.document.documentElement.scrollHeight + 'px';
1020
+ self.e.$iframeLoaded = true;
1021
+ adjustIFrameSize(self);
9961022
});
9971023
iframe.setAttribute('src', downloadUri);
9981024
});
9991025
D.append(w, btnEmbed, btnLabel);
10001026
}
10011027
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -894,18 +894,46 @@
894 };
895
896 const canEmbedFile = function f(msg){
897 if(!f.$rx){
898 f.$rx = /\.((html?)|(txt))$/i;
 
 
 
 
 
 
899 }
900 if(msg.fmime){
901 return (msg.fmime.startsWith("text/")
902 || msg.fmime.startsWith("image/"));
903 }
904 return msg.fname && f.$rx.test(msg.fname);
905 };
906
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
907 cf.prototype = {
908 scrollIntoView: function(){
909 this.e.content.scrollIntoView();
910 },
911 setMessage: function(m){
@@ -969,32 +997,30 @@
969 const embedTarget = this.e.content;
970 const self = this;
971 const btnEmbed = D.attr(D.checkbox("1", false), 'id',
972 'embed-'+ds.msgid);
973 const btnLabel = D.label(btnEmbed, "Embed");
 
 
 
 
 
 
974 btnEmbed.addEventListener('change',function(){
975 if(self.e.iframe){
976 if(btnEmbed.checked) D.removeClass(self.e.iframe, 'hidden');
 
 
 
977 else D.addClass(self.e.iframe, 'hidden');
978 return;
979 }
980 D.disable(btnEmbed);
981 const iframe = self.e.iframe = document.createElement('iframe');
982 D.append(embedTarget, iframe);
983 iframe.addEventListener('load', function(){
984 D.enable(btnEmbed);
985 const body = iframe.contentWindow.document.querySelector('body');
986 if(body && !body.style.fontSize){
987 /** _Attempt_ to force the iframe to inherit the message's text size
988 if the body has no explicit size set. On desktop systems
989 the size is apparently being inherited in that case, but on mobile
990 not. */
991 const cs = window.getComputedStyle(self.e.content);
992 body.style.fontSize = cs.fontSize;
993 }
994 iframe.style.maxHeight = iframe.style.height
995 = iframe.contentWindow.document.documentElement.scrollHeight + 'px';
996 });
997 iframe.setAttribute('src', downloadUri);
998 });
999 D.append(w, btnEmbed, btnLabel);
1000 }
1001
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -894,18 +894,46 @@
894 };
895
896 const canEmbedFile = function f(msg){
897 if(!f.$rx){
898 f.$rx = /\.((html?)|(txt))$/i;
899 f.$specificTypes = [
900 'text/plain',
901 'text/html'
902 // add more as we discover which ones Firefox won't
903 // force the user to try to download.
904 ];
905 }
906 if(msg.fmime){
907 return (msg.fmime.startsWith("image/")
908 || f.$specificTypes.indexOf(msg.fmime)>=0);
909 }
910 return msg.fname && f.$rx.test(msg.fname);
911 };
912
913 const adjustIFrameSize = function(msgObj){
914 const iframe = msgObj.e.iframe;
915 const body = iframe.contentWindow.document.querySelector('body');
916 if(body && !body.style.fontSize){
917 /** _Attempt_ to force the iframe to inherit the message's text size
918 if the body has no explicit size set. On desktop systems
919 the size is apparently being inherited in that case, but on mobile
920 not. */
921 body.style.fontSize = window.getComputedStyle(msgObj.e.content);
922 }
923 if('' === iframe.style.maxHeight){
924 /* Resize iframe height to fit the content. Workaround: if we
925 adjust the iframe height while it's hidden then its height
926 is 0, so we must briefly unhide it. */
927 const isHidden = iframe.classList.contains('hidden');
928 if(isHidden) D.removeClass(iframe, 'hidden');
929 iframe.style.maxHeight = iframe.style.height
930 = iframe.contentWindow.document.documentElement.scrollHeight + 'px';
931 if(isHidden) D.addClass(iframe, 'hidden');
932 }
933 };
934
935 cf.prototype = {
936 scrollIntoView: function(){
937 this.e.content.scrollIntoView();
938 },
939 setMessage: function(m){
@@ -969,32 +997,30 @@
997 const embedTarget = this.e.content;
998 const self = this;
999 const btnEmbed = D.attr(D.checkbox("1", false), 'id',
1000 'embed-'+ds.msgid);
1001 const btnLabel = D.label(btnEmbed, "Embed");
1002 /* Maintenance reminder: do not disable the toggle
1003 button while the content is loading because that will
1004 cause it to get stuck in disabled mode if the browser
1005 decides that loading the content should prompt the
1006 user to download it, rather than embed it in the
1007 iframe. */
1008 btnEmbed.addEventListener('change',function(){
1009 if(self.e.iframe){
1010 if(btnEmbed.checked){
1011 D.removeClass(self.e.iframe, 'hidden');
1012 if(self.e.$iframeLoaded) adjustIFrameSize(self);
1013 }
1014 else D.addClass(self.e.iframe, 'hidden');
1015 return;
1016 }
 
1017 const iframe = self.e.iframe = document.createElement('iframe');
1018 D.append(embedTarget, iframe);
1019 iframe.addEventListener('load', function(){
1020 self.e.$iframeLoaded = true;
1021 adjustIFrameSize(self);
 
 
 
 
 
 
 
 
 
 
1022 });
1023 iframe.setAttribute('src', downloadUri);
1024 });
1025 D.append(w, btnEmbed, btnLabel);
1026 }
1027

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button