@@ -31,8 +31,18 @@ import { useIFrameContext } from "@cocalc/frontend/jupyter/cell-list";
31
31
import { sha1 } from "@cocalc/util/misc" ;
32
32
import TTL from "@isaacs/ttlcache" ;
33
33
34
+ // AFter this many seconds, an element that hasn't been in the react dom and whose
35
+ // parent hasn't been scrolled, will get un-rendered.
34
36
const IDLE_TIMEOUT_S = 10 * 60 ; // 10 minutes
37
+ // If there are more than this many elements, old ones are un-rendered.
35
38
const MAX_ELEMENTS = 500 ; // max items
39
+ // Rough assumption about size of scrollbar.
40
+ const SCROLL_WIDTH = 30 ;
41
+ // we have to put the html on top of the notebook to be visible. This is the z-index we use.
42
+ const Z_INDEX = 1 ;
43
+ // no matter what when the html is in the REACT dom, it will have its position updated this frequently.
44
+ // it also gets updated on scroll of the cell list.
45
+ const POSITION_WHEN_MOUNTED_INTERVAL_MS = 500 ;
36
46
37
47
const cache = new TTL < string , any > ( {
38
48
ttl : IDLE_TIMEOUT_S * 1000 ,
@@ -43,11 +53,6 @@ const cache = new TTL<string, any>({
43
53
elt . remove ( ) ;
44
54
} ,
45
55
} ) ;
46
- // const cache: { [globalKey: string]: any } = {};
47
-
48
- const Z_INDEX = 1 ;
49
-
50
- const SCROLL_COUNT = 25 ;
51
56
52
57
// make it really standout:
53
58
// const PADDING = 5;
@@ -110,9 +115,9 @@ export default function StableUnsafeHtml({
110
115
divRef . current . style . height = `${
111
116
eltRect . bottom - eltRect . top + 2 * PADDING
112
117
} px`;
113
- divRef . current . style . width = `${
114
- eltRect . right - eltRect . left + 2 * PADDING
115
- } px`;
118
+ // divRef.current.style.width = `${
119
+ // eltRect.right - eltRect.left + 2 * PADDING
120
+ // }px`;
116
121
117
122
// clip our immortal html so it isn't visible outside the parent
118
123
const parent = $ ( iframeContext . cellListDivRef ?. current ) [ 0 ] ;
@@ -123,26 +128,29 @@ export default function StableUnsafeHtml({
123
128
// leave 30px on right so to not block scrollbar
124
129
const right = Math . min (
125
130
eltRect . width ,
126
- parentRect . right - 30 - eltRect . left ,
131
+ parentRect . right - SCROLL_WIDTH - eltRect . left ,
127
132
) ;
128
133
const bottom = Math . min ( eltRect . height , parentRect . bottom - eltRect . top ) ;
129
134
const left = Math . max ( 0 , parentRect . left - eltRect . left ) ;
130
135
131
136
// Apply clip-path to elt to make it visible only inside of parentRect:
132
137
elt . style . clipPath = `polygon(${ left } px ${ top } px, ${ right } px ${ top } px, ${ right } px ${ bottom } px, ${ left } px ${ bottom } px)` ;
133
138
139
+ // Set widht, so it possible to scroll horizontally and see whatever widget is in the output.
140
+ const w = $ ( divRef . current ) . width ( ) ;
141
+ if ( w ) {
142
+ elt . style . width = `${ w } px` ;
143
+ }
144
+
134
145
// if its an iframe resize it
135
146
if ( html . toLowerCase ( ) . startsWith ( "<iframe" ) ) {
136
147
const iframe = jElt . find ( "iframe" ) ;
137
148
if ( iframe . length > 0 ) {
138
149
var iframeBody = iframe . contents ( ) . find ( "body" ) ;
139
150
if ( iframeBody . length > 0 ) {
140
151
// Get dimensions of the iframe's body
141
- //const width = iframeBody.outerWidth();
142
152
const height = iframeBody . outerHeight ( ) ;
143
- //iframe[0].style.width = `${width}px`;
144
153
iframe [ 0 ] . style . height = `${ height } px` ;
145
- iframeBody [ 0 ] . style [ "overflow-y" ] = "hidden" ;
146
154
}
147
155
}
148
156
}
@@ -152,7 +160,7 @@ export default function StableUnsafeHtml({
152
160
const getElt = ( ) => {
153
161
if ( ! cache . has ( globalKey ) ) {
154
162
const elt = $ (
155
- `<div id="${ globalKey } " style="border:0;position:absolute;overflow-y:hidden ;z-index:${ zIndex } "/>${ html } </div>` ,
163
+ `<div id="${ globalKey } " style="border:0;position:absolute;overflow:auto ;z-index:${ zIndex } "/>${ html } </div>` ,
156
164
) ;
157
165
// @ts -ignore
158
166
elt . process_smc_links ( ) ;
@@ -191,27 +199,19 @@ export default function StableUnsafeHtml({
191
199
useEffect ( ( ) => {
192
200
// TOOD: can we get rid of interval by using a resize observer on
193
201
// this iframeContext.cellListDivRef?
194
- intervalRef . current = setInterval ( position , 500 ) ;
202
+ intervalRef . current = setInterval (
203
+ position ,
204
+ POSITION_WHEN_MOUNTED_INTERVAL_MS ,
205
+ ) ;
195
206
if ( iframeContext . iframeOnScrolls != null ) {
196
- let count = 0 ;
197
207
iframeContext . iframeOnScrolls [ globalKey ] = async ( ) => {
198
- // We run position a lot whenever there is a scroll
199
- // in order to make it so the iframe doesn't appear
200
- // to just get "dragged along" nearly as much, as
201
- // onScroll is throttled.
202
- count = SCROLL_COUNT ;
203
- while ( count > 0 ) {
204
- position ( ) ;
205
- await new Promise ( requestAnimationFrame ) ;
206
- count -= 1 ;
207
- }
208
- // throw in an update when we're done.
208
+ position ( ) ;
209
+ await new Promise ( requestAnimationFrame ) ;
209
210
position ( ) ;
210
211
} ;
211
212
}
212
213
position ( ) ;
213
214
setTimeout ( position , 0 ) ;
214
- setTimeout ( position , 5 ) ;
215
215
216
216
return ( ) => {
217
217
delete iframeContext . iframeOnScrolls ?. [ globalKey ] ;
0 commit comments