Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Creating an enclosing widget

In SugarCube, the <<if>> macro has a boolean parameter, as well as a closing tag, <</if>> or <<endif>>.

Can I, using <<widget>>, create something similar? I want to make a widget that can accept parameters, as well as having a closing tag.

Example:
<<showIf "showDesc" "Nature">>The tree is green.<<endShow>>
This will only show the "The tree is green." text if showDesc is true and settings.describe is "Nature".

Comments

  • What are you trying to do? As in, why does it require a closing tag at all?
    <<widget "ShowNature">>
        <<if $showDesc>>
            <<if $settings.describe is "nature">>
                <<display $args[0]>>
            <<endif>>
        <<endif>>
    <<endwidget>>
    

    Then just call it with
    <<ShowNature "passage to display">>
    

    where the "passage to display" has the text you want to conditionally show or not show. Then just make different widgets for different $settings.describe values.
  • That's a good Plan B, but I'll be using this very liberally during my story. Having different passages for each and every of them will get old too quickly :pensive: Some of them may be paragraphs long, but some of them will probably be one liners like my example. Putting it in a separate Passage seems overkill.
  • edited February 2017
    Can I, using <<widget>>, create something similar? I want to make a widget that can accept parameters, as well as having a closing tag.
    Unfortunately, no. Widgets are void/self-closing only—i.e. no closing tag.

    For what you want you'd either have to write a custom macro or a custom helper function which you could simply use with the <<if>> macro.

    For an example of the latter: (goes in Story JavaScript)
    window.describe = function (what) {
    	return settings.showDesc && settings.describe === what;
    };
    
    Usage:
    <<if describe("Nature")>>The tree is green.<</if>>
    
  • Thanks, TME, that's a great Plan C.

    For now, I'm going to dive into the Macro API. Do you have any tips aside from the docs?
  • First. Now that I'm not half-asleep, the function example I gave previously didn't correctly handle the "All" value. It should have looked something like the following—as an upgrade, it now matches case-insensitively:
    window.describe = function (name) {
    	if (!settings.showDesc) {
    		return false;
    	}
    
    	var what     = String(name).toLowerCase();
    	var describe = settings.describe.toLowerCase();
    
    	return describe === 'all' || describe === what;
    };
    


    For now, I'm going to dive into the Macro API. Do you have any tips aside from the docs?
    None come immediately to mind. Though, as a simple example, which matches case-insensitively:
    Macro.add('show', {
    	tags    : null,
    	handler : function () {
    		if (this.args.length === 0) {
    			return this.error('no description name specified');
    		}
    
    		if (!settings.showDesc) {
    			return;
    		}
    
    		var what     = String(this.args[0]).toLowerCase();
    		var describe = settings.describe.toLowerCase();
    
    		if (describe === 'all' || describe === what) {
    			jQuery(this.output).wiki(this.payload[0].contents);
    		}
    	}
    });
    

    A slightly more complicated example, which also verifies that the given argument is one of the possible settings.describe values—to protect against fat fingering:
    Macro.add('show', {
    	tags    : null,
    	handler : function () {
    		if (this.args.length === 0) {
    			return this.error('no description name specified');
    		}
    
    		var what       = String(this.args[0]).toLowerCase();
    		var validNames = Setting.get('describe').list.map(function (name) {
    			return name.toLowerCase()
    		});
    
    		if (!validNames.includes(what)) {
    			return this.error('invalid description name "' + this.args[0] + '"');
    		}
    
    		if (!settings.showDesc) {
    			return;
    		}
    
    		var describe = settings.describe.toLowerCase();
    
    		if (describe === 'all' || describe === what) {
    			jQuery(this.output).wiki(this.payload[0].contents);
    		}
    	}
    });
    

    Usage:
    <<show "Nature">>The tree is green.<</show>>
    
  • Thanks again, TME. I had started on the Macro, and your input reminds me about the argument checking.

    In your code, you used:
    jQuery(this.output).wiki(this.payload[0].contents);
    
    Is there a difference from the example in the docs, which used:
    new Wikifier(this.output, this.payload[i].contents);
    

    I mean, I get that the one from the docs is iterating through the contents of each of the tags in the main macro (which I love and will be using). Is there a difference between using new Wikifier and jQuery().wiki()?
  • Is there a difference from the example in the docs, which used:
    new Wikifier(this.output, this.payload[i].contents);
    
    Ah, thanks. That documentation example has been updated to use <jQuery>.wiki() instead.

    […] Is there a difference between using new Wikifier and jQuery().wiki()?
    They do the same basic job, parsing the given content as SugarCube markup and injecting it someplace.

    The <jQuery>.wiki() extension method is documented—meaning I'm committed to supporting it. As noted by its docs, it supports chaining, as one would expect from a jQuery method, and accepts an arbitrary number of content sources. It is also the recommended interface.

    The publicly known Wikifier interface obviously isn't going anywhere—it's too entrenched as a legacy API—however, I do have plans to eventually replace the actual code behind it, so it's going to become a legacy shim at some point.
Sign In or Register to comment.