-
Notifications
You must be signed in to change notification settings - Fork 3
Refining the authentication dialog again
In the last few tutorials, we have created an authentication dialog and configured it to handle authentication issues and remember users' settings. In this tutorial, we will use control actions and conditions to make our dialog a little more accessible by giving focus to empty fields when the dialog loads.
Setup
This tutorial assumes that you have completed the tutorial, Saving user settings, and have a version of the engine that will start and attempt to contact your web-server.
What we hope to accomplish
We would like to implement the following behavior:
- if one of our authentication dialog's fields is empty, that field should get focus.
- if all of our authentication dialog's fields have content, the passphrase field should get focus.
Giving a control focus
- We have already implemented control actions for our authentication dialog. Let's add another control action to set focus to the username control. Add the following to the
Actions
block of ourLoginBanner
xml:
<SetFocusAction onetime="true">
<ControlKey>username</ControlKey>
</SetFocusAction>
Don't forget to add the onetime="true"
attribute here. If you do not use this attribute, the action will fire every time the dialog is updated.
- In order for this action to work, the xml for our
username
control needs to include acontrolKey
attribute. If you've been completing these tutorials in order, this should be present, but we'll need to add control keys to xml for our authentication dialog's other controls:
<SimpleInputField settingKey="username" controlKey="username"/>
...
<PasswordInputField settingKey="passphrase" controlKey="passphrase"/>
...
<SimpleInputField settingKey="credential2" controlKey="credential2" />
...
<SimpleInputField settingKey="credential3" controlKey="credential3" />
...
<SimpleInputField settingKey="credential4" controlKey="credential4" />
The controlKey
attribute allows you to designate controls when using control actions. The settingsKey
attribute allows you to associate a control's content with entries in the engine's temporary settings store. This is a subtle, but important distinction. Basically, use control keys to manipulate controls and settings key to manipulate control content.
- It doesn't make sense to give the username control focus if it has content, so let's add some conditions to prevent this from happening:
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingNotPresent key="username" />
</Conditions.All>
<ControlKey>username</ControlKey>
</SetFocusAction>
Here, we're using a settings key to determine whether the username control has content and a control key to set focus to the control. We've named both keys the same for convenience. This should give the username control focus only if it has no content.
- Let's do the same for the passphrase control. Here, we want to give the passphrase field focus if the username control has content, but the passphrase control does not:
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingNotPresent key="username" />
</Conditions.All>
<ControlKey>username</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingNotPresent key="passphrase" />
</Conditions.All>
<ControlKey>passphrase</ControlKey>
</SetFocusAction>
- If both the username and passphrase controls have content, but one of the other credentials controls does not, we want that control to have focus. We'll need to add three more
SetFocusAction
blocks to accomplish this:
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingNotPresent key="username" />
</Conditions.All>
<ControlKey>username</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingNotPresent key="passphrase" />
</Conditions.All>
<ControlKey>passphrase</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingNotPresent key="credential2" />
</Conditions.All>
<ControlKey>credential2</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingPresent key="credential2" />
<Settings.SettingNotPresent key="credential3" />
</Conditions.All>
<ControlKey>credential3</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingPresent key="credential2" />
<Settings.SettingPresent key="credential3" />
<Settings.SettingNotPresent key="credential4" />
</Conditions.All>
<ControlKey>credential4</ControlKey>
</SetFocusAction>
You'll notice that each successive condition block grows by one condition. The SetFocusAction
for the username control only contains one condition, that the block for the passphrase control contains two conditions, etc.
Here, we want to give focus to the first control without content, so we only need conditions to evaluate the state the control in question and the states of any preceding controls. In the case of our username control, we only need to check if it has no content, but in the case of the passphrase control, we need to check if it is empty and that the username control has content. And so on.
- Your banners.xml file should now be as follows:
<Content xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://incert.incommon.org/schemas ../Schemas/tasklist.xsd">
<Banners>
<SimpleBanner name="LoginBanner" height="550" width="500">
<Content>
<SimpleParagraph margin="0,36,0,36" fontSize="24" alignment="Center">
<Content>
<DirectTextContent>!ApplicationTitle! Login</DirectTextContent>
</Content>
</SimpleParagraph>
<SimpleParagraph>
<Content>
<DirectTextContent>Username:</DirectTextContent>
</Content>
</SimpleParagraph>
<SimpleInputField settingKey="username" controlKey="username"/>
<SimpleParagraph margin="0,8,0,0">
<Content>
<DirectTextContent>Passphrase:</DirectTextContent>
</Content>
</SimpleParagraph>
<PasswordInputField settingKey="passphrase" controlKey="passphrase"/>
<SimpleParagraph margin="0,8,0,0">
<Content>
<DirectTextContent>Credential 2:</DirectTextContent>
</Content>
</SimpleParagraph>
<SimpleInputField settingKey="credential2" controlKey="credential2"/>
<SimpleParagraph margin="0,8,0,0">
<Content>
<DirectTextContent>Credential 3:</DirectTextContent>
</Content>
</SimpleParagraph>
<SimpleInputField settingKey="credential3" controlKey="credential3" />
<SimpleParagraph margin="0,8,0,0">
<Content>
<DirectTextContent>Credential 4:</DirectTextContent>
</Content>
</SimpleParagraph>
<SimpleInputField settingKey="credential4" controlKey="credential4"/>
<SimpleParagraph controlKey="Instructions" margin="0,12,0,0">
<Content>
<DirectTextContent>Please provide your network credentials and click Login to continue.</DirectTextContent>
</Content>
</SimpleParagraph>
<ProgressParagraph settingKey="AuthenticatingMessage" controlKey="AuthenticatingMessage" margin="0,12,0,0">
<Content>
<DirectTextContent>Please wait while !ApplicationTitle! verifies your network credentials</DirectTextContent>
</Content>
</ProgressParagraph>
</Content>
<Buttons>
<ResultButton>
<Target>NextButton</Target>
<Text>Login</Text>
<IsDefaultButton>true</IsDefaultButton>
<Result>ControlResults.NextResult</Result>
</ResultButton>
<DisabledButton>
<Target>BackButton</Target>
<Text>Back</Text>
</DisabledButton>
<UrlButton>
<Target>HelpButton</Target>
<Text>Help</Text>
<Value>https://certdev0.incommontest.org/incommon/index.html</Value>
</UrlButton>
</Buttons>
<Actions>
<DisableControlAction>
<Conditions.Any>
<Settings.SettingNotPresent key="username" />
<Settings.SettingNotPresent key="passphrase" />
<Settings.SettingNotPresent key="credential2" />
<Settings.SettingNotPresent key="credential3" />
<Settings.SettingNotPresent key="credential4" />
<Settings.SettingEquals key="authenticating" value="true" />
</Conditions.Any>
<ControlKey>NextButton</ControlKey>
</DisableControlAction>
<EnableControlAction>
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingPresent key="credential2" />
<Settings.SettingPresent key="credential3" />
<Settings.SettingPresent key="credential4" />
<Settings.SettingNotEqual key="authenticating" value="true" />
</Conditions.All>
<ControlKey>NextButton</ControlKey>
</EnableControlAction>
<HideControlAction onetime="true">
<ControlKey>AuthenticatingMessage</ControlKey>
</HideControlAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingNotPresent key="username" />
</Conditions.All>
<ControlKey>username</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingNotPresent key="passphrase" />
</Conditions.All>
<ControlKey>passphrase</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingNotPresent key="credential2" />
</Conditions.All>
<ControlKey>credential2</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingPresent key="credential2" />
<Settings.SettingNotPresent key="credential3" />
</Conditions.All>
<ControlKey>credential3</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingPresent key="credential2" />
<Settings.SettingPresent key="credential3" />
<Settings.SettingNotPresent key="credential4" />
</Conditions.All>
<ControlKey>credential4</ControlKey>
</SetFocusAction>
</Actions>
</SimpleBanner>
</Banners>
</Content>
- Upload banners.xml to your server and run the engine. The passphrase field should have focus if there is already content in the username field:
- The last thing that we need to do is to highlight the content of the passphrase field if all of the dialog's fields have content. To do this, add the following
SelectAllContentAction
block:
<SelectAllContentAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingPresent key="credential2" />
<Settings.SettingPresent key="credential3" />
<Settings.SettingPresent key="credential4" />
</Conditions.All>
<ControlKey>passphrase</ControlKey>
</SelectAllContentAction>
- Your banners.xml file should now be as follows:
<Content xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://incert.incommon.org/schemas ../Schemas/tasklist.xsd">
<Banners>
<SimpleBanner name="LoginBanner" height="550" width="500">
<Content>
<SimpleParagraph margin="0,36,0,36" fontSize="24" alignment="Center">
<Content>
<DirectTextContent>!ApplicationTitle! Login</DirectTextContent>
</Content>
</SimpleParagraph>
<SimpleParagraph>
<Content>
<DirectTextContent>Username:</DirectTextContent>
</Content>
</SimpleParagraph>
<SimpleInputField settingKey="username" controlKey="username"/>
<SimpleParagraph margin="0,8,0,0">
<Content>
<DirectTextContent>Passphrase:</DirectTextContent>
</Content>
</SimpleParagraph>
<PasswordInputField settingKey="passphrase" controlKey="passphrase"/>
<SimpleParagraph margin="0,8,0,0">
<Content>
<DirectTextContent>Credential 2:</DirectTextContent>
</Content>
</SimpleParagraph>
<SimpleInputField settingKey="credential2" controlKey="credential2"/>
<SimpleParagraph margin="0,8,0,0">
<Content>
<DirectTextContent>Credential 3:</DirectTextContent>
</Content>
</SimpleParagraph>
<SimpleInputField settingKey="credential3" controlKey="credential3" />
<SimpleParagraph margin="0,8,0,0">
<Content>
<DirectTextContent>Credential 4:</DirectTextContent>
</Content>
</SimpleParagraph>
<SimpleInputField settingKey="credential4" controlKey="credential4"/>
<SimpleParagraph controlKey="Instructions" margin="0,12,0,0">
<Content>
<DirectTextContent>Please provide your network credentials and click Login to continue.</DirectTextContent>
</Content>
</SimpleParagraph>
<ProgressParagraph settingKey="AuthenticatingMessage" controlKey="AuthenticatingMessage" margin="0,12,0,0">
<Content>
<DirectTextContent>Please wait while !ApplicationTitle! verifies your network credentials</DirectTextContent>
</Content>
</ProgressParagraph>
</Content>
<Buttons>
<ResultButton>
<Target>NextButton</Target>
<Text>Login</Text>
<IsDefaultButton>true</IsDefaultButton>
<Result>ControlResults.NextResult</Result>
</ResultButton>
<DisabledButton>
<Target>BackButton</Target>
<Text>Back</Text>
</DisabledButton>
<UrlButton>
<Target>HelpButton</Target>
<Text>Help</Text>
<Value>https://certdev0.incommontest.org/incommon/index.html</Value>
</UrlButton>
</Buttons>
<Actions>
<DisableControlAction>
<Conditions.Any>
<Settings.SettingNotPresent key="username" />
<Settings.SettingNotPresent key="passphrase" />
<Settings.SettingNotPresent key="credential2" />
<Settings.SettingNotPresent key="credential3" />
<Settings.SettingNotPresent key="credential4" />
<Settings.SettingEquals key="authenticating" value="true" />
</Conditions.Any>
<ControlKey>NextButton</ControlKey>
</DisableControlAction>
<EnableControlAction>
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingPresent key="credential2" />
<Settings.SettingPresent key="credential3" />
<Settings.SettingPresent key="credential4" />
<Settings.SettingNotEqual key="authenticating" value="true" />
</Conditions.All>
<ControlKey>NextButton</ControlKey>
</EnableControlAction>
<HideControlAction onetime="true">
<ControlKey>AuthenticatingMessage</ControlKey>
</HideControlAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingNotPresent key="username" />
</Conditions.All>
<ControlKey>username</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingNotPresent key="passphrase" />
</Conditions.All>
<ControlKey>passphrase</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingNotPresent key="credential2" />
</Conditions.All>
<ControlKey>credential2</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingPresent key="credential2" />
<Settings.SettingNotPresent key="credential3" />
</Conditions.All>
<ControlKey>credential3</ControlKey>
</SetFocusAction>
<SetFocusAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingPresent key="credential2" />
<Settings.SettingPresent key="credential3" />
<Settings.SettingNotPresent key="credential4" />
</Conditions.All>
<ControlKey>credential4</ControlKey>
</SetFocusAction>
<SelectAllContentAction onetime="true">
<Conditions.All>
<Settings.SettingPresent key="username" />
<Settings.SettingPresent key="passphrase" />
<Settings.SettingPresent key="credential2" />
<Settings.SettingPresent key="credential3" />
<Settings.SettingPresent key="credential4" />
</Conditions.All>
<ControlKey>passphrase</ControlKey>
</SelectAllContentAction>
</Actions>
</SimpleBanner>
</Banners>
</Content>
- Upload banners.xml and run the engine. If you enter invalid credentials and click retry on the intervention dialog, the passphrase field should now be highlighted:
Conclusion
Our authentication dialog should now be more or less completed. We've spent a long time on it, but we've learned how to create dynamic dialogs, how to use error branches to intervene if issues occur, and how to manipulate temporary and persisted settings. In the next tutorial, we will be adding a license dialog and exploring how to combine banners to create advanced layouts.