User Preferences Pages

Overview

Answer Generators may have localized preferences pages that allow users to save preferences that affect how the answers are generated. Preferences pages are specified by developers as EJS templates outputting a form. When users submit the form on a preferences page, the preferences are serialized into a JSON object that is available to the corresponding Answer Generator when it executes.

Creating a User Preferences Page Template

To create a user preferences page, use the EJS template language to create a full HTML page containing a single form. Your template can contain code written in ES6 non-strict mode; see Javascript Execution for information. The names of the form input elements determine where in the structure of the JSON object the property value lies, and the type of the property value. The corresponding values of the form input elements will be converted to property values.

Solve for All uses jquery.serializeJSON to convert form name/pairs to objects, so by following the documentation of the jquery.serializeJSON project, you can select the names of form inputs to create complex preferences objects. serializeJSON is called with the following options:

  {
    "checkboxUncheckedValue": "false"
  }

to make unchecked checkboxes output false as their associated value. See the source code of the preferences page for the Hacker News Answer Generator for an example.

The existing preferences, if they exist, will be available in the settings object. Be sure to handle non-existent property values as initially the settings object will be empty.

Bootstrap 3.3.6 and Font Awesome 4.5.0 classes will be applied to the page, so you can make it look reasonably nice. You can also include inline styles, according to the same limitations that apply to inline answers.

Note The preferences page you create should not include submit or cancel buttons, as they will be provided by the container of the preferences page.

Full example

Here is an example user preferences page template (excerpted from the Gravatar preferences page):

<%
const settings = context.settings;
const savedSize = settings.size || 80;

const ratingValues = ['g', 'pg', 'r', 'x'];
const ratingLabels = _(ratingValues).map(rating => rating.toUpperCase());
const selectedRating = settings.rating || 'g';
%>
<!doctype html>
<html>
  <head>
    <title>Gravatar Preferences</title>
  </head>
  <body>
    <form class="form-horizontal" role="form">
      <div class="form-group">
        <label for="input_size" class="col-xs-4 col-sm-3 control-label">Size</label>
        <div class="col-xs-6 col-sm-4">
          <input name="size" type="number" min="1" max="2048" value="<%= savedSize %>"
           class="form-control">
        </div>
      </div>

      <div class="form-group">
        <label for="input_rating" class="col-xs-4 col-sm-3 control-label">Rating</label>
        <div class="col-xs-6 col-sm-4">
          <select id="input_rating" name="rating" class="form-control">
            <% for (let i = 0; i < ratingValues.length; i++) { %>
              <option value="<%= ratingValues[i] %>"
                <% if (ratingValues[i] === selectedRating) { %>
                  selected
                <% } %>
              ><%= ratingLabels[i] %></option>
            <% } %>
          </select>
        </div>
      </div>
    </form>
  </body>
</html>

In the above example, when the user submits the form, the preferences will be saved in a JSON object like this:

{
  "size" : 100,
  "rating" : "pg"
}

Sanitization

To protect the security of Solve for All and users, user preferences pages are sanitized before they are displayed. Only a subset of HTML tags are allowed, with only a subset of allowed attributes:

Tag Allowed Attributes
a autofocus, class, href, title
b class, title
blockquote class, title
body class, title
br class, title
button autofocus, class, disabled, name, required, title, type, value
caption class, title
cite class, title
code class, title
col class, title
colgroup class, title
datalist autofocus, class, disabled, name, required, title
dd class, title
div class, title
del class, title, cite, datetime
dl class, title
dt class, title
em class, title
fieldset class, title
form autocomplete, autofocus, class, name, novalidate, title
h1, h2, h3, h4, h5, h6 class, title
html class, title
i class, title
img alt, class, height, src, title, width
input alt, autocomplete, autofocus, checked, class, formnovalidate, height, list, max, maxlength, min, multiple, placeholder, readonly, required, step, title, type, value, width
ins class, title, cite, datetime
keygen autofocus, challenge, class, disabled, keytype, name, required, title
label class, title
legend class, title
li class, title
ol class, title
optgroup class, title
option autofocus, class, label, required, selected, title, value
output autofocus, class, disabled, name, required, title
p class, title
pre class, title
q class, title
s class, title
section class, title
select autofocus, class, disabled, name, required, title
small class, title
span class, title
strike class, title
strong class, title
style (None)
sub class, title
sup class, title
table class, title
tbody class, title
th class, title
thead class, title
textarea autofocus, class, cols, disabled, placeholder, maxlength, readonly, required, title
td class, title
tfoot class, title
tr class, title
u class, title
ul class, title

All other attributes will either be removed or replaced with other values.

As mentioned previously, user preferences pages are localized, so you can create a user preferences page for each of the different locales you want to target.

Uploading User Preferences Pages

Once you've created the preferences page template(s) for the locales you want to target, you can upload them by editing the localizable properties of your Answer Generator. For each desired locale, simply attach the template file to the localizable properties form. To use a single preferences page for all locales, choose the locale with Any language and Any country.

Accessing User Preferences during Answer Generation

To read user preferences for an Answer Generator, access the variable appropriate to the type of Answer Generator:

  • For URI Template Answer Generators, the user preferences object is available in the variable c.settings
  • For Content Template Answer Generators, the user preferences object is available in the variable context.settings. See the source code of the Gravatar Answer Generator for an example.
  • For Javascript Answer Generators, the user preferences object is available in the variable context.settings, where context is the Query Context, passed in as the 3rd argument of generateResults(). See the source code of the Skype Answer Generator for an example.