And Now For Something Fun (i.e., Making Popups Draggable)

...at least fun to me :P

I was trying to make a popup box draggable via mouse, by modifying KV's code from a previous post:

https://textadventures.co.uk/forum/quest/topic/hqokwdlme0wxfjs3h1jssg/movable-compass

The pertinent code is this:

msg ("<div id='compassHolder' style='display:none;'></div>")

JS.eval ("$('#compassLabel').appendTo($('#compassHolder')).css('display', 'none');$('#compassAccordion').insertAfter($('#compassLabel'));var ch = $('#compassHolder');ch.dialog({height: 200, width: 245,close: function(){ch.dialog('close');}});ch.dialog('option', 'title', 'Compass');ch.dialog('open');openCompass = function(){ch.dialog('open');};$('.ui-dialog').css('position', 'fixed');")

As far as I can understand this, KV created a modified dialog box which was already draggable (#compassHolder), and then appended the compass to it. I tried to apply the same concept to a popup box, by applying KV's code to the only built-in Quest function that I could find, ProcessTextCommand_Popup. In the function, there is a variable s that encapsulates all of the popup code, but I couldn't figure out how to append that to KV's dialog box.

Are we having fun yet?


Wow!

For a long time i was wondering if it would be possible to place some things on a small, pop-up window. Things like the "Look at" descriptions or pictures which would appear on a floating smaller window, without interfering on the main "room description". Now i see it is possible, even if i have no clue yet how doing this, as i am very poor on coding. Wonderful work!


This is another guy's code (KV), but he is not around anymore.


What happened to KV?? Am I missing something?


He got a job!


Off the top of my head…

<function name="MakePopup" type="string" parameters="text, title, open">
  if (not IsDefined("title")) {
    title = ""
  }
  else if (TypeOf(title) = "boolean") {
    open = title
    title = ""
  }
  if (not IsDefined ("open")) {
    open = (title = "")
  }
  if (HasInt (game, "last_popup_id")) {
    id = game.last_popup_id + 1
  }
  else {
    id = 1
  }
  game.last_popup_id = 1
  link = "<span  id=\"popuplink"+id+"\" style=\"cursor:pointer;color:" + link + ";\" onclick=\"var dia = $('#popup" + id + "');dia.dialog(dia.dialod('isOpen') ? 'close' :'open');\">"
  script = "$('#popup"+id+"').dialog({show: 'explode'"
  if (not open) {
    script = script + ", autoOpen: false"
  }
  if (title = "" or not TypeOf(title) = "string") {
    link = link + "[popup"
  }
  else {
    link = link + title
    script = script + ", title: '"+title+"'"
  }
  link = link + "</span>"
  script = script + "});"
  msg ("<div id=\"popup" + id + "\">"+text+"</div>")
  JS.eval (script)
  return (link)
</function>

Usage:

  • MakePopup ("Here's some text to show in a popup") - shows a popup, which can be dragged and closed
  • msg (MakePopup ("Here's the text for in the popup", "Click me!")) - makes a link which you can click on to show/hide the popup
  • msg (MakePopup ("This popup will be shown immediately, but there's still a link you can click on to see it again", "click here", true))

I'm sure someone will tell me I made a dumb mistake in that code somewhere; I'm writing this at 7 in the morning after being woken by toothache.


Sorry it's taken me so long to respond, but I had a slew of issues crop up in my game, which I think (fingers-crossed) I have finally fixed.

@mrangel
I inserted your code into full code view, but the game won't load due to various XML syntax errors (which is not surprising given your groggy, pain-ridden state). I tried to fix them one by one, but was not sure if I was really fixing anything, and there were some that I just didn't know how to fix. Maybe you could post some revised code, please?

Also would wearing a nightguard help? : )


Well, straight away I notice that I missed out the <![CDATA and ]]>.
Where's the next error?


OK... actually tested it now. Three errors fixed (link where it should have been game.defaultlinkforeground, the missing <![CDATA[, and typo dialod for dialog).

EDIT: Made a few changes to make it more flexible.

<function name="MakePopup" type="string" parameters="text, title, open"><![CDATA[
  if (not IsDefined("title")) {
    title = ""
  }
  else if (TypeOf(title) = "boolean") {
    if (IsDefined ("open")) {
      temp = open
      open = title
      title = temp
    }
    else {
      open = title
      title = ""
    }
  }
  if (StartsWith (title, "@@")) {
    linktext = ""
    title = Mid (title, 3)
  }
  else if (EndsWith (title, "@@")) {
    linktext = Left (title, LengthOf(title) - 2)
    title = ""
  }
  else if (Instr (title, "@@") > 0) {
    parts = Split (title, "@@")
    linktext = ListItem (parts, 0)
    title = ListItem (parts, 1)
  }
  else {
    linktext = title
  }
  if (not IsDefined ("open")) {
    open = (linktext = "")
  }
  if (HasInt (game, "last_popup_id")) {
    id = game.last_popup_id + 1
  }
  else {
    id = 1
  }
  game.last_popup_id = id
  link = "<span  id=\"popuplink"+id+"\" style=\"cursor:pointer;color:" + game.defaultlinkforeground + ";\" onclick=\"var dia = $('#popup" + id + "');dia.dialog(dia.dialog('isOpen') ? 'close' :'open');\">"
  script = "$('#popup"+id+"').dialog({show: 'explode'"
  if (not open) {
    script = script + ", autoOpen: false"
  }
  if (linktext = "" or not TypeOf(linktext) = "string") {
    link = link + "[popup]"
  }
  else {
    link = link + linktext
  }
  if (TypeOf(title) = "string" and not Equal(title, "")) {
    script = script + ", title: '"+title+"'"
  }
  link = link + "</span>"
  script = script + "});"
  msg ("<div id=\"popup" + id + "\">"+text+"</div>")
  JS.eval (script)
  return (link)
]]></function>

This function outputs the popup, and returns the link that you can click on to show the popup.

  • The first parameter is the text (or HTML) to go in the popup.
  • The second parameter is the text for the link, and also goes in the title bar of the popup.
    • You can get the link text and title to be different by using, for example, "click here@@This is a popup"
    • If it is missing, the link will contain the text "[popup]" and the popup's title bar will be blank
  • If the third parameter is true, the popup will be open to start with.
    • If it isn't specified, the popup will start open if a link text wasn't specified

If you only supply two parameters, it will look if the second one is a string or a boolean to decide which one is not specified.

Note that you can only use functions with missing parameters, so you can do:

somevariable = MakePopup("Here's a popup that appears right away and doesn't have a title")

(and then discard the variable if you don't want to show the link).
But you can't do:

MakePopup ("This will give an error because you haven't passed the function enough parameters.")

Very cool, thank you!

I can't get an image to display in the popup, though. So I have an object named "widget". I put MakePopup in the object's description with all 3 parameters. In the "text" parameter, I have:

"<img src=\"SomeImage.jpg\" alt=\"dummy\">"

"SomeImage.jpg" doesn't show (although a missing image icon is there). The image file is in the same folder as the Quest files.


There's a function that returns the address of an image. I think it's GetFileURL("SomeImage.jpg"), but not sure off the top of my head. It's because of the way Quest handles file hosting.
So your expression would be: "<img src=\"" + GetFileURL("SomeImage.jpg") + "\" alt=\"dummy\">"

(There really should be a text processor command for that)


Silly me, I forgot about that. Yes, it works now! I just have to adjust the dialog box's properties now. Thanks again!


Hmm... that's a good point. It would be convenient if you could pass arbitrary parameters to the JS.

Let me see…

Rather messy untested code
<function name="MakePopup" type="string" parameters="arg1, arg2, arg3, arg4, arg5"><![CDATA[
  if (not IsDefined("arg1") {
    arg1 = null
  }
  if (not IsDefined("arg2") {
    arg2 = null
  }
  if (not IsDefined("arg3") {
    arg3 = null
  }
  if (not IsDefined("arg4") {
    arg4 = null
  }
  if (not IsDefined("arg5") {
    arg5 = null
  }

  if (EndsWith (TypeOf (arg1), "dictionary")) {
    params = arg1
  }
  else if (EndsWith (TypeOf (arg2), "dictionary")) {
    params = arg2
  }
  else if (EndsWith (TypeOf (arg3), "dictionary")) {
    params = arg3
  }
  else if (EndsWith (TypeOf (arg4), "dictionary")) {
    params = arg4
  }
  else if (EndsWith (TypeOf (arg5), "dictionary")) {
    params = arg5
  }
  else {
    params = NewDictionary()
  }
  matchedstrings = 0
  if (DictionaryContains (params, "content")) {
    text = DictionaryItem (params, "content")
  }
  else {
    if (TypeOf (arg1) = "string") {
      text = arg1
      matchedstrings = 1
    }
    else if (TypeOf (arg2) = "string") {
      text = arg2
      matchedstrings = 2
    }
    else if (TypeOf (arg3) = "string") {
      text = arg3
      matchedstrings = 3
    }
    else if (TypeOf (arg4) = "string") {
      text = arg4
      matchedstrings = 4
    }
    else if (TypeOf (arg5) = "string") {
      text = arg5
      matchedstrings = 5
    }
    else {
      text = ""
    }
    dictionary add (params, "content", text)
  }
  if (DictionaryContains (params, "title")) {
    title = DictionaryItem (params, "title")
  }
  else {
    if (TypeOf (arg1) = "string" and matchedstrings < 1) {
      title = arg1
      matchedstrings = 1
    }
    else if (TypeOf (arg2) = "string" and matchedstrings < 2) {
      title = arg2
      matchedstrings = 2
    }
    else if (TypeOf (arg3) = "string" and matchedstrings < 3) {
      title = arg3
      matchedstrings = 3
    }
    else if (TypeOf (arg4) = "string" and matchedstrings < 4) {
      title = arg4
      matchedstrings = 4
    }
    else if (TypeOf (arg5) = "string" and matchedstrings < 5) {
      title = arg5
      matchedstrings = 5
    }
    else {
      title = ""
    }
  }
  if (DictionaryContains (params, "linktext")) {
    linktext = DictionaryItem (params, "linktext")
  }
  else if (StartsWith (title, "@@")) {
    linktext = ""
    title = Mid (title, 3)
  }
  else if (EndsWith (title, "@@")) {
    linktext = Left (title, LengthOf(title) - 2)
    title = ""
  }
  else if (Instr (title, "@@") > 0) {
    parts = Split (title, "@@")
    linktext = ListItem (parts, 0)
    title = ListItem (parts, 1)
  }
  else {
    if (TypeOf (arg1) = "string" and matchedstrings < 1) {
      linktext = arg1
      matchedstrings = 1
    }
    else if (TypeOf (arg2) = "string" and matchedstrings < 2) {
      linktext = arg2
      matchedstrings = 2
    }
    else if (TypeOf (arg3) = "string" and matchedstrings < 3) {
      linktext = arg3
      matchedstrings = 3
    }
    else if (TypeOf (arg4) = "string" and matchedstrings < 4) {
      linktext = arg4
      matchedstrings = 4
    }
    else if (TypeOf (arg5) = "string" and matchedstrings < 5) {
      linktext = arg5
      matchedstrings = 5
    }
    else {
      linktext = title
    }
  }
  if (not DictionaryContains (params, "title")) {
    dictionary add (params, "title", title)
  }
  if (not DictionaryContains (params, "linktext")) {
    dictionary add (params, "linktext", linktext)
  }
  if (DictionaryContains (params, "autoOpen")) {
    open = DictionaryItem (params, "autoOpen")
  }
  else {
    if (TypeOf (arg1) = "boolean") {
      open = arg1
    }
    else if (TypeOf (arg2) = "boolean") {
      open = arg2
    }
    else if (TypeOf (arg3) = "boolean") {
      open = arg3
    }
    else if (TypeOf (arg4) = "boolean") {
      open = arg4
    }
    else if (TypeOf (arg5) = "boolean") {
      open = arg5
    }
    else {
      open = (linktext = "")
    }
    dictionary add (params, "autoOpen", open)
  }
  if (DictionaryContains (params, "id")) {
    id = DictionaryItem (params, "id")
  }
  else {
    if (HasInt (game, "last_popup_id")) {
      id = game.last_popup_id + 1
    }
    else {
      id = 1
    }
    game.last_popup_id = id
    dictionary add (params, "id", id)
  }
  if (not DictionaryContains (params, "open")) {
    dictionary add (params, "open", "explode")
  }
  link = "<span  class=\"popuplink"+id+"\" style=\"cursor:pointer;color:" + game.defaultlinkforeground + ";\" onclick=\"var dia = $('#popup" + id + "');dia.dialog(dia.dialog('isOpen') ? 'close' :'open');\">"
  if (linktext = "" or not TypeOf(linktext) = "string") {
    link = link + "[popup]"
  }
  else {
    link = link + linktext
  }
  link = link + "</span>"
  scriptparams = NewStringDictionary()
  foreach (key, params) {
    if (not ListContains (Split("id;content;linktext"), key)) {
      value = DictionaryItem (params, key)
      dictionary add (scriptparams, key, ToString(value));
    }
  }
  JS.eval ("MakePopup = function(id,text,params) {$.each(params, function (k,v) {if(v=='false') {params[k] = false;} if(v=='true') {params[k] = true;}}); if ($('#popup'+id).length == 0) {$('<div>', {id: 'popup'+id}).appendTo('#divOutput').html(text).dialog(params);} else { if (text) {$('#popup'+id).html(text);} if (params) {$('#popup'+id).dialog("options", params)}; } };")
  JS.MakePopup (id, text, scriptparams)
  return (link)
]]></function>

(noting that it would probably be neater to remove the `JS.eval` line, and put it in your UI initialisation script instead, or put it in a JS file)

This one is a little hairy. Most of the function is actually dealing with the parameters, so it doesn't matter what order you put them in. It will look at up to 3 string parameters (the popup contents, title, and link text respectively), one boolean parameter (whether the popup should be open when it's created), and one dictionary parameter to contain other values.

It doesn't matter if the dictionary comes before or after the string parameters, and the same for the boolean.

The dictionary's keys may contain some of:

  • content - the text for the popup
  • id - an id for the popup. Using the same ID twice will result in changing the contents of the existing popup rather than creating a new one
  • title - the title for the popup
  • linktext - text for the link returned by MakePopup
  • autoOpen - boolean. Is the dialog visible. (I haven't tested whether setting this one 'true' on an existing ID will show it again)
  • closeOnEscape - boolean. Can the player press their escape key to close the popup?
  • closeText - string. Mouseover text for the popup's close button
  • draggable - boolean
  • width and height - in pixels or "auto"
  • show and hide - the names of jQueryUI animation effects, such as "slideUp", "fold", or "explode".
  • maxHeight, maxWidth, minHeight and minWidth - allow you to limit the size that the player can resize the popup to
  • modal - boolean. If true, the popup will prevent the player clicking anything else while it is open
  • resizable - boolean; can the player resize the popup

I'm using your first function for now. When you click-open an object's popup link a second time (without closing the first one), another of the same popup window is opened. How do you make it so that the first one will automatically close? I tried making the id of every popup = 1, but, strangely, there was no change.


When I tested it, clicking the link would toggle the popup correctly. Not sure what the difference is.
I'll take another look in the morning.

I'm going to be testing the later version, anyway. I think that for a lot of uses, like popping up a window with a character's stats, you would want to have the ability to change the popup's contents using a simple function.


Ok, I'll try the second version...


Ok, I got the second version working. I got the popup to only display once by setting the id to always be 1. A few questions...

  1. Where is the linktext supposed to show up? I dont' see it anywhere.

  2. I was going to set up the popup's properties (height/width, background color, fixed position, etc.) directly in the script, bypassing the parameters. Where do I do type this?

  3. The "explode" animation doesn't seem to work anymore, but it did in the first version?


The function returns a string. So that you can put the link in the middle of a message.

Usage with all the features enabled should look something like:

params = NewDictionary()
dictionary add (params, "width", 399)
dictionary add (params, "height", 55)
dictionary add (params, "resizable", false)
dictionary add (params, "title", "this is a popup")
dictionary add (params, "hide", "explode")
dictionary add (params, "show", "left")
dictionary add (params, "id", "my-popup")
link = MakePopup ("Here's the text that goes in the popup", "click here", params)
msg ("This is a popup test. " + link + " to see the popup.")

I've not tested this one yet, so it might have some issues with some parameters not behaving as expected.


I gave up. Couldn't get most of the properties to work. Also, couldn't stop multiple popups from coming up for the same object. Thanks anyways.


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums