How to get transclusion depth?

Yes, even if you change your own code, if there is any need to use the depth of something, it is most likely to be to the parent or grandparent process, that is the relative depth, -1 or -2 conceptually. Very unlikely an absolute depth.

I think your issue stems from the same issue I raised, because the slot contents are only returned using a widget (read as a final output mechanism) there is little we can do to make use of the contents. And this includes the contents of the calling widget/procedure which is what slots are all about. Accessing ts-raw without the slot widget?

  • Since we can’t use those contents much at any level we can’t set variables etc… that will be available in a child widget or process either.
  • So we then look to the depth parameter and it all gets really confusing.
  • What do you mean with these words? surely there is no need to use the word transclude here? Just
    • I could need to include a widget or macro

    • Or do you mean something different?

At least in a way, yes. I wanted to access slots at an unknown relative depth. My thought was that if the absolute transclusion depth were available as a variable, then the relative depth would be easily computable, but if slots were available as variables as in the idea in your post, that would also make it a lot easier.

@pmario provided a good answer:

As the $transclude widget documentation says:

The $transclude widget dynamically includes the content from another tiddler or variable

(emphasis added)

And as we know macros are also a kind of variable. Even custom widgets are implemented as a kind of variable:

Custom widgets are implemented as a special kind of variable. The only thing that distinguishes them from ordinary variables is the way that they can be called as a custom widget with attributes mapped to parameters.

Normally I wouldn’t use that word for widgets, procedures, or variables because that’s just the implementation under the hood. But in this case, it’s relevant that the underlying mechanism is a transclusion, because this changes the transclusion depth, and thus, changes the $depth value needed to use slots. For example, if you copy the following code into a new tiddler and open the preview:

\define myMacro() <$slot $name="ts-raw"/>

\widget $my.widget() <<myMacro>>

<$my.widget> slot content </$my.widget>

You’ll find that the slot content isn’t displayed. (As per the custom widgets documentation linked above, ts-slot is the slot that TW automatically fills in a custom widget to provide access to the the children of that widget, slot content in this case.) But if you change the first line to:

\define myMacro() <$slot $name="ts-raw" $depth=2/>

Then it displays. This is because the macro call is technically a variable transclusion, so to use the slot widget’s slot within the macro, we have to specify that it is not a slot filled in the macro call but filled in the widget call, its parent in the tree.

(If you change the preview type to widget tree, you can see that the widget and macro are both rendered via transclusions. However, despite the simplicity of the code example, the widget tree is too unwieldy to share here.)

That’s why I chose to use that word - not just because it’s a transclusion under the hood, but because the fact that it’s a transclusion is relevant to this particular issue of wanting to use $slots without having to know the transclusion depth.

To my understanding this is an incorrect use of the slot widget. The slot widget is designed to be used inside a widget definition, be it a custom widget, or one that overrides a core widget.

  • It is interesting that you point out it works when placed inside a macro definition but this is just a side effect. Macros are deprecated and procedures recommended).
  • Interesting but non-standard

Actually I think this view point is confusing the issue, seriously.

Lets go back to the slot widget, what do you want to use it for?, I have learned how to use them and never needed to consider depth.

  • As I understand it the depth already is a relative term, and no need to work it out, there is arguably no useful absolute depth.
  • If one was to use depth, most likely it would ONLY be for access to the grandparent or higher within a specific set of code, such as a reiterative or recursive code set. The default depth is the one before.
    • And the ways variables flow down to its children, even this is unlikely to be needed.
      • Perhaps except in the event of meta things, like writing code that writes code, or generates templates and objects like buttons.
  • I think there is value in building a code structure that uses the slot widget in standard ways, and only then asking how you can make use of the depth.

Being a bit of a hacker myself, I did guess that using depth may give us some interesting hacks into the tiddlywiki core processes and provide some creative design opportunities. But I have not yet found a compelling reason to do so.

It’s not a side effect. It works because the macro is called by a widget. It’s only incorrect if I call the macro outside the widget.

Perhaps I should amend the example:

\widget $my.widget() 
\define myMacro() <$slot $name="ts-raw"/> <!-- add $depth=2 to make it work -->

<<myMacro>>

\end $my.widget

<$my.widget> slot content </$my.widget>

This would make it a little more clear that the macro can only be called inside the widget, I think.

From what I understand, this is only relevant when using parameters; for reusable code snippets with no parameters, \define and \procedure work exactly the same, do they not?

This means you are only using them directly in the widget definition or transcluded tiddler. In a way, this is where I was going wrong - assuming that you ought to be able to easily use them that widget or tiddler’s children. (Keyword “easily”) I am looking to things other than slots now (although there’s no alternative to the ts-raw slot).

Edit: as for the relative vs absolute depth: $depth is a relative depth, yes. I wanted absolute depth available (as a variable) in order to be able to easily compute the needed relative depth (as in the examples above).

  • To me it (needing the depth) is a side effect of

putting the slot widget inside a macro.

But why not just;

\widget $my.widget() 
<$slot $name="ts-raw"/> 
\end $my. Widget

<$my.widget> slot content </$my.widget>

It does make it clearer.

  • There is a little more to it than that but the part you say is not wrong.
  • It is a problem using both macros and procedures when some sort of evaluation needs to take place, because some uses will need you to wikify it first.
    • But this is also true when your macro includes the slot statement, however your invocation of that macro <<myMacro>> is just that it gets wikifeld in the final render.

I do think I know where your queries were generated. There is some incompletness in the code for manapulating slots and I have reased this in the past

I would argue I see no case where you need to do this. As the coder you can see what the depth is and encode that.

  • In the example above, inside the macro you need depth 2, in the body depth 1 the default.
1 Like

(Discourse won’t let me post without at least 20 characters, and apparently quotes don’t count, so I’m writing this junk sentence.)

I think there would be value pursuing as simple an example as you can of what you are trying to do. Ideally a package we can drop on tiddlywiki.com and experiment with. Looking at tiddlywiki at this level of sophistication gets complex perhaps as a result of its flexibility. I expect it is quite easy to get the same results by more than one path.

  • The standard way to fill a slot is using the fill widget?
  • I think they were designed for a much simpler use case, but I applauded your objectives. Initially only the ts-raw was in effect valid.
  • Traditionally the approach is to transclude the content of a macro, procedure or tiddler. The slot is the first time we gained access to the content of the calling widget to support custom widgets and is still incomplete.

@pmario @TW_Tones Here is an oversimplified example of why I want to be able to use slots at arbitrary depths without having to worry about the $depth attribute. I don’t yet know how to format the json so that it can be dragged onto a TiddlyWiki to be imported, but this should at least be able to be downloaded and the contents copied and pasted into the $:/Import tiddler. Thanks @Scott_Sauyet

Oversimplified version (1).json (1.6 KB)

I have created an <$error.context> custom widget that does nothing but display its ts-raw slot. I have also created a <$safe.button> widget that is a wrapper for the <$button> widget, except that it wikifies the slot of the error context widget into a widget tree and detects the presence of any <$error> widgets within the <$error.context> widget, and disables the button if there are any errors present.

As a demonstration of how this could be used, I have created a couple of input fields, and some logic to produce <$error> widgets if there are any incorrect inputs. This acts as “validations” that also result in the button being disabled.

The limitation I want to overcome is that the <$safe.button> widget needs to know the relative depth it’s being used inside the <$error.context> widget in order to get the correct slot and check for the <$error> widgets. I have simply hardcoded it as 2, but because of this, I have to use the <$safe.button> as a direct child of the <$error.context> and can’t make tiddlers containing the buttons etc. (or else would have to use $fillignore everywhere along the chain to the <$safe.button> widget).

Even if I don’t make the tool public, I myself don’t want to have to deal with the $depth attribute. That’s why I wanted to be able to simply compute it.

I originally tried doing the wikification of the slot in the <$error.context> widget itself, thus creating a variable that the <$safe.button> widget can access. The issue with that is that any time the widget tree for the slot changes (such as if an error message appears or disappears), any contained <$edit-text> widget will lose focus.

I am currently looking at making the <$safe.button> widget send a custom message that contains enough information to simulate what would happen if all the same attributes were given to a <$button> widget, and adding a <$messagecatcher> to the <$error.context> widget that catches the custom message. When it catches the actions, it would wikify the ts-raw slot (into the widget tree) in order to check for <$error> widgets, and if there aren’t any errors, it would run the actions that simulate what would’ve happened with a normal <$button> widget (using the information in the custom message to do so).

I’m also considering avoiding slots altogether and using some kind of template in place of a custom <$error.context> widget. That doesn’t seem as nice to use, though.

In the tiddler’s More Actions dropdown is an “export tiddler” option. You can choose “JSON file” from there:

image

For more than one, you can write a filter that includes exactly the tiddlers you want to export and put it in the Advanced Search > Filter box, and there will be an export button that will allow you to choose JSON.

(Note that when you do this, although the pre-import screen puts them in alphabetic order, the one that says “The following tiddlers were imported:” restores the order from the filter. This lets you put the most important ones [e.g. “My Overview”] first in the list…)

1 Like

Thanks, @Scott_Sauyet

Fixed (also fixed the bug caused by changing temp tiddler titles in one place but not another)

Should probably also change to display: table-cell but that’s not too important here.

It will likely require a real expert to answer for certain, but my guess is that this is not available in wikitext. You might look to the rendering code or, as mentioned earlier, to the qualify widget to see if this could be added to the core. You could fiddle with updating it for your needs with an eye towards both solving it for your own use and creating code that could be contributed back to the core.

Maybe one day! (I would imagine that it could be kept track of in the widget tree)

2 Likes

I will look at your example tomorrow. best of luck

A js macro would be needed:

/*\
title: depth.js
type: application/javascript
module-type: macro


\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

/*
Information about this macro
*/

exports.name = "depth";

exports.params = [];

/*
Run the macro
*/
exports.run = function() {
	var name ="transclusion",
	depth=0,
	node = this;
	while(node && node.parentWidget) {
		if($tw.utils.hop(node.parentWidget.variables,name)) {
			depth++;
		}
		node = node.parentWidget;
	}
	return depth;
};

})();
2 Likes

@buggyj I believe that’s the idea. However, it doesn’t seem to increase the depth level with macro calls, custom widgets, and the like. I’m not sure why, since viewing the widget tree for all those things shows they are all transclusions in the end. (All those things affect the needed $depth attribute for slots.)

Still, this may have provided me with a few clues about how to dig into TW JS code enough to figure out how to get the solution.

I must admit, I am finding if difficult to understand your example, perhaps I should “bow out”, But I can’t help but think this is over complicated, and there is a standard TiddlyWiki script solution, however you have not really outlined what you want done, only the way you are doing “it”, and telling us what is no good with it.

  • I imagine the reason I see it this way, is something about your real need is lost in the example?

I have a hint to you that may help, see the end, at a conceptual level.

It seems to me all you are after is a button to be disabled until two conditions are met?

  • For some reason you have gone off trying to retrieve this conditional information via slot widgets and redefining the button, or are you?
  • This may be exacerbated by your use of the if statements, because the result is only displayed, and can’t be passed to the button. It is also split into two separate if statements.
    • So this has led you down the path of trying to use the depth (in some ways really height), to retrieve the above code, wikify it “again” to find if the button should be disabled.

Could this have some relevance here ActionWidget Execution Modes you are using the genesis widget to create a button, who’s key quality is the onclick action?

  • More so now I don’t think so.

@bluepenguindeveloper , with all respect, Your code is most inventive, curious and possibly ingenious, but seems to me, to be the result of a conceptual error in your design and coding. You have “gone down the wrong rabbit hole”.

  • Although, as always, I may be wrong.

Hint

As soon as you invoke a widget, that is something with a $sign you are saying “display this”, Not compute this for later use, just display it.

  • However nested inside a widget you can go deeper and deeper in nested widgets to work out what to display, but from the outer widget down, it will only be displayed.
    • Keep in mind you can display interactive components like a button, and they can do things, but they are still just displayed.
  • It seems in many ways this is somewhat true for the %if statements. Nothing that happens after the condition can ever come outside of that statement, only displayed.

Conclusion

You seem not to be aware of the above, which is understandable, and you are trying to fight back, by trying to access the result of wikification above, to change something lower down.

  • I believe this is totally unnecessary and there are other code patterns to achieve the outcome.

The question is would you value me putting time into reverse engineering your code and design a better solution?

  • Could you help reduce the time I spend, by giving a “code agnostic” requirement statement?

How I would do it?

  • I would not have an error.context
  • I would use functions and variables and multiple conditions
  • I would only use widgets, and %if statements, other than the list widget, at the lowest level possible, and to display something.

People that don’t know this, including me in the past, always think wikifying it is the answer. But that just compounds the problem. There are very few ways this (wikification) is appropriate, if any. Wikify is also discouraged for performance reasons.

@TW_Tones I’m not gonna go so far as to ask you (or anyone else) to design a solution for me.

I was actually looking to make a suite of widgets for building UIs, many of which wrap the existing widgets (edit-text, etc.) but also can be passed conditions (filters) which display validation messages (I used $error for the example, but I intend them to look and behave differently). And I wanted the validations to have actual force, without changing the button every time I change one of the conditions.

Maybe the best TW way to do this is to add pragmas (\define or \procedures) for all the filters and reference all the same filters in the button to disable it. But I was trying to avoid having to add everything to both the button and whatever field is using them… too easy to forget to add or remove it from one thing and then have a mismatch.

Thus, I was looking for a way for the button to detect the presence of the error messages without having to change the code for the button every time I add or remove code for an error message elsewhere. (I looked to see if there was some way, even if only in action widgets, that I detect DOM nodes with a CSS selector or XPATH selector, but I couldn’t find a way other than wikify.)

I thought about having the custom input widgets record the valid/invalid values into state tiddlers which the custom button widget could lookup, but the problem is that the same fields could change due to things outside the custom input widget. So I thought, the custom input widgets would just need to listen for changes to the fields, and update the validation states on any changes to those fields regardless of the origin/cause. But I found a topic you created where it was answered that there was no such mechanism.

Maybe I am just trying to do something that TW isn’t designed for. One thing it doesn’t seem to be great for is modularization (in this case, the button being modular in the sense that it doesn’t have to know the conditions that cause validations to appear, only whether there are any).

Alternatively, maybe I could look into whether a custom solution with JS could detect DOM nodes - although, outside of action strings, this seems problematic. (Or maybe a custom JS plugin could allow for field listeners, although that seems like a potentially more complicated solution than wikification, and potentially similarly performance-intensive.)

1 Like