Howdy, Stranger!

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

[Sugarcube 2] Specifying max length for macro?

Hi,

I'm using Twine 1.4.2 with Sugarcube 2. I want to have the player enter some text into a single-line <<textbox>> macro, but I don't want them to be able to enter something too long - I want to cap the input at a certain number of characters.

Is it possible to specify a max length for the <<textbox>> so that the player can't enter more characters than that? Or am I going to have to let them enter as many as they like and then tell them it was too long?

Comments

  • You could do something like the following.

    Put the following code in a script section: (Twine 1: script-tagged passage; Twine 2: Story JavaScript)
    /*
    	Set the maximum length of a <<textbox>> macro.
    
    	Usage: setTextboxMaxLength(storyVarName, maxLength)
    		e.g. setTextboxMaxLength('$foo', 8)
    */
    window.setTextboxMaxLength = function (storyVarName, maxLength) {
    	var textboxId = '#textbox-' + Util.slugify(storyVarName);
    	postdisplay[textboxId + '-maxlength'] = function (taskName) {
    		delete postdisplay[taskName];
    		$(textboxId)
    			.attr('maxlength', maxLength)
    			.css({
    				'min-width' : 'initial',
    				width       : maxLength + 'em'
    			});
    	};
    };
    


    Usage:
    <<textbox "$foo" "" autofocus>>
    <<script>>setTextboxMaxLength('$foo', 8);<</script>>
    
    That will set the <<textbox>> which alters $foo to a maximum length of eight characters.
  • That code didn't work for me, but I'll look into how I can do it with Javascript, thanks.
  • edited March 2017
    The code has been tested and does work, so if it didn't work for you, then you probably did something wrong somewhere. I'd recheck your steps.

    You say you're using SugarCube v2, what's the full version?
  • That code didn't work for me...
    The posted example works as is.

    Could you supply an example of the code you were using that did not work for you?
  • Thanks again for your answer. Your code does work when I make a new Twine story and enter it as you posted it. I've done some experimenting and I think what's different about my code is that the <<textbox>> macro isn't in the page to start off with, but is being added with a <<replace>>.

    This code doesn't limit the size of the textbox:
    <div id="test-block">Test block</div>
    
    <<link "Click here to replace">>
    	<<replace "#test-block">>
    		<<textbox "$foo" "" autofocus>>
    		<<script>>setTextboxMaxLength('$foo', 8);<</script>>
    	<</replace>>
    <</link>>
    

    (My own code is more complicated, and the textbox is actually inside another passage that's being displayed with the display macro inside the replace, but this is the simplest code I could come up with that demonstrates the problem.)

    I'm using Sugarcube 2.12.0 (I think).
  • The solution supplied by TheMadExile uses an event (postdisplay) triggered by passage traversal. That event does not occur when a passage is displayed using a <<display>> macro, nor when the current page is updated using <<replace>>, which is why that setTextboxMaxLength function is not working.

    The following is a modified version of that function that tries to instantly update the input element created by the <<textbox>> macro, this version will not work for a <<textbox>> macro used directly in the current passage.
    /*
    	Set the maximum length of a <<textbox>> macro.
    
    	Usage: setTextboxMaxLength(storyVarName, maxLength)
    		e.g. setTextboxMaxLength('$foo', 8)
    */
    window.setTextboxMaxLength = function (storyVarName, maxLength) {
    	var textboxId = '#textbox-' + Util.slugify(storyVarName);
    	$(textboxId)
    			.attr('maxlength', maxLength)
    			.css({
    				'min-width' : 'initial',
    				width       : maxLength + 'em'
    			});
    };
    

    To use it modify your example like so:
    <<link "Click here to replace">>
    	<<replace "#test-block">>
    		<<textbox "$foo" "" autofocus>>
    	<</replace>>
    	<<script>>setTextboxMaxLength('$foo', 8);<</script>>
    <</link>>
    
    ... notice it is called after the <<replace>> has finished, this should allow the input element created by the <<textbox>> macro to exist before the setTextboxMaxLength tries to modify it.
  • edited March 2017
    […] I've done some experimenting and I think what's different about my code is that the <<textbox>> macro isn't in the page to start off with, but is being added with a <<replace>>.
    You should have mentioned that from the beginning. I don't say this to castigate you. This is simply one of those things that unless we know in advance, we'll probably offer advice that doesn't fit your situation. In the future, please try to make note of all pertinent information.

    In particular, when you're using any kind of link macro, you're doing things asynchronously and that is something you should most definitely mention.

    Anyway. greyelf's revised solution should work for what you're doing.

    greyelf wrote: »
    The solution supplied by TheMadExile uses an event (postdisplay) triggered by passage traversal. That event does not occur when a passage is displayed using a <<display>> macro, nor when the current page is updated using <<replace>>, which is why that setTextboxMaxLength function is not working.
    Calling out <<display>> here is something of an unintentional red herring. While it's true that invoking <<display>> does not trigger navigational tasks, it's also mostly irrelevant here. The key issue is here is one of when, not how. The "when" in this case is "whenever the player activates the <<link>> containing the <<replace>>, which is long after all navigational tasks for the current turn have been done".

    For example, the following would work with my original code even though it uses <<display>>:
    :: Texty Boxy
    <<textbox "$foo" "" autofocus>>
    
    
    :: Some Other Passage
    <<display "Texty Boxy">>
    <<script>>setTextboxMaxLength('$foo', 8);<</script>>
    
  • Thank you both! The revised solution works in my code.

    And apologies for not mentioning it from the beginning; I'm not used to thinking in terms of events being triggered, so I didn't realize it was pertinent. I'll be sure to mention it if I have another problem like this.
  • Calling out <<display>> here is something of an unintentional red herring.
    You are correct but I was trying to make it clear that the postdisplay event is not triggered by <<display>> macro calls, only by passage traversals.
Sign In or Register to comment.