Fossil SCM

Lots of tweaking to the "help buttonlet" popup position. Something to improve some rainy day.

stephan 2020-08-25 06:18 misc-js-experiments
Commit 3f08a9d200fb9c8b035a96dac2eecb8d61c8585d3c9a8515a5c7183f7562b864
--- src/default.css
+++ src/default.css
@@ -1346,6 +1346,7 @@
13461346
*/
13471347
.fossil-tooltip.help-buttonlet-content {
13481348
cursor: default;
13491349
text-align: left;
13501350
border-style: outset;
1351
+ box-shadow: 0em 0em 0.2em 0.2em rgba(0,0,0,0.40);
13511352
}
13521353
--- src/default.css
+++ src/default.css
@@ -1346,6 +1346,7 @@
1346 */
1347 .fossil-tooltip.help-buttonlet-content {
1348 cursor: default;
1349 text-align: left;
1350 border-style: outset;
 
1351 }
1352
--- src/default.css
+++ src/default.css
@@ -1346,6 +1346,7 @@
1346 */
1347 .fossil-tooltip.help-buttonlet-content {
1348 cursor: default;
1349 text-align: left;
1350 border-style: outset;
1351 box-shadow: 0em 0em 0.2em 0.2em rgba(0,0,0,0.40);
1352 }
1353
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -470,12 +470,12 @@
470470
btnHelp = D.append(
471471
D.addClass(D.div(), "help-buttonlet"),
472472
'Locally-edited files. Timestamps are the last local edit time. ',
473473
'Only the ',P.config.defaultMaxStashSize,' most recent files ',
474474
'are retained. Saving or reloading a file removes it from this list. ',
475
- D.append(D.code(),'localStorage'),' uses browser-local persistent storage. ',
476
- D.append(D.code(),'sessionStorage'),' uses storage local to this browser tab.'
475
+ D.append(D.code(),F.storage.storageImplName()),
476
+ ' = ',F.storage.storageHelpDescription()
477477
);
478478
479479
D.append(wrapper, "Local edits (",
480480
D.append(D.code(),
481481
F.storage.storageImplName()),
482482
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -470,12 +470,12 @@
470 btnHelp = D.append(
471 D.addClass(D.div(), "help-buttonlet"),
472 'Locally-edited files. Timestamps are the last local edit time. ',
473 'Only the ',P.config.defaultMaxStashSize,' most recent files ',
474 'are retained. Saving or reloading a file removes it from this list. ',
475 D.append(D.code(),'localStorage'),' uses browser-local persistent storage. ',
476 D.append(D.code(),'sessionStorage'),' uses storage local to this browser tab.'
477 );
478
479 D.append(wrapper, "Local edits (",
480 D.append(D.code(),
481 F.storage.storageImplName()),
482
--- src/fossil.page.fileedit.js
+++ src/fossil.page.fileedit.js
@@ -470,12 +470,12 @@
470 btnHelp = D.append(
471 D.addClass(D.div(), "help-buttonlet"),
472 'Locally-edited files. Timestamps are the last local edit time. ',
473 'Only the ',P.config.defaultMaxStashSize,' most recent files ',
474 'are retained. Saving or reloading a file removes it from this list. ',
475 D.append(D.code(),F.storage.storageImplName()),
476 ' = ',F.storage.storageHelpDescription()
477 );
478
479 D.append(wrapper, "Local edits (",
480 D.append(D.code(),
481 F.storage.storageImplName()),
482
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -694,12 +694,12 @@
694694
btnHelp = D.append(
695695
D.addClass(D.div(), "help-buttonlet"),
696696
'Locally-edited wiki pages. Timestamps are the last local edit time. ',
697697
'Only the ',P.config.defaultMaxStashSize,' most recent pages ',
698698
'are retained. Saving or reloading a file removes it from this list. ',
699
- D.append(D.code(),'localStorage'),' uses browser-local persistent storage. ',
700
- D.append(D.code(),'sessionStorage'),' uses storage local to this browser tab.'
699
+ D.append(D.code(),F.storage.storageImplName()),
700
+ ' = ',F.storage.storageHelpDescription()
701701
);
702702
D.append(wrapper, "Local edits (",
703703
D.append(D.code(),
704704
F.storage.storageImplName()),
705705
"):",
706706
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -694,12 +694,12 @@
694 btnHelp = D.append(
695 D.addClass(D.div(), "help-buttonlet"),
696 'Locally-edited wiki pages. Timestamps are the last local edit time. ',
697 'Only the ',P.config.defaultMaxStashSize,' most recent pages ',
698 'are retained. Saving or reloading a file removes it from this list. ',
699 D.append(D.code(),'localStorage'),' uses browser-local persistent storage. ',
700 D.append(D.code(),'sessionStorage'),' uses storage local to this browser tab.'
701 );
702 D.append(wrapper, "Local edits (",
703 D.append(D.code(),
704 F.storage.storageImplName()),
705 "):",
706
--- src/fossil.page.wikiedit.js
+++ src/fossil.page.wikiedit.js
@@ -694,12 +694,12 @@
694 btnHelp = D.append(
695 D.addClass(D.div(), "help-buttonlet"),
696 'Locally-edited wiki pages. Timestamps are the last local edit time. ',
697 'Only the ',P.config.defaultMaxStashSize,' most recent pages ',
698 'are retained. Saving or reloading a file removes it from this list. ',
699 D.append(D.code(),F.storage.storageImplName()),
700 ' = ',F.storage.storageHelpDescription()
701 );
702 D.append(wrapper, "Local edits (",
703 D.append(D.code(),
704 F.storage.storageImplName()),
705 "):",
706
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -288,18 +288,19 @@
288288
during initialization and stashed away for use in a PopupWidget
289289
when the botton is clicked.
290290
291291
*/
292292
setup: function f(){
293
- if(!f.clickHandler){
293
+ if(!f.hasOwnProperty('clickHandler')){
294294
f.clickHandler = function fch(ev){
295295
if(!fch.popup){
296296
fch.popup = new F.PopupWidget({
297297
cssClass: ['fossil-tooltip', 'help-buttonlet-content'],
298298
refresh: function(){
299299
}
300300
});
301
+ fch.popup.e.style.maxWidth = '80%'/*of body*/;
301302
const hide = ()=>fch.popup.hide();
302303
fch.popup.e.addEventListener('click', hide, false);
303304
document.body.addEventListener('click', hide, true);
304305
document.body.addEventListener('keydown', function(ev){
305306
if(fch.popup.isShown() && 27===ev.which){
@@ -306,24 +307,58 @@
306307
fch.popup.hide();
307308
}
308309
}, true);
309310
}
310311
D.append(D.clearElement(fch.popup.e), ev.target.$helpContent);
311
- const rect1 = ev.target.getClientRects()[0];
312
- var x = rect1.left, y = rect1.top;
312
+ var popupRect = ev.target.getClientRects()[0];
313
+ var x = popupRect.left, y = popupRect.top;
313314
if(x<0) x = 0;
314315
if(y<0) y = 0;
315
- /* shift help to the left 1/2 the width of fch.popup.e. However,
316
- fch.popup.e.getClientRects() is empty until the popup is shown,
317
- so we have to show it, calculate that size, then move it. */
316
+ /* Shift the help around a bit to "better" fit the
317
+ screen. However, fch.popup.e.getClientRects() is empty
318
+ until the popup is shown, so we have to show it,
319
+ calculate the resulting size, then move and/or resize it.
320
+
321
+ This algorithm/these heuristics can certainly be improved
322
+ upon. Just be careful to mess only with the X coordinate
323
+ and the width. The browser will try to keep the widget
324
+ from being truncated off-screen on the right, shifting it
325
+ to the left if needed, and we cannot generically be sure
326
+ that an enforced fully on-screen size will actually fit
327
+ the current help text.
328
+ */
318329
fch.popup.show(x, y);
319
- const rect2 = fch.popup.e.getClientRects()[0];
320
- x -= rect2.width/2;
330
+ x = popupRect.left, y = popupRect.top;
331
+ popupRect = fch.popup.e.getBoundingClientRect();
332
+ const rectBody = document.body.getClientRects()[0];
333
+ if(popupRect.right > rectBody.right){
334
+ x -= (popupRect.right - rectBody.right);
335
+ }
336
+ if(x + popupRect.width > rectBody.right){
337
+ x = rectBody.x + (rectBody.width*0.1);
338
+ fch.popup.e.style.minWidth = '70%';
339
+ }else{
340
+ fch.popup.e.style.removeProperty('min-width');
341
+ x -= popupRect.width/2;
342
+ }
321343
if(x<0) x = 0;
344
+ //console.debug("dimensions",x,y, popupRect, rectBody);
322345
fch.popup.show(x, y);
323346
};
324
- }
347
+ f.foreachElement = function(e){
348
+ if(e.classList.contains('processed')) return;
349
+ e.classList.add('processed');
350
+ e.$helpContent = [];
351
+ /* We have to move all child nodes out of the way because we
352
+ cannot hide TEXT nodes via CSS (which cannot select TEXT
353
+ nodes). We have to do it in two steps to avoid invaliding
354
+ the list during traversal. */
355
+ e.childNodes.forEach((ch)=>e.$helpContent.push(ch));
356
+ e.$helpContent.forEach((ch)=>ch.remove());
357
+ e.addEventListener('click', f.clickHandler, false);
358
+ };
359
+ }/*static init*/
325360
var elems;
326361
if(!arguments.length){
327362
arguments[0] = '.help-buttonlet:not(.processed)';
328363
arguments.length = 1;
329364
}
@@ -330,27 +365,15 @@
330365
if(arguments.length){
331366
if('string'===typeof arguments[0]){
332367
elems = document.querySelectorAll(arguments[0]);
333368
}else if(arguments[0] instanceof HTMLElement){
334369
elems = [arguments[0]];
335
- }else{/* assume DOM element list or array */
370
+ }else if(arguments[0].forEach){/* assume DOM element list or array */
336371
elems = arguments[0];
337372
}
338373
}
339
- if(!elems) return;
340
- elems.forEach(function(e){
341
- if(e.classList.contains('processed')) return;
342
- e.classList.add('processed');
343
- e.$helpContent = [];
344
- /* We have to move all child nodes out of the way because we
345
- cannot hide TEXT nodes via CSS (which cannot select TEXT
346
- nodes). We have to do it in two steps to avoid invaliding
347
- the list during traversal. */
348
- e.childNodes.forEach((ch)=>e.$helpContent.push(ch));
349
- e.$helpContent.forEach((ch)=>ch.remove());
350
- e.addEventListener('click', f.clickHandler, false);
351
- });
374
+ if(elems) elems.forEach(f.foreachElement);
352375
},
353376
354377
/**
355378
Sets up the given element as a "help buttonlet", adding the CSS
356379
class help-buttonlet to it. Any (optional) arguments after the
357380
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -288,18 +288,19 @@
288 during initialization and stashed away for use in a PopupWidget
289 when the botton is clicked.
290
291 */
292 setup: function f(){
293 if(!f.clickHandler){
294 f.clickHandler = function fch(ev){
295 if(!fch.popup){
296 fch.popup = new F.PopupWidget({
297 cssClass: ['fossil-tooltip', 'help-buttonlet-content'],
298 refresh: function(){
299 }
300 });
 
301 const hide = ()=>fch.popup.hide();
302 fch.popup.e.addEventListener('click', hide, false);
303 document.body.addEventListener('click', hide, true);
304 document.body.addEventListener('keydown', function(ev){
305 if(fch.popup.isShown() && 27===ev.which){
@@ -306,24 +307,58 @@
306 fch.popup.hide();
307 }
308 }, true);
309 }
310 D.append(D.clearElement(fch.popup.e), ev.target.$helpContent);
311 const rect1 = ev.target.getClientRects()[0];
312 var x = rect1.left, y = rect1.top;
313 if(x<0) x = 0;
314 if(y<0) y = 0;
315 /* shift help to the left 1/2 the width of fch.popup.e. However,
316 fch.popup.e.getClientRects() is empty until the popup is shown,
317 so we have to show it, calculate that size, then move it. */
 
 
 
 
 
 
 
 
 
 
318 fch.popup.show(x, y);
319 const rect2 = fch.popup.e.getClientRects()[0];
320 x -= rect2.width/2;
 
 
 
 
 
 
 
 
 
 
 
321 if(x<0) x = 0;
 
322 fch.popup.show(x, y);
323 };
324 }
 
 
 
 
 
 
 
 
 
 
 
 
325 var elems;
326 if(!arguments.length){
327 arguments[0] = '.help-buttonlet:not(.processed)';
328 arguments.length = 1;
329 }
@@ -330,27 +365,15 @@
330 if(arguments.length){
331 if('string'===typeof arguments[0]){
332 elems = document.querySelectorAll(arguments[0]);
333 }else if(arguments[0] instanceof HTMLElement){
334 elems = [arguments[0]];
335 }else{/* assume DOM element list or array */
336 elems = arguments[0];
337 }
338 }
339 if(!elems) return;
340 elems.forEach(function(e){
341 if(e.classList.contains('processed')) return;
342 e.classList.add('processed');
343 e.$helpContent = [];
344 /* We have to move all child nodes out of the way because we
345 cannot hide TEXT nodes via CSS (which cannot select TEXT
346 nodes). We have to do it in two steps to avoid invaliding
347 the list during traversal. */
348 e.childNodes.forEach((ch)=>e.$helpContent.push(ch));
349 e.$helpContent.forEach((ch)=>ch.remove());
350 e.addEventListener('click', f.clickHandler, false);
351 });
352 },
353
354 /**
355 Sets up the given element as a "help buttonlet", adding the CSS
356 class help-buttonlet to it. Any (optional) arguments after the
357
--- src/fossil.popupwidget.js
+++ src/fossil.popupwidget.js
@@ -288,18 +288,19 @@
288 during initialization and stashed away for use in a PopupWidget
289 when the botton is clicked.
290
291 */
292 setup: function f(){
293 if(!f.hasOwnProperty('clickHandler')){
294 f.clickHandler = function fch(ev){
295 if(!fch.popup){
296 fch.popup = new F.PopupWidget({
297 cssClass: ['fossil-tooltip', 'help-buttonlet-content'],
298 refresh: function(){
299 }
300 });
301 fch.popup.e.style.maxWidth = '80%'/*of body*/;
302 const hide = ()=>fch.popup.hide();
303 fch.popup.e.addEventListener('click', hide, false);
304 document.body.addEventListener('click', hide, true);
305 document.body.addEventListener('keydown', function(ev){
306 if(fch.popup.isShown() && 27===ev.which){
@@ -306,24 +307,58 @@
307 fch.popup.hide();
308 }
309 }, true);
310 }
311 D.append(D.clearElement(fch.popup.e), ev.target.$helpContent);
312 var popupRect = ev.target.getClientRects()[0];
313 var x = popupRect.left, y = popupRect.top;
314 if(x<0) x = 0;
315 if(y<0) y = 0;
316 /* Shift the help around a bit to "better" fit the
317 screen. However, fch.popup.e.getClientRects() is empty
318 until the popup is shown, so we have to show it,
319 calculate the resulting size, then move and/or resize it.
320
321 This algorithm/these heuristics can certainly be improved
322 upon. Just be careful to mess only with the X coordinate
323 and the width. The browser will try to keep the widget
324 from being truncated off-screen on the right, shifting it
325 to the left if needed, and we cannot generically be sure
326 that an enforced fully on-screen size will actually fit
327 the current help text.
328 */
329 fch.popup.show(x, y);
330 x = popupRect.left, y = popupRect.top;
331 popupRect = fch.popup.e.getBoundingClientRect();
332 const rectBody = document.body.getClientRects()[0];
333 if(popupRect.right > rectBody.right){
334 x -= (popupRect.right - rectBody.right);
335 }
336 if(x + popupRect.width > rectBody.right){
337 x = rectBody.x + (rectBody.width*0.1);
338 fch.popup.e.style.minWidth = '70%';
339 }else{
340 fch.popup.e.style.removeProperty('min-width');
341 x -= popupRect.width/2;
342 }
343 if(x<0) x = 0;
344 //console.debug("dimensions",x,y, popupRect, rectBody);
345 fch.popup.show(x, y);
346 };
347 f.foreachElement = function(e){
348 if(e.classList.contains('processed')) return;
349 e.classList.add('processed');
350 e.$helpContent = [];
351 /* We have to move all child nodes out of the way because we
352 cannot hide TEXT nodes via CSS (which cannot select TEXT
353 nodes). We have to do it in two steps to avoid invaliding
354 the list during traversal. */
355 e.childNodes.forEach((ch)=>e.$helpContent.push(ch));
356 e.$helpContent.forEach((ch)=>ch.remove());
357 e.addEventListener('click', f.clickHandler, false);
358 };
359 }/*static init*/
360 var elems;
361 if(!arguments.length){
362 arguments[0] = '.help-buttonlet:not(.processed)';
363 arguments.length = 1;
364 }
@@ -330,27 +365,15 @@
365 if(arguments.length){
366 if('string'===typeof arguments[0]){
367 elems = document.querySelectorAll(arguments[0]);
368 }else if(arguments[0] instanceof HTMLElement){
369 elems = [arguments[0]];
370 }else if(arguments[0].forEach){/* assume DOM element list or array */
371 elems = arguments[0];
372 }
373 }
374 if(elems) elems.forEach(f.foreachElement);
 
 
 
 
 
 
 
 
 
 
 
 
375 },
376
377 /**
378 Sets up the given element as a "help buttonlet", adding the CSS
379 class help-buttonlet to it. Any (optional) arguments after the
380
--- src/fossil.storage.js
+++ src/fossil.storage.js
@@ -135,9 +135,24 @@
135135
/** Returns a symbolic name for the current storage mechanism. */
136136
storageImplName: function(){
137137
if($storage===window.localStorage) return 'localStorage';
138138
else if($storage===window.sessionStorage) return 'sessionStorage';
139139
else return 'transient';
140
+ },
141
+
142
+ /**
143
+ Returns a brief help text string for the currently-selected
144
+ storage type.
145
+ */
146
+ storageHelpDescription: function(){
147
+ return {
148
+ localStorage: "Browser-local persistent storage with an "+
149
+ "unspecified long-term lifetime (survives closing the browser, "+
150
+ "but maybe not a browser upgrade).",
151
+ sessionStorage: "Storage local to this browser tab, "+
152
+ "lost if this tab is closed.",
153
+ "transient": "Transient storage local to this invocation of this page."
154
+ }[this.storageImplName()];
140155
}
141156
};
142157
143158
})(window.fossil);
144159
--- src/fossil.storage.js
+++ src/fossil.storage.js
@@ -135,9 +135,24 @@
135 /** Returns a symbolic name for the current storage mechanism. */
136 storageImplName: function(){
137 if($storage===window.localStorage) return 'localStorage';
138 else if($storage===window.sessionStorage) return 'sessionStorage';
139 else return 'transient';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140 }
141 };
142
143 })(window.fossil);
144
--- src/fossil.storage.js
+++ src/fossil.storage.js
@@ -135,9 +135,24 @@
135 /** Returns a symbolic name for the current storage mechanism. */
136 storageImplName: function(){
137 if($storage===window.localStorage) return 'localStorage';
138 else if($storage===window.sessionStorage) return 'sessionStorage';
139 else return 'transient';
140 },
141
142 /**
143 Returns a brief help text string for the currently-selected
144 storage type.
145 */
146 storageHelpDescription: function(){
147 return {
148 localStorage: "Browser-local persistent storage with an "+
149 "unspecified long-term lifetime (survives closing the browser, "+
150 "but maybe not a browser upgrade).",
151 sessionStorage: "Storage local to this browser tab, "+
152 "lost if this tab is closed.",
153 "transient": "Transient storage local to this invocation of this page."
154 }[this.storageImplName()];
155 }
156 };
157
158 })(window.fossil);
159

Keyboard Shortcuts

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