Extra space below edit-text widget

Strange behavior. I run TW 5.3.5.

  1. create new tiddler, say ‘bug?’
  2. paste this text into the text field:
    <$edit-text tiddler="$:/boekenkast/config/variables/securitystand" size="5" tag="input">Wijzig securitystand</$edit-text>
    (there are some Dutch words here)
  3. confirm edit
  4. the tiddler contains the edit-text widget as specified BUT the tiddler itself is too high: below the widget are several empty lines of space
  5. this extra space also shows when ‘bug?’ is transcluded in another tiddler
  6. this behavior is consistent in several of my wiki’s, even after restarting the browser (Firefox 144.0.2 on Ubuntu 24.04.3 LTS)

Puzzled,
Sjaak

Normally an $edit-text widget does not have any content and is written like this:

<$edit-text tiddler="$:/boekenkast/config/variables/securitystand" size="5" tag="input"/>

(note the /> at the end of the widget)

But, when the $edit-text widget encloses some content (as you have done), that content is rendered within a .tc-editor-toolbar div, followed by an iframe wrapped around a textarea element. This combination of elements is used by the TWCore to show the standard multi-line tiddler editor with a toolbar.

In your example code, you have specfied tag="input", which forces the use of a single-line “input” element instead of a multi-line “textarea” element. However, because your $edit-text widget has “Wijzig securitystand” as internal content, it is rendering that content inside a .tc-editor-toolbar div, and followed by an iframe wrapper around the single-line input element… but the default height for an iframe element is 100 pixels, which is where the extra “empty lines of space” come from.

To avoid this, you should write your wikitext like this:

Wijzig securitystand<br>
<$edit-text tiddler="$:/boekenkast/config/variables/securitystand" size="5" tag="input"/>

-e

Thanks to your deep knowledge of tiddlywiki for this answer @EricShulman is seems to me that this “quirk” of the edit-text widget should be better documented;

On tiddlywiki.com the documentation for edit-text widget says;

The content of the <$edit-text> widget is ignored.

This is patently false.

It seems clear this side effect is a result of hidden behaviours, that are used elsewhere in the core to handle the editing of textarea’s specifically textarea and toolbars.

perhaps it should say;

The content of the <$edit-text> widget is used by the core to edit text areas.

With your reply here I can see using the contents of the edit widget I can use inspect to see how its behaviour is very different as you suggested.

Can this behaviour be made use of in tiddlywiki script?

  • Perhaps then the documentation can be extended and thus complete

I don’t fully understand this mechanism yes, but it seems to me to have the potential for extended use, and understanding if properly documented.

With this perhaps we could use on our own edits

  • editor toolbar buttons
    • tm-edit-text-operations
  • Autocomplete tools
  • keyboard shortcuts
  • Preserve selections/cursor position

There are still cases where there is a problem editing from the view template fields on the current tiddler, as it looses focus. Perhaps there a way to reduce this when not in draft.

Thanks @EricShulman for once more helping a stupefied TW user out. I honestly do not know why I put the accompanying text inside the widget in the first place. But it worked, so I did not think of repairing it the way you suggested (let alone why).

I fully agree with @TW_Tones that the documentation could use an update in this case.

It certainly should.

Not only is that some crazy set of markup generated, the <input> tag nested in that IFrame has a style attribute with 276 different CSS properties!:

CSS Properties
accent-color: auto;
place-content: normal;
place-items: normal;
place-self: auto;
alignment-baseline: auto;
anchor-name: none;
anchor-scope: none;
animation-composition: replace;
animation: 0s ease 0s 1 normal none running none;
app-region: none;
appearance: auto;
backdrop-filter: none;
backface-visibility: visible;
background: none 0% 0% / auto repeat scroll padding-box border-box rgb(255, 255, 255);
background-blend-mode: normal;
baseline-shift: 0px;
baseline-source: auto;
block-size: auto;
border-block-end: 1px solid rgb(118, 118, 118);
border-block-start: 1px solid rgb(118, 118, 118);
border-color: rgb(118, 118, 118);
border-radius: 0px;
border-style: solid;
border-width: 1px;
border-collapse: separate;
border-end-end-radius: 0px;
border-end-start-radius: 0px;
border-image: none 100% / 1 / 0 stretch;
border-inline-end: 1px solid rgb(118, 118, 118);
border-inline-start: 1px solid rgb(118, 118, 118);
border-start-end-radius: 0px;
border-start-start-radius: 0px;
inset: auto;
box-decoration-break: slice;
box-shadow: none;
box-sizing: border-box;
break-after: auto;
break-before: auto;
break-inside: auto;
buffered-rendering: auto;
caption-side: top;
caret-animation: auto;
caret-color: rgb(51, 51, 51);
clear: none;
clip: auto;
clip-path: none;
clip-rule: nonzero;
color: rgb(51, 51, 51);
color-interpolation: srgb;
color-interpolation-filters: linearrgb;
color-rendering: auto;
columns: auto;
gap: normal;
column-rule: 0px rgb(51, 51, 51);
column-span: none;
contain-intrinsic-block-size: none;
contain-intrinsic-inline-size: none;
contain-intrinsic-size: none;
container: none;
content: normal;
corner-shape: round;
corner-block-end-shape: round;
corner-block-start-shape: round;
cursor: text;
cx: 0px;
cy: 0px;
d: none;
display: block;
dominant-baseline: auto;
dynamic-range-limit: no-limit;
empty-cells: show;
field-sizing: fixed;
fill: rgb(51, 51, 51);
fill-opacity: 1;
fill-rule: nonzero;
filter: none;
flex: 0 1 auto;
flex-flow: row;
float: none;
flood-color: rgb(0, 0, 0);
flood-opacity: 1;
font-family: -apple-system, BlinkMacSystemFont, &quot;
egoe UI", "Noto Sans", sans-serif, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
font-kerning: auto;
font-optical-sizing: auto;
font-palette: normal;
font-size: 14px;
font-size-adjust: none;
font-stretch: 100%;
font-style: normal;
font-synthesis: weight style small-caps;
font-variant: normal;
font-weight: 400;
grid: none;
grid-area: auto;
height: auto;
hyphenate-character: auto;
hyphenate-limit-chars: auto;
hyphens: manual;
image-orientation: from-image;
image-rendering: auto;
initial-letter: normal;
inline-size: auto;
inset-block: auto;
inset-inline: auto;
interactivity: auto;
interest-delay: normal;
interpolate-size: numeric-only;
isolation: auto;
letter-spacing: normal;
lighting-color: rgb(255, 255, 255);
line-break: auto;
line-height: 16.1px;
list-style: outside none disc;
margin-block: 0px;
margin-inline: 0px;
margin: 0px;
marker: none;
mask: none;
mask-type: luminance;
math-depth: 0;
math-shift: normal;
math-style: normal;
max-block-size: none;
max-height: none;
max-inline-size: none;
max-width: none;
min-block-size: 0px;
min-height: 0px;
min-inline-size: 0px;
min-width: 0px;
mix-blend-mode: normal;
object-fit: fill;
object-position: 50% 50%;
object-view-box: none;
offset: normal;
opacity: 1;
order: 0;
orphans: 2;
outline: rgb(51, 51, 51) none 0px;
outline-offset: 0px;
overflow-anchor: auto;
overflow-block: visible;
overflow-clip-margin: 0px;
overflow-inline: visible;
overflow-wrap: break-word;
overflow: visible;
overlay: none;
overscroll-behavior-block: auto;
overscroll-behavior-inline: auto;
padding-block: 2px;
padding: 2px;
padding-inline: 2px;
paint-order: normal;
perspective: none;
perspective-origin: 50% 50%;
pointer-events: auto;
position: static;
position-anchor: auto;
position-area: none;
position-try: none;
position-visibility: anchors-visible;
print-color-adjust: economy;
r: 0px;
reading-flow: normal;
reading-order: 0;
resize: both;
rotate: none;
ruby-align: space-around;
ruby-position: over;
rx: auto;
ry: auto;
scale: none;
scroll-behavior: auto;
scroll-initial-target: none;
scroll-margin-block: 0px;
scroll-margin-inline: 0px;
scroll-marker-group: none;
scroll-padding-block: auto;
scroll-padding-inline: auto;
scroll-target-group: none;
scroll-timeline: none;
scrollbar-color: auto;
scrollbar-gutter: auto;
scrollbar-width: auto;
shape-image-threshold: 0;
shape-margin: 0px;
shape-outside: none;
shape-rendering: auto;
speak: normal;
stop-color: rgb(0, 0, 0);
stop-opacity: 1;
stroke: none;
stroke-dasharray: none;
stroke-dashoffset: 0px;
stroke-linecap: butt;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-opacity: 1;
stroke-width: 1px;
tab-size: 4;
table-layout: auto;
text-align: start;
text-align-last: auto;
text-anchor: start;
text-autospace: no-autospace;
text-box: normal;
text-decoration: rgb(51, 51, 51);
text-decoration-skip-ink: auto;
text-emphasis: none rgb(51, 51, 51);
text-emphasis-position: over;
text-indent: 0px;
text-overflow: clip;
text-rendering: auto;
text-shadow: none;
text-size-adjust: 100%;
text-spacing-trim: normal;
text-transform: none;
text-underline-position: auto;
text-wrap: wrap;
timeline-scope: none;
touch-action: auto;
transform: none;
transform-origin: 50% 50%;
transform-style: flat;
transition: all;
translate: none;
unicode-bidi: normal;
user-select: auto;
vector-effect: none;
vertical-align: baseline;
view-timeline: none;
view-transition-class: none;
view-transition-group: normal;
view-transition-name: none;
visibility: visible;
white-space-collapse: preserve;
widows: 2;
width: 100%;
will-change: auto;
word-break: normal;
word-spacing: 0px;
writing-mode: horizontal-tb;
x: 0px;
y: 0px;
z-index: auto;
zoom: 1;
border-spacing: 0px;
-webkit-border-image: none;
-webkit-box-align: stretch;
-webkit-box-decoration-break: slice;
-webkit-box-direction: normal;
-webkit-box-flex: 0;
-webkit-box-ordinal-group: 1;
-webkit-box-orient: horizontal;
-webkit-box-pack: start;
-webkit-font-smoothing: antialiased;
-webkit-line-break: auto;
-webkit-line-clamp: none;
-webkit-locale: "en-GB";
-webkit-mask-box-image-outset: 0;
-webkit-mask-box-image-repeat: stretch;
-webkit-mask-box-image-slice: 0 fill;
-webkit-mask-box-image-source: none;
-webkit-mask-box-image-width: auto;
-webkit-rtl-ordering: logical;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0.18);
-webkit-text-combine: none;
-webkit-text-decorations-in-effect: none;
-webkit-text-fill-color: currentcolor;
-webkit-text-orientation: vertical-right;
-webkit-text-security: none;
-webkit-text-stroke: 0px rgb(51, 51, 51);
-webkit-user-drag: auto;
-webkit-user-modify: read-only;
-webkit-writing-mode: horizontal-tb;

Can anyone explain what this behavior is about? Can it be fixed simply without breaking the core or breaking wikis depending on it? It seems quite bizarre!

Scott,

I should have spelt this out a little more, when @EricShulman said,

I understood why. and I did not expand.

for clarity the text editor for tiddlers is quite sophisticated and includes buttons and shortcuts and a number of plugins enhance this, not to mention the draft and preview mechanism. the core team decided an IFrame was nessasary too.

what was discovered by @SjaakA and myself by accident was that the content of the widget although documented as ignored is in fact the way the tiddler edit mechanism is implemented. this if accidentally used has side effects.

thus you found an extraordinary amount of CSS applied, I expect mostly to support the editor.

If the tiddler editor’s textarea was rendered outside of an iframe, then when the user clicks on a toolbar button, the textarea would lose the input focus and forget its current selection/cursor position.

However, when the textarea is rendered within an iframe, it preserves the current selection/cursor position when a toolbar button is clicked.

This behavior is essential so that the toolbar button’s actions can insert content at the cursor position or replace the current selection with new/modified content.

-e

thanks Eric for the backgrounding

If we install the edit buttons for “done keep open” we loose the cursor position. If instead we implement this in the editor toolbar, we should be able to retain the cursor position then? Ideally with a shortcut so we can keep working without touching the mouse.

IFrames need to be used to allow toolbar buttons to be clicked and keeping selections active in the text editor. Otherwise with a default TEXTAREA HTML element browsers will de-select the text if the focus changes to a button, when it is clicked.

IFrames are notoriously hard to style. An iframe basically starts a completely new browser document inside an existing HTML BODY element. We need to copy over all needed styles, to be able to apply colour palette changes dynamically. Only a style-element is has a “strong” enough specificity to apply style changes to the inside of the iframe.

I think there is nothing to fix, except iframes have changed considerably.

Thank you for the excellent explanation!

I’ve avoided IFrames as much as I possibly can for my long career, partly because of these complexities. I think I’ll continue ignoring them as best I can!

It wouldn’t make a difference. The issue here is that “done keep open” updates the underlying tiddler object in the TWCore’s store area and this triggers a refresh event that re-renders the iframe containing the tiddler’s textarea. As a result, the textarea’s cursor position/current selection is lost.

-e

Iframes were my goto method for “XHR” before XHR hit the scene (late 90s). I was that soldier :wink: with the scars to prove it :scream: . But hey, it worked, despite MS trying to convince us we needed ActiveX and an embedded Java object to make it all happen. Uh, no, MS… iframes, parentWindow.my_fn() (and postmessage) were fine, thank you very much.

Oops. I got off one one there. Sorry. :blush:

I was too busy with document.layers and document.all and “make it sizzle” to do more than just play with useful async. When we told management about all the real possibilities, they pooh-poohed it. I left that company and started my new job (following the old boss, along with Jack and Brian, and eventually, 18 others!) the same week that Google’s April 1 announcement of Gmail turned out not to be a hoax. The boss immediately said, “We need some of that.” But at that point the AJAX path was clear and easily followed. We were told by colleagues who stayed behind that management immediately asked, “Why didn’t anyone tell us about these things?” To their credit, they risked management’s ire and said, “Well, Scott, Jack, and Brian were suggesting this for a while. Here are the emails. But you said no.” They floundered for a while, but didn’t manage to do anything with AJAX until jQuery eventually made it easy for them. Meanwhile, the company I’d moved to was a competitor who had been doing this for nearly three years, although I was only there for the first year of it.

Fun times!

But I got to miss that usage of iFrames except for proofs of concept at StodgyOldCompany Inc.

1 Like