Allow inclusion of application-wide custom CSS.

pull/7/head
Ferry Boender 10 years ago
parent cc3479e9e3
commit c1a029a996
  1. 48
      doc/MANUAL.md
  2. 12
      examples/customize/custom.css
  3. 20
      examples/customize/customize.json
  4. 3
      examples/customize/job_customize.sh
  5. 32
      src/scriptform.py

@ -32,6 +32,8 @@ This is the manual for version %%VERSION%%.
- [Passwords](#users_passwords) - [Passwords](#users_passwords)
- [Form limiting](#users_formlimit) - [Form limiting](#users_formlimit)
- [Security considerations](#users_security) - [Security considerations](#users_security)
1. [Form customization](#cust)
- [Custom CSS](#cust_css)
1. [Security](#security) 1. [Security](#security)
## <a name="invocations">Invocations</a> ## <a name="invocations">Invocations</a>
@ -119,6 +121,10 @@ Structurally, they are made up of the following elements:
served. See also "[Serving static files](#output_static_files)". served. See also "[Serving static files](#output_static_files)".
**Optional**, **String**. **Optional**, **String**.
- **`custom_css`**: Path to a file containing custom CSS. It will be included
in every page's header. See also "[Form customization](#cust)". **Optional**,
**String**.
- **`forms`**: A list of dictionaries of form definitions. **Required**, **List - **`forms`**: A list of dictionaries of form definitions. **Required**, **List
of dictionaries**. of dictionaries**.
@ -154,9 +160,6 @@ Structurally, they are made up of the following elements:
view it, if you know its name. This is useful for other forms to view it, if you know its name. This is useful for other forms to
redirect to this forms and such. redirect to this forms and such.
- **`style`**: A string of inline CSS which will be applied to the field.
**Optional**, **String**.
- **`fields`**: List of fields in the form. Each field is a dictionary. - **`fields`**: List of fields in the form. Each field is a dictionary.
**Required**, **List of dictionaries**. **Required**, **List of dictionaries**.
@ -177,6 +180,9 @@ Structurally, they are made up of the following elements:
pre-filled forms which takes it values from the GET request. pre-filled forms which takes it values from the GET request.
**Optional**, **boolean**, **Default:** `false`. **Optional**, **boolean**, **Default:** `false`.
- **`style`**: A string of inline CSS which will be applied to the field.
**Optional**, **String**.
- **`...`**: Other options, which depend on the type of field. For - **`...`**: Other options, which depend on the type of field. For
more information, see [Field types](#field_types). **Optional**. more information, see [Field types](#field_types). **Optional**.
@ -525,6 +531,42 @@ For an example, see the [beginning of this chapter](#users).
*does* support HTTPS, such as Apache. For more information on that, see *does* support HTTPS, such as Apache. For more information on that, see
the "Invocations" chapter. the "Invocations" chapter.
## <a name="cust">Form customization</a>
### <a name="cust_css">Custom CSS</a>
You can customize a form input field's style using the **`style`** property of
the field definition in the form configuration. It takes a string that will be
put in the generated form's `style=""` HTML attribute. For example:
"fields": [
{
"name": "background",
"title": "Different background color",
"type": "string",
"style": "background-color: #C0FFC0;"
}
]
The example above will render as:
<input required="" type="text" name="background" value="" size="" class="" style="background-color: #C0FFC0;">
You can also include a global piece of CSS by specifying the **`custom_css`**
property in the form definition. For example:
{
"title": "Customized forms",
"custom_css": "custom.css",
"forms": [
...
`custom.css` is the path to a file which will be included in the rendered HTML
page in the `<style>` header. If the path is relative, it will be relative to
the form configuration file's location.
For a good example, see the `examples/customize/` directory in the source.
## <a name="security">Security</a> ## <a name="security">Security</a>
There are a few security issues to take into consideration when deploying Scriptform: There are a few security issues to take into consideration when deploying Scriptform:

@ -0,0 +1,12 @@
form {
background-color: #F0F0F0;
padding: 20px;
border-radius: 10px;
}
form li.submit input {
background-color: #FF0000;
}
div.result pre {
font-size: 12px;
overflow: scroll;
}

@ -0,0 +1,20 @@
{
"title": "Customized forms",
"custom_css": "custom.css",
"forms": [
{
"name": "custom",
"title": "Customized form",
"description": "This form is customized using global CSS and inline CSS.<br><br>The form's background has been made lightgray, the input box is green, the submit button is red and the results are wrapped in a scrolling viewport.",
"script": "job_customize.sh",
"fields": [
{
"name": "background",
"title": "Different background color",
"type": "string",
"style": "background-color: #C0FFC0;"
}
]
}
]
}

@ -28,7 +28,6 @@
# until the next request) to stop the server. # until the next request) to stop the server.
# 10. The program exits. # 10. The program exits.
import sys import sys
import optparse import optparse
import os import os
@ -112,6 +111,9 @@ html_header = u'''<html>
/* Other */ /* Other */
div.about {{ text-align: center; font-size: 12px; color: #808080; }} div.about {{ text-align: center; font-size: 12px; color: #808080; }}
div.about a {{ text-decoration: none; color: #000000; }} div.about a {{ text-decoration: none; color: #000000; }}
/* Custom css */
{custom_css}
</style> </style>
</head> </head>
<body> <body>
@ -139,11 +141,11 @@ html_form = u'''
<div class="form"> <div class="form">
<h2 class="form-title">{title}</h2> <h2 class="form-title">{title}</h2>
<p class="form-description">{description}</p> <p class="form-description">{description}</p>
<form action="submit" method="post" enctype="multipart/form-data"> <form id="{name}" action="submit" method="post" enctype="multipart/form-data">
<input type="hidden" name="form_name" value="{name}" /> <input type="hidden" name="form_name" value="{name}" />
<ul> <ul>
{fields} {fields}
<li> <li class="submit">
<input type="submit" class="btn btn-act" value="{submit_title}" /> <input type="submit" class="btn btn-act" value="{submit_title}" />
<a href="."><button type="button" class="btn btn-lnk" value="Back">Back to the list</button></a> <a href="."><button type="button" class="btn btn-lnk" value="Back">Back to the list</button></a>
</li> </li>
@ -222,13 +224,16 @@ class ScriptForm:
config = json.load(file(self.config_file, 'r')) config = json.load(file(self.config_file, 'r'))
static_dir = None static_dir = None
forms = [] custom_css = None
users = None users = None
forms = []
if 'users' in config:
users = config['users']
if 'static_dir' in config: if 'static_dir' in config:
static_dir = config['static_dir'] static_dir = config['static_dir']
if 'custom_css' in config:
custom_css = file(config['custom_css'], 'r').read()
if 'users' in config:
users = config['users']
for form in config['forms']: for form in config['forms']:
form_name = form['name'] form_name = form['name']
script = form['script'] script = form['script']
@ -248,7 +253,8 @@ class ScriptForm:
config['title'], config['title'],
forms, forms,
users, users,
static_dir static_dir,
custom_css
) )
self.form_config_singleton = form_config self.form_config_singleton = form_config
return form_config return form_config
@ -285,11 +291,12 @@ class FormConfig:
file. It holds information (title, users, the form definitions) on the file. It holds information (title, users, the form definitions) on the
form configuration being served by this instance of ScriptForm. form configuration being served by this instance of ScriptForm.
""" """
def __init__(self, title, forms, users={}, static_dir=None): def __init__(self, title, forms, users={}, static_dir=None, custom_css=None):
self.title = title self.title = title
self.users = users self.users = users
self.forms = forms self.forms = forms
self.static_dir = static_dir self.static_dir = static_dir
self.custom_css = custom_css
self.log = logging.getLogger('FORMCONFIG') self.log = logging.getLogger('FORMCONFIG')
# Validate scripts # Validate scripts
@ -811,7 +818,8 @@ class ScriptFormWebApp(WebAppHandler):
) )
output = html_list.format( output = html_list.format(
header=html_header.format(title=form_config.title), header=html_header.format(title=form_config.title,
custom_css=form_config.custom_css),
footer=html_footer, footer=html_footer,
form_list=u''.join(h_form_list) form_list=u''.join(h_form_list)
) )
@ -893,7 +901,8 @@ class ScriptFormWebApp(WebAppHandler):
html_errors += u'</ul>' html_errors += u'</ul>'
output = html_form.format( output = html_form.format(
header=html_header.format(title=form_config.title), header=html_header.format(title=form_config.title,
custom_css=form_config.custom_css),
footer=html_footer, footer=html_footer,
title=form_def.title, title=form_def.title,
description=form_def.description, description=form_def.description,
@ -985,7 +994,8 @@ class ScriptFormWebApp(WebAppHandler):
msg = result['stdout'].decode('utf8') msg = result['stdout'].decode('utf8')
output = html_submit_response.format( output = html_submit_response.format(
header=html_header.format(title=form_config.title), header=html_header.format(title=form_config.title,
custom_css=form_config.custom_css),
footer=html_footer, footer=html_footer,
title=form_def.title, title=form_def.title,
form_name=form_def.name, form_name=form_def.name,

Loading…
Cancel
Save