Harlowe 3.1.0 - Customizing (alert:)

Hello Interactive Fiction Community,
I am utilizing the (alert:) functionality which generates a dialog box. I’d like to adding a warning symbol image onto the dialog box and perhaps change the color of it from a black background to a grey background and from a white border to a white border. Is it possible to do that?

Thank you!!

1 Like

The quickest way to see the HTML and CSS being used to show the ‘alert’ dialog of Harlowe 3.1.0 is to add something like the following to the initial Passage of a test project…

(alert: "The quick brown fox jumps over the lazy dog.")

…and then use the Web Developer Tools of either the Twine 2.x application or your favourite web-browser to Inspect the dialog’s HTML (and associated CSS) while playing/viewing the story.

The structure of the ‘dialog’ related HTML looks like…

<tw-backdrop data-raw="">
	<tw-dialog data-raw="">
		The quick brown fox jumps over the lazy dog.
		<br>
		<tw-align style="text-align: right;">
			<br>
			<tw-link tabindex="0" data-raw="">OK</tw-link>
		</tw-align>
	</tw-dialog>
</tw-backdrop>

…and the CSS being used to style the two main elements (<tw-backdrop> and <tw-dialog>) is…

tw-backdrop {
    z-index: 999996;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0,0,0,0.8);
    display: flex;
    align-items: center;
    justify-content: center;
}

tw-dialog {
    z-index: 999997;
    position: fixed;
    left: auto;
    right: auto;
    bottom: auto;
    top: auto;
    border: #fff solid 2px;
    padding: 2em;
    color: #fff;
    background-color: #000;
    display: block;
    max-width: 50vw;
    max-height: 75vh;
    overflow: hidden;
}

The CSS that targets the <tw-dialog> element controls the look of the dialog itself, so altering its background colour is as simple as add adding CSS like the following to your project’s Story Stylesheet area.

tw-dialog {
	background-color: grey;
}

see: CSS background-color property, and the associated color value documentation.

If you want to also change the dialog’s border then could add a CSS border property to the above example…

tw-dialog {
	background-color: grey;
	border: orange solid 2px;
}

This is going to be more difficult for a number of reasons, two of them being:

  1. There no simple way to distinguish one dialog type from another. (alert vs confirm)
  2. There is no event to associate ‘dialog’ HTML structure changing JavaScript with.

One possible solution is to use CSS like the following to associate a background image with the dialog’s <tw-align>

tw-dialog tw-align:last-of-type {
	background-image: url('warning.png');
	background-repeat: no-repeat;
	background-size: contain;
}

…however that image will also appear within any (confirm:) or (prompt:) dialog you show.

Hi @Greyelf, wow! So I followed as you suggested and tested it in a separate code - that worked just fine! Then I tried bringing it back to the current game I’m working on and it was giving me all sorts of errors.I have pasted the JS code and CSS codes below (in both circumstances, the code you provided are at the very bottom). I also pasted the two passages that implements both the processInputElements function and the (alert:) and uploaded pictures of the error messages I received. I can’t post the html file unfortunately, but I have it here published in neocities if that helps too!

JavaScript:

window.Harlowe = { 'State' : State };
window.processInputElements = function () {
    $('input[data-varname]').on('change', function () {
        var varName = $(this).attr('data-varname');
        Harlowe.State.variables[varName] = this.value;
    });
		$('select[data-varname]').on('change', function () {
        var varName = $(this).attr('data-varname');
        Harlowe.State.variables[varName] = this.value;
    });
};

<tw-backdrop data-raw="">
	<tw-dialog data-raw="">
		The quick brown fox jumps over the lazy dog.
		<br>
		<tw-align style="text-align: right;">
			<br>
			<tw-link tabindex="0" data-raw="">OK</tw-link>
		</tw-align>
	</tw-dialog>
</tw-backdrop>

CSS Stylesheet Code

tw-story {
 /* Add a vote background */
  background-image: url("https://www.acslaw.org/wp-content/uploads/2018/03/vote-hands.jpg");
  background-size: cover; 
}
tw-story[tags~="About-Digital-Commons"]{
/* Background photo for Digital Studies Center*/
  background-image: url("https://www.inquirer.com/resizer/Ck1oq5wXPRYECJONFej6Xp3perc=/1400x932/smart/arc-anglerfish-arc2-prod-pmn.s3.amazonaws.com/public/3SELX2I4WJDOFA3YXHSG5XCOMM.jpg");
  background-size: cover;
}
tw-story[tags~="About-OCE"]{
/* Background photo for Office of Civic Engagement*/
  background-image: url("https://www.camden.rutgers.edu/sites/camden/files/mapimage/civic-engagement.jpg");
  background-size: cover;
}

tw-story[tags~="About-LWVNJ"]{
/* Background photo for League of Women Voters of New Jersey*/
  background-image: url("https://images.squarespace-cdn.com/content/v1/568aa781a976af7af9b0e2d3/1535642426802-YDL1Z13M9N0XDQELQ0C0/ke17ZwdGBToddI8pDm48kHRQmmGuFIdqE7GSc9pC9HN7gQa3H78H3Y0txjaiv_0fDoOvxcdMmMKkDsyUqMSsMWxHk725yiiHCCLfrh8O1z5QPOohDIaIeljMHgDF5CVlOqpeNLcJ80NK65_fV7S1UbmS8kTOFb-kHQWdCIhhMyl9udsnlBX4KvtG_wW4fLYyxrxjPk_CVDSDL5ouV0jMuQ/Hear+Us+Vote+Shirt.jpg");
  background-size: cover;
}

tw-story[tags~="Black-Background"]{
 /* Black background */
  background-image: url("https://upload.wikimedia.org/wikipedia/commons/7/71/Black.png");
  background-size: cover;
}

tw-story[tags~="DACA-Story"]{
 /* Background for DACA Story*/
  background-image: url("https://images.axios.com/_BuKsTVML9o3TIlWB2RRt9PSQMc=/0x0:5255x2956/1920x1080/2019/11/12/1573586158785.jpg");
  background-size: cover;
}


tw-story[tags~="International-Student-Story"]{
 /* Background for DACA Story*/
  background-image: url("https://www.uclahealth.org/international-services/images/carousel/Internationa-Flags-2000x1200.jpg");
  background-size: cover;
}

/*default font type and size*/
tw-passage {
  font-family: calibri;
  text-align: left; 
  font-size: 5vh;
  font-size: 5vw;
  font-size: 5vmin;
  line-height: normal;
 
color: black;
  
    /* The following changes the text box */
  border: 5px groove gray; /* Gray border around the box */
  border-radius: 25px; /* Rounded corners on the box */
  background: rgba(255,255,255,0.7); /* 30% transparent box */
  padding: 25px;
}
/* The following is almost identical to the above, but changes the text box to 10% transparent for any picture that renders the text harder to read */
tw-passage[tags~="Ninety-Box"] {
  font-family: calibri;
  text-align: left; 
  font-size: 5vh;
  font-size: 5vw;
  font-size: 5vmin;
  line-height: normal;
 
color: black;
  
    /* The following changes the text box */
  border: 5px groove gray; /* Gray border around the box */
  border-radius: 25px; /* Rounded corners on the box */
  background: rgba(255,255,255,0.9); /*10% transparence*/
  padding: 25px;
}

/* The following is almost identical to the above, but changes the text box to 20% transparent for any picture that renders the text harder to read */
tw-passage[tags~="Eighty-Box"] {
  font-family: calibri;
  text-align: left; 
  font-size: 5vh;
  font-size: 5vw;
  font-size: 5vmin;
  line-height: normal;
 
color: black;
  
    /* The following changes the text box */
  border: 5px groove gray; /* Gray border around the box */
  border-radius: 25px; /* Rounded corners on the box */
  background: rgba(255,255,255,0.8); /*20% transparence*/
  padding: 25px;
}

/*The following code effectively hides the dialogue box and makes the text white*/
tw-passage[tags~="No-Dialogue-Box"]{
  font-family: calibri;
  text-align: left; 
  font-size: 5vh;
  font-size: 5vw;
  font-size: 5vmin;
  line-height: normal;
 
color: white;
border: 0px groove gray; /* Gray border around the box */
background: rgba(255,255,255,0); /* 30% transparent box */
}

/*deafult hyperlink color is blue*/
tw-link {
  color: blue;
}

tw-link.visited {
  color: blue;  
}

/*different color options for hyperlinks*/
.redlink tw-link { color : red;} /*red hyperlink format*/
.purplelink tw-link {color: purple;} /*purple hyperlink format*/
.orangelink tw-link {color: orange;} /*orange hyperlink format*/
.navylink tw-link {color: navy;} /*navy hyperlink format*/
.magentalink tw-link {color: magenta;} /*magenta hyperlink format*/
.greenlink tw-link {color: green;} /*green hyperlink format*/
.limelink tw-link {color: lime;} /*lime hyperlink format*/
.whitelink tw-link {color: white;} /*white hyperlink format*/

/*All hyperlinks will turn white with a blue outline when hovering the mouse on them*/
.enchantment-link:hover, tw-link:hover {
	color: white;
  	text-shadow: 1px 1px 2px blue;
  
}
/*All hyperlinks will remain white white a blue outline when hovering the mouse on them despite the fact that they were already visited/clicked on*/
.enchantment-link.visited:hover, tw-link.visited:hover {
	color: white;
  	text-shadow: 1px 1px 2px blue;
  
}
tw-sidebar {
  display:none; /* Hide the undo and redo buttons */

}
tw-passage[tags~="About"] { /*changed font size for description passages*/
  font-family: calibri;
  text-align: left; 
  font-size: 4vh;
  font-size: 4vw;
  font-size: 4vmin;
  line-height: normal;
}

img.right-side {
  float: right;
}

img.left-side{
  float: left;
}

img.small {
  height: 3em;
}

img.medium {
  height: 6em;
  width:  10em;
}

img.large {
  height: 8em;
  width:  8em;
}

hr.clear {
  clear: both;
  border: 0;
}

p {
	margin-top: 0.15em;
	margin-bottom: 0em;
}

tw-backdrop {
    z-index: 999996;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0,0,0,0.8);
    display: flex;
    align-items: center;
    justify-content: center;
}

tw-dialog {
    z-index: 999997;
    position: fixed;
    left: auto;
    right: auto;
    bottom: auto;
    top: auto;
    border: #fff solid 2px;
    padding: 2em;
    color: #fff;
    background-color: grey;
    display: block;
    max-width: 50vw;
    max-height: 75vh;
    overflow: hidden;
    border: orange solid 2px;
}

tw-dialog tw-align:last-of-type {
	background-image: url('https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Warning.svg/832px-Warning.svg.png');
	background-repeat: no-repeat;
	background-size: contain;
}

Passage with processInputElements -> leads to the next passage

{(set: $userName to "")
Before we begin, what is your ''//first name//''?}
<input type="text" data-varname="userName">

<span style="font-size: 4vw;">(link-goto: "Done", "Story Choice")</span><span style="color:#838383;font-size: 1.75vw;"> <-- Click this when you finished writing your name!</span>
<script>processInputElements();</script>

Passage 2 - catches the $userName value and passes that to the next passage

{

	(set: $found to false)

	(if: $userName's length > 0)[

		(set: _chars to (lowercase: $userName))

		(set: $last to "")

		(set: $count to 1)

		(for: each _chr, ..._chars)[

			(unless: $found)[

				(if: _chr is $last)[

					(set: $count to it + 1)

				]

				(else:)[

					(set: $count to 1)

				]

				(set: $last to _chr)

				(set: $found to ($count is 3))

			]

		]

	]

(if: $found)[(set: $userNameError to "Invalid")(go-to: "Invalid Name Check")](else-if: $userName is "")[(set: $userNameError to "no text")(go-to: "Invalid Name Check")](else-if: "0123456789!@#$%^&*()-_+={[}]:;\"|'<,>.?/`~" contains any of $userName)[(set: $userNameError to "Invalid")(go-to: "Invalid Name Check")](else-if: $userName contains " ")[(set: $userNameError to "not first name")(go-to: "Invalid Name Check")](else-if:  $userName's length is < 3)[(set: $userNameError to "not three letters")(go-to: "Invalid Name Check")](else:)[(align: "<==")[It's nice to meet you (upperfirst: $userName)!]]}
(set: $a to (shuffled: "story", "story2", "story3"))
Please select a story and press play when you're ready:
(set: $story to "this does not matter")
(dropdown: bind $story, $a's 1st, $a's 2nd, $a's 3rd)[[<p>Play</p>->loading screen]]

Passage with (alert:)! - reverts back to the first passage above if $userName is invalid

{(if: $userNameError is "no text")[Click "OK" to return to the previous page(alert:'Please write your name in the text box and press <u>Done</u>')(go-to: "User Name")](else-if: $userNameError is "Invalid")[Click! "OK" to return to the previous page(alert:"Please provide a valid name")(go-to: "User Name")](else-if: $userNameError is "not first name")[Click "OK" to return to the previous page(alert:"Please provide your first name only")(go-to: "User Name")](else-if: $userNameError is "not three letters")[Click "OK" to return to the previous page(alert:"Please provide a name with at least 3 letters")(go-to: "User Name")]}

Attachments
Error message when I enter the game
Starting Passage error


Error message for the passage that uses process input elements
Process Input elements error passage

The ‘dialog’ related HTML I included in my previous comment was for informational purposes only, so you could see what HTML Harlowe generates when you use a (alert:) macro. The large block of CSS that directly followed the HTML structure was also for informational purposes only, so you would know the default CSS Harlowe uses to style the dialog shown by the (alert:), (confirm:) and (prompt:) macros.

The Story JavaScript area of your project is for JavaScript code only, you are seeing the first of your error message because you placed HTML code in that area. Remove the HTML code from your Story JavaScript area and both of those error messages should go away.

You also don’t need the tw-backdrop based CSS rule or the first of the tw-dialog based CSS rules within your project’s Story Stylesheet area, so you can safely delete both of them from that area.

Thank you @Greyelf! This fixed the problem!! I still needed parts of the first tw-dialog so that I could change the color of the (alert:) box, but otherwise things worked really well!!

So onto my next questions :sweat_smile: -->

  1. How do I center the image and or make the image appear to the right of the text? (I’m assuming I’ll have to make the dialog box wider if I were to attempt the second one.
  2. How do I customize the “OK” link - would like to change it from “OK” to “Go back”, move it to the center of the dialog box, and change its static color, its hover color and its visited color.

Thank you!!

Nitan Shanasnitani10

Thank you for your post, I’m new here and trying to make my first Twine, and this is what I’m trying to do, but with three variables, name, surname and email…don’t know if I can ask this here, but how can I make that happen in one screen? I mean to display an error and prevent going forward if not all the three fields are completed?

I set the first passage as:

{(set: $userName to "")(set: $userSurname to "")(set: $userMail to "")
Before starting please complete the following fields: }
Name
<input type="text" data-varname="userName">
Surname
<input type="text" data-varname="userSurname">
Mail
<input type="text" data-varname="userMail">

<span ">(link-goto: "Ready", "Story Choice")</span><span style="color:#838383;font-size: 1.75vw;"> <-- click here when done</span>
<script>processInputElements();</script>

And can’t figure it out how to code the “Story Choice” passage, following your example…also how can this be donde with just one history?

I coded the alert passage as:

{(if: $userNameError is "no text")[Click "OK" to return to the previous page(alert:'write tour name<u>Listo</u>')(go-to: "User Name")](else-if: $userNameError is "Invalid")[Click! "OK" to return to the previous page(alert:"Please provide a valid name")(go-to: "User Name")](else-if: $userNameError is "not first name")[Click "OK" to return to the previous page(alert:"Please provide your first name only")(go-to: "User Name")](else-if: $userNameError is "not three letters")[Click "OK" to return to the previous page(alert:"Please provide a name with at least 3 letters")(go-to: "User Name")]}

{(if: $userSurnameError is "no text")[Click "OK" to return to the previous page(alert:'write your surname<u>Listo</u>')(go-to: "User Name")](else-if: $userSurnameError is "Invalid")[Click! "OK" to return to the previous page(alert:"Please provide a valid name")(go-to: "User Name")](else-if: $userSurnameError is "not first name")[Click "OK" to return to the previous page(alert:"Please provide your first name only")(go-to: "User Name")](else-if: $userSurnameError is "not three letters")[Click "OK" to return to the previous page(alert:"Please provide a name with at least 3 letters")(go-to: "User Name")]}

{(if: $userMailError is "no text")[Click "OK" to return to the previous page(alert:'write your mail<u>Listo</u>')(go-to: "User Name")](else-if: $userMailError is "Invalid")[Click! "OK" to return to the previous page(alert:"Please provide a valid name")(go-to: "User Name")](else-if: $userMailError is "not first name")[Click "OK" to return to the previous page(alert:"Please provide your first name only")(go-to: "User Name")](else-if: $userMailError is "not three letters")[Click "OK" to return to the previous page(alert:"Please provide a name with at least 3 letters")(go-to: "User Name")]}

Just repeating your code and changing the variable names…but don’t know if this doesn’t work because of this code, or for the “Story Selection” passage code…
Thanks in advance!