Drop-Down List in a Frame

Discuss macro implementations, ask for macro help (to share your creations, see User Creations, probably either Campaign Frameworks or Drop-in Resources).

Moderators: dorpond, trevor, Azhrei, giliath, jay, Mr.Ice

Fobbo
Giant
Posts: 196
Joined: Wed Feb 01, 2006 2:11 pm

Re: Drop-Down List in a Frame

Post by Fobbo »

Thank you again. I am really learning a lot about macro creation with the notes and help you are providing.

After doing some more thinking about what I am looking to do and writing it down, I think I am going to approach it a little different. Instead of having a formatted whisper sent to the user, I will send a link that will open a frame with the information.

I start to work on it a little this morning but could not get the arg(s) to work.

Here is the code I have so far:

macro to create the link:

Code: Select all

[if( json.type( macro.args )!="OBJECT" ), code:{  <!-- Form data not submitted, (re-)draw the frame. -->
   [h: playerList = getAllPlayerNames() ]
   [H: thisMacro = getMacroName()+"@this" ]  <!-- why have to change your code, just because you renamed your macro later? ;) -->
   [frame("MKCDC15","width=200;height=300"):{
      <html>
           <head>
                <title>Monster Knowledge Check DC15</title>
           </head>
           <body><form name ="MKCDC15" method="json" action='[r:macroLinkText( thisMacro, "none", "", currentToken() )]'><!-- the form is sent to this macro, output displayed to "none", no arguments, with the current token as focus. -->
               <table border="0" cellpadding="0" cellspacing="0">
                   <tr>
                      <th>
                             Send To <small>([R:macroLink("Refresh Player List", thisMacro, "none")])</small>
                      </th>
                  </tr>
                  <tr>
                    <td>
      [R: listFormat( playerList, "<select name='Player'>%list</select>", "<option value='%item'>%item</option>", "" )]
                    </td>
                  </tr>
                 <tr><td align="center">
             <input type='submit' value='Send' ><input type='hidden' name='tName' value='[R: token.name]' >
           </td></tr>
      </table>
      </html>
   }]
   [h:abort(0)]
};{
   <!-- process form data submitted as a json object (in 'macro.args') -->
   [H: targetName = json.get( macro.args, 'Player' )]<!-- contains the literal value, not an index.  See how much fun html forms can be? -->
   [h: arg = json.get(macro.args, 'tName')]
   [h: testString = macroLink("Click This" , "displayMK@this", "self")]
   [h: sendTo = json.fromList(targetName)]
   [H: outputTo(sendTo, testString)]  <!-- this is queued output: it will be sent to chat after this macro stops. -->
}]
macro for the frame the user will open from the link:

Code: Select all

[h: tName = json.get(macro.arg, "tName")]

[frame("MK Display"): {
Display MK [r:tName]
}]

User avatar
Rumble
Deity
Posts: 6235
Joined: Tue Jul 01, 2008 7:48 pm

Re: Drop-Down List in a Frame

Post by Rumble »

It's macro.args - that might be sufficient to fix the problem!

Fobbo
Giant
Posts: 196
Joined: Wed Feb 01, 2006 2:11 pm

Re: Drop-Down List in a Frame

Post by Fobbo »

I figured it out and got it working. I finished up each of the different Monster Check DC display macros. All I have left is to make it easier for the DM to send it. Right now I have 3 separate macros on the token, so my next task is to create just one macro on the token and have a drop down list and based on the drop down list it will send the correct macrolink to the player.

Thank you again for all the help. :mrgreen:

User avatar
mfrizzell
Dragon
Posts: 762
Joined: Sat Feb 13, 2010 2:35 am
Location: California

Re: Drop-Down List in a Frame

Post by mfrizzell »

biodude wrote:
Fobbo wrote: Thank you biodude,

I have tried your code however when I click on the send button it asks me for token.name and race. It then sends what ever was the value in the input pops to the player selected.

The token.name and race should come from the token selected where the macro call was triggered.
Right. Good point. Sorry, I didn't fully test before posting (which goes to show the value of bug-checking ;) ). On the bright side, we get to learn something about token focus (or context, as I like to think of is) ;-)

The problem is that once the form is drawn, token focus disappears, so when the form is submitted, the macro has forgotten what the Current Token is. So, when the macro is called again by form submission, there is no current token, regardless of what is selected or impersonated :(
Fortunately, you can tell it what it should be in the Wiki: macroLinkText() function. So, the command that specifies the action for the html form should include the optional argument to specify the token context under which to run the specified macro. With that, it should 'remember' which token is the current one when you submit the form. The code would now look like this (hidden in spoiler to save our collective scrolling wheels):
MonsterKnowledgeCheck

Code: Select all

[if( json.type( macro.args )!="OBJECT" ), code:{  <!-- Form data not submitted, (re-)draw the frame. -->
   [h: playerList = getAllPlayerNames() ]
   [H: thisMacro = getMacroName()+"@this" ]  <!-- why have to change your code, just because you renamed your macro later? ;) -->
   [frame("MKCDC15","width=200;height=300"):{
      <html>
           <head>
                <title>Monster Knowledge Check DC15</title>
           </head>
           <body><form name ="MKCDC15" method="json" action='[r:macroLinkText( thisMacro, "none", "", currentToken() )]'><!-- the form is sent to this macro, output displayed to "none", no arguments, with the current token as focus. -->
               <table border="0" cellpadding="0" cellspacing="0">
                   <tr>
                      <th>
                             Send To <small>([R:macroLink("Refresh Player List", thisMacro, "none")])</small>
                      </th>
                  </tr>
                  <tr>
                    <td>
      [R: listFormat( playerList, "<select name='Player'>%list</select>", "<option value='%item'>%item</option>", "" )]
                    </td>
                  </tr>
                 <tr><td align="center">
             <input type='submit' value='Send' >
           </td></tr>
      </table>
      </html>
   }]
   [h:abort(0)]
};{
   <!-- process form data submitted as a json object (in 'macro.args') -->
   [H: targetName = json.get( macro.args, 'Player' )]<!-- contains the literal value, not an index.  See how much fun html forms can be? -->
   [h: testString = "You know the following about this creature: " +token.name+ " " +Race]
   [h: sendTo = json.fromList(targetName)]
   [H: outputTo(sendTo, testString)]  <!-- this is queued output: it will be sent to chat after this macro stops. -->
}]
  
Is that better?
Hi,
I'm trying to follow along here. I pasted the code here into a macro and working through the issue of the UDF's I finally got it to do something but I still get it asking what values these should have token.name & Race. I had thought that the first was probably the Tokens name (Duh!) and the other maybe a token property.
DCI/RPGA# 7208328396 Skype ID mfrizzell77
Characters:
Strabor - Dwarf Avenger 5th Level
Tikkanan - Human Warlock 2nd Level
----------------------------------------------------
"People are more violently opposed to fur than leather because it's safer to harass rich women than motorcycle gangs."

User avatar
biodude
Dragon
Posts: 444
Joined: Sun Jun 15, 2008 2:40 pm
Location: Montréal, QC

Re: Drop-Down List in a Frame

Post by biodude »

mfrizzell wrote: Hi,
I'm trying to follow along here. I pasted the code here into a macro and working through the issue of the UDF's I finally got it to do something but I still get it asking what values these should have token.name & Race. I had thought that the first was probably the Tokens name (Duh!) and the other maybe a token property.
Yes, token.name is a special variable that always returns the name of the Current Token. You can get the same result with Wiki: getName(), which might help avoid the kind of confusion or uncertainty you had when you first saw it. I assume Race is also a custom token property. Again, using Wiki: getProperty() to retrieve it would help avoid ambiguity. But enough about recommended practice...

It sounds like you are having a problem with token scope, where there is no Current Token when the macro is running. This is likely caused by one of the following:
  • There is no token selected or impersonated when the macro is called. It's a good idea to include a check in macros where this is necessary. e.g.

    Code: Select all

    [H if( currentToken()=="" ): abort()]
    <!-- OR -->
    [H: assert( currentToken()!="", "error message" )] 
  • A macro sets the current token using Wiki: switchToken(), but then calls another macro, which has a different scope and thus you have the same problem as above (currentToken is blank again). Scope is a little tricky, but is very important with respect to the current token. Luckily, scope for the current token follows much the same rules as for variables (see Wiki: defineFunction()).
    Advanced Note: calling another macro using the [MACRO:] roll option creates a new scope within the called macro, whereas wrapping that statement in an Wiki: evalMacro() function does not (it calls the macro with the same scope).
Hope that helps, otherwise you might have to post some more details about your problem. I suggest having a closer look at how the macros are being called, and checking the value of currentToken() along the way.
"The trouble with communicating is believing you have achieved it"
[ d20 StatBlock Importer ] [ Batch Edit Macros ] [ Canned Speech UI ] [ Lib: Math ]

User avatar
mfrizzell
Dragon
Posts: 762
Joined: Sat Feb 13, 2010 2:35 am
Location: California

Re: Drop-Down List in a Frame

Post by mfrizzell »

biodude wrote:
mfrizzell wrote: Hi,
I'm trying to follow along here. I pasted the code here into a macro and working through the issue of the UDF's I finally got it to do something but I still get it asking what values these should have token.name & Race. I had thought that the first was probably the Tokens name (Duh!) and the other maybe a token property.
biodude wrote:Yes, token.name is a special variable that always returns the name of the Current Token. You can get the same result with Wiki: getName(), which might help avoid the kind of confusion or uncertainty you had when you first saw it. I assume Race is also a custom token property. Again, using Wiki: getProperty() to retrieve it would help avoid ambiguity. But enough about recommended practice...
I was just following along with your explanation to Fobbo and noted where he had the same problem of not retaining token scope so you put up corrected code. He found that it worked. I tried the same code and found I still was getting asked for to variables. The race one I assumed was a token property and would not have that, but the token.name even though I had not heard of it before assumed it was either a variable with the token name or a function to return the token name. I tried replacing token.name with getNPCName() with no luck so I assume now that it is what you say. The Macro no longer knows what token I'm talking about.
I don't fully understand why that would be since it is the macro not macro passed to from another. Especially since it seemed to work for Fobbo and I assume it worked for you when you tested it prior to posting.
DCI/RPGA# 7208328396 Skype ID mfrizzell77
Characters:
Strabor - Dwarf Avenger 5th Level
Tikkanan - Human Warlock 2nd Level
----------------------------------------------------
"People are more violently opposed to fur than leather because it's safer to harass rich women than motorcycle gangs."

User avatar
biodude
Dragon
Posts: 444
Joined: Sun Jun 15, 2008 2:40 pm
Location: Montréal, QC

Re: Drop-Down List in a Frame

Post by biodude »

1. Did you check "Apply to Selected Tokens" for the macro? If not, currentToken() will be empty, and MapTool won't know what to do (hence, the error message).

2. Try this code, which is a bit more robust (fewer error messages, but rather empty or no output if there is a problem):
MKCDC15

Code: Select all

[if( json.type( macro.args )!="OBJECT" ), code:{  <!-- Form data not submitted, (re-)draw the frame. -->
   [h: playerList = getAllPlayerNames() ]
   [H: thisMacro = getMacroName()+"@this" ]  <!-- why have to change your code, just because you renamed your macro later? ;) -->
   [frame("MKCDC15","width=200;height=300"):{
      <html>
           <head>
                <title>Monster Knowledge Check DC15</title>
           </head>
           <body><form name ="MKCDC15" method="json" action='[r:macroLinkText( thisMacro, "none", "", currentToken() )]'><!-- the form is sent to this macro, output displayed to "none", no arguments, with the current token as focus. -->
               <table border="0" cellpadding="0" cellspacing="0" align='left'>
                   <tr>
                      <td>
                             <strong>Token:</strong> <em>[R: getName()]</em>
                      </td>
                   </tr>
                   <tr>
                      <th>
                             Send To <small>([R:macroLink("Refresh Player List", thisMacro, "none", "", currentToken() )])</small>
                      </th>
                  </tr>
                  <tr>
                    <td>
      [R: listFormat( playerList, "<select name='Player'>%list</select>", "<option value='%item'>%item</option>", "" )]
                    </td>
                  </tr>
                 <tr><td align="center">
             <input type='submit' value='Send' >
           </td></tr>
      </table>
      </html>
   }]
   [h:abort(0)]
};{
   <!-- process form data submitted as a json object (in 'macro.args') -->
   [H: targetName = json.get( macro.args, 'Player' )]<!-- contains the literal value, not an index.  See how much fun html forms can be? -->
   [h: testString = "You know the following about this creature: " +getName()+ " " +getProperty('Race') ]
   [h: sendTo = json.fromList(targetName)]
   [H: outputTo(sendTo, testString)]  <!-- this is queued output: it will be sent to chat after this macro stops. -->
}]
"The trouble with communicating is believing you have achieved it"
[ d20 StatBlock Importer ] [ Batch Edit Macros ] [ Canned Speech UI ] [ Lib: Math ]

User avatar
mfrizzell
Dragon
Posts: 762
Joined: Sat Feb 13, 2010 2:35 am
Location: California

Re: Drop-Down List in a Frame

Post by mfrizzell »

biodude wrote:1. Did you check "Apply to Selected Tokens" for the macro? If not, currentToken() will be empty, and MapTool won't know what to do (hence, the error message).
That was it.
biodude wrote:2. Try this code, which is a bit more robust (fewer error messages, but rather empty or no output if there is a problem):
MKCDC15

Code: Select all

[if( json.type( macro.args )!="OBJECT" ), code:{  <!-- Form data not submitted, (re-)draw the frame. -->
   [h: playerList = getAllPlayerNames() ]
   [H: thisMacro = getMacroName()+"@this" ]  <!-- why have to change your code, just because you renamed your macro later? ;) -->
   [frame("MKCDC15","width=200;height=300"):{
      <html>
           <head>
                <title>Monster Knowledge Check DC15</title>
           </head>
           <body><form name ="MKCDC15" method="json" action='[r:macroLinkText( thisMacro, "none", "", currentToken() )]'><!-- the form is sent to this macro, output displayed to "none", no arguments, with the current token as focus. -->
               <table border="0" cellpadding="0" cellspacing="0" align='left'>
                   <tr>
                      <td>
                             <strong>Token:</strong> <em>[R: getName()]</em>
                      </td>
                   </tr>
                   <tr>
                      <th>
                             Send To <small>([R:macroLink("Refresh Player List", thisMacro, "none", "", currentToken() )])</small>
                      </th>
                  </tr>
                  <tr>
                    <td>
      [R: listFormat( playerList, "<select name='Player'>%list</select>", "<option value='%item'>%item</option>", "" )]
                    </td>
                  </tr>
                 <tr><td align="center">
             <input type='submit' value='Send' >
           </td></tr>
      </table>
      </html>
   }]
   [h:abort(0)]
};{
   <!-- process form data submitted as a json object (in 'macro.args') -->
   [H: targetName = json.get( macro.args, 'Player' )]<!-- contains the literal value, not an index.  See how much fun html forms can be? -->
   [h: testString = "You know the following about this creature: " +getName()+ " " +getProperty('Race') ]
   [h: sendTo = json.fromList(targetName)]
   [H: outputTo(sendTo, testString)]  <!-- this is queued output: it will be sent to chat after this macro stops. -->
}]
Once I disect and figure out the first one I'll try the second one. Thanks for your help. Just trying to learn.
DCI/RPGA# 7208328396 Skype ID mfrizzell77
Characters:
Strabor - Dwarf Avenger 5th Level
Tikkanan - Human Warlock 2nd Level
----------------------------------------------------
"People are more violently opposed to fur than leather because it's safer to harass rich women than motorcycle gangs."

Post Reply

Return to “Macros”