Howdy, Stranger!

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

Any other user input methods available?

Hello! I've been searching for ways for user to input data, which could be stored, and found only standard javascript alert window with input textbox available. What I would like to use is a textbox for user to type his name or other text, which can be shown directly on a page, and not in the pop-up window. Is there any way to do this? I hope what I have requested is possible.

Comments

  • (you need to state which story format you are using as answers for each can be different. I am going to assume Harlowe)

    1. Harlowe:
    Besides the (prompt:) macro there does not appear to be any built-in way to do so.

    You could try to use standard HTML <input> & <textarea> tags but Harlowe also does not appear to have a submit button macro so you would have to implement one using some HTML and Javascript. To make things more complex I could not determine a way for an Author to use javascript to save the input into a variable nor to load the next passage after someone clicks on the submit button.

    2. SugarCube: (third-party story format)
    This story format has both <<textbox>> and <<button>> macros, which I believe still work in Twine 2.

    But maybe someone else like Leon will have a better answer.
  • I've been batting this problem around over the past day myself using Harlowe. Finally came up with something that's ugly, but seems to work!

    Two parts: one is a custom script that replaces a hook with the value of a textbox. We call that using an onclick attribute on a button in the passage. Here's the script that you add to your javascript file for the story. I'm also adding it to the "customScripts" namespace:
    if (typeof window.customScripts == "undefined") {
    window.customScripts = {
    submitName: function(inputName) {
    //Get the value of the textbox at time of click
    var newName = $("input[name='" + inputName + "']")[0].value;
    //Find the hook node based on name and set the text inside
    $("tw-hook[title*='" + inputName + "']").text(newName);
    //Log the Change
    console.log(inputName + " changed.")
    }
    };
    };
    On the passage end of things you need to make sure that the hook and the input use the same name. The hook in this example is named "fname" and the input has an attribute of "fname" as well. When we call the function we need to give it the string "fname" too. Whenever your player clicks on the button it'll call the script from above. "fname" could be anything you want as long as it's the same for the hook, the input name, and the string you give the function.

    Then, to make things easier to reuse the information later, we do a check every 100ms to set a variable (in this case $rivalName) equal to whatever the hook currently is.

    You and [your unnamed rival]<fname|.

    <input type="text" name="fname" value="Johnson">
    <button type="submit" onclick="customScripts.submitName('fname')">Yes that's it</button>

    (live:100ms)[(set:$rivalName = ?fname)]
    Annoying to set up, however, once it's in place you can use this pattern for any amount of inputs you'd like. Just make sure the hook name and the input name are the same.

    I could simplify this further if there was a way to set Harlowe's variables directly from javascript, but I can't seem to find where it stores them.
  • Thanks! Been trying to solve this too - will give this a go.
  • I tried the example of csalzman but it did not work for me. The $rivalName does not set to anything I put in the box, even after pressing the "Yes that's it" button. The $rivalName remains set at "your unnamed rival".

    The steps I followed were:

    1. Put the first chunk of code into the "Edit Story JavaScript" part of my Twine 2 story.

    2. Put the second lot of code into a start passage called "Passage01" with a Twine link to "Passage 02"

    3. In Passage02, I put "The rival name is $rivalName"

    Any ideas on how to get it to work, as per the example above?
  • Also, how can we get this to work for a "textarea"?
  • This does work JavaScript-wise (the variable is stored and spit out to the Console). I made a minor change to see the name:
    if (typeof window.customScripts == "undefined") {
    	window.customScripts = {
    		submitName: function(inputName) {
    			//Get the value of the textbox at time of click
    			var newName = $("input[name='" + inputName + "']")[0].value;
    			//Find the hook node based on name and set the text inside
    			$("tw-hook[title*='" + inputName + "']").text(newName);
    			//Log the Change
    			console.log(inputName + " changed.")
    			//Show name
    			console.log(newName)
    		}
    	}; 
    };
    
    What’s not happening is that "fname" isn’t communicating properly.

    I have an idea, though, but no time right now… I’ll check this out again later.

    (Btw, this shouldn’t be too difficult to use with a textarea.)

    Tim
  • I tested both versions of the Javascript code using Firefox and Chrome on Windows 7 and they both worked.

    You may want to think about a couple of possible issues:

    1. The timer event created by Harlowe's (live:) macro will keep firing until you manually (stop:) it.

    2. If you show a link to the Reader before they have clicked on the button then it is quite likely that they will click on the link instead of the button.

    The following code solves both of these issues:
    (set: $rivalName to "your unnamed rival")
    You and [$rivalName]<fname|.
    
    <input type="text" name="fname" value="Johnson">
    <button type="submit" onclick="customScripts.submitName('fname')">Yes that's it</button>
    
    |link>[]
    (live:100ms)[
    	(set: $rivalName to ?fname)
    	(if: $rivalName is not "your unnamed rival")[
    		(replace: ?link)[(link-goto: "Next Passage", "Next Passage")]
    		(stop:)
    	]
    ]
    
  • edited May 2015
    Just to be clear... By "works," you mean that the name updated onscreen and not just in the Console?

    This is what didn't work for me... The Console updates, yes, but not the Dom.

    I'll try your version of the code, though.
  • timsamoff wrote: »
    Just to be clear... By "works," you mean that the name updated onscreen and not just in the Console?
    By "works" I mean it updated the hook, the console and the $variable.
  • I tried this in both Chrome and Firefox and it does not work for me.

    Just to be clear, I am using Twine 2.0.4 with Harlowe 1.0.1

    By "does not work" I mean that the variable $rivalName stays set to "your unnamed rival" no matter what i put in the box, or how many times I press the button.

    And I think in your example, greyelf, when I click the button, the links are supposed to show, but nothing happens when I click the button.
  • Just to make sure we are talking about the same thing.

    You placed the Javascript code in your story's Story Javascript area and the passage code in a Passage and it does not work?

    If you open the browser's Developer Tools Console, refresh the page, enter a value and then click the button does the console show an error?
  • Correct in placement of the code/markup… No errors in the Console — in fact, the Console reports everything is working just fine… The "break" is in the fact that the JavaScript is not communicating with the hook (for me anyway).
  • greyelf wrote: »
    Just to make sure we are talking about the same thing.

    You placed the Javascript code in your story's Story Javascript area and the passage code in a Passage and it does not work?

    Yes. I did the above and it does not work.

    On that note, I just noticed in another of my posts, that the forum program added some semicolons to the code I posted. I am a total noob when it comes to JavaScript, so I just copied and pasted the JS code above into the Story JavaScript area. I noticed there are some semicolons in the code. Are they meant to be there?
    greyelf wrote: »
    If you open the browser's Developer Tools Console, refresh the page, enter a value and then click the button does the console show an error?

    It does not show an error. Nothing actually happens. (I entered the value "Peter" and pressed the button).

    The <body> tag that appeared in the developer window on the bottom seems to be automatically highlighted in purple and flickering. (I have attached an image to this post to show you).

    21e871302a5c1ee26fb615faeeadb9.jpg
  • That’s the "Inspect Element" view in your browser, not the Console. In Chrome, go to View > Developer > JavaScript Console. If you use my code above, you’ll see that the "fname" attribute changes and it will spit out whatever name you put in the input field.

    Also, as an answer to your question, JavaScript statements are typically ended with a semicolon (similar to ending a sentence with a period).
  • timsamoff wrote: »
    That’s the "Inspect Element" view in your browser, not the Console. In Chrome, go to View > Developer > JavaScript Console. If you use my code above, you’ll see that the "fname" attribute changes and it will spit out whatever name you put in the input field.

    Also, as an answer to your question, JavaScript statements are typically ended with a semicolon (similar to ending a sentence with a period).

    Okay, I had gone to the developer console. I have now gone to the JavaScript Console, and it is as you say that it mentions that fname changes when I input a new value and click the button. So, it is as you say that the JavaScript is working, but it is not communicating with the twine variable.

    8085954a29ae833586d4d6d705ba41.jpg
  • "Annoying to set up, however, once it's in place you can use this pattern for any amount of inputs you'd like. Just make sure the hook name and the input name are the same."

    I can't make it work with multiple fields, the second always give me an error "not defined". Can you show a basic example, with two fields?
  • Nevermind, made it work:

    Javascript:

    if (typeof window.customScripts == "undefined") {
    window.customScripts = {
    submitName: function(inputName) {
    var newName = $("input[name='" + inputName + "']")[0].value;
    $("tw-hook[name*='" + inputName + "']").text(newName);
    console.log(inputName + " changed.")
    }
    };
    };

    if (typeof window.customScripts == "undefined") {
    window.customScripts = {
    submitName: function(inputHeight) {
    var newHeight= $("input[name='" + inputHeight + "']")[0].value;
    $("tw-hook[name*='" + inputHeight + "']").text(newHeight);
    console.log(inputHeight + " changed.")
    }
    };
    };


    Code (Ok button to valid all fields together):

    Name [...]<fname|. <input type="text" name="fname" value="...">
    Height [...]<fheight|. <input type="text" name="fheight" value="...">

    <button type="submit" onclick="customScripts.submitName('fname');
    customScripts.submitName('fheight')">OK</button>

    (live:100ms)[(set:$yourName = ?fname)(set:$yourHeight = ?fheight)]
  • It's undocumented and perhaps fragile in the long term, but it seems to be possible to write to a global variable from "Story Javascript" like this:

    State.variables[varName] = newValue;

    So this:

    $("tw-hook[title*='" + inputName + "']").text(newName);

    Might become:

    State.variables[inputName] = newName;

    Twine and Harlowe use modern, namespaced Javascript so it is not possible to access those variables from the Javascript console but if you want to explore them you can cache them away this way:

    window.interesting_stuff = {"Engine": Engine, "State": State, "Passages": Passages, "Renderer": Renderer, "Selectors": Selectors, "Utils": Utils}

    console.log("Stored interesting stuff in window.interesting_stuff");

    You can also poke around them with a debugger; statement in your Story Javascript.
  • I want to do something like that to radio input:

    What's your character born place?
    <input type="radio" name="fhome" value="London">London
    <input type="radio" name="fhome" value="São Paulo">São Paulo
    <input type="radio" name="fhome" value="Madrid">Madrid


    Any hint on how to pass the value of fhome? Original function (to input text) is:

    if (typeof window.customScripts == "undefined") {
    window.customScripts = {
    submitName: function(inputName) {
    var newName = $("input[name='" + inputName + "']")[0].value;
    $("tw-hook[name*='" + inputName + "']").text(newName);
    console.log(inputName + " changed.")
    }
    };
    };
  • Nevermind...
    if (typeof window.customScript == "undefined") {
      window.customScript = {
        submitRadio: function(inputRadio) {
    			var newRadio = $("input[name='" + inputRadio + "']:checked")[0].value;
    			$("tw-hook[name*='" + inputRadio + "']").text(newRadio);
    			console.log(inputRadio + " changed to " + newRadio);
        }
      }; 
    };
    
  • The Javascript code created by csalzman locates the related named hook via it's title property, it should be using it's name property instead.

    The following Javascript corrects this issue:
    if (typeof window.customScripts == "undefined") {
    	window.customScripts = {
    		submitName: function(inputName) {
    			//Get the value of the textbox at time of click
    			var newName = $("input[name='" + inputName + "']")[0].value;
    			//Find the hook node based on name and set the text inside
    			$("tw-hook[name*='" + inputName + "']").text(newName);
    			//Log the Change
    			console.log(inputName + " changed.")
    		}
    	}; 
    };
    
  • I have two questions...
    Greyelf's edited javascript works perfectly for text input fields, but the downside is that it saves the variable as a string, which doesn't work quite so well when you need a variable as a number (say character age, or similar stuff). Is there a way to modify it to save input as a non-string? Or is there a way to 'convert' a string containing numbers into a numerical value?

    Second, is there a way to make a similar script for a dropdown menu? Since it's a <select> rather than an <input> tag, I have no idea how to edit the javascript to do what I want it to do. I can't even figure out how to get l3m35's radio input script to work (it errors out), and that's still an <input> tag.
Sign In or Register to comment.