"""
Classes for generating HTML forms
"""
import logging,sys
from cgi import escape
from galaxy.util import restore_text
log = logging.getLogger(__name__)
class BaseField(object):
def get_html( self, prefix="" ):
"""Returns the html widget corresponding to the parameter"""
raise TypeError( "Abstract Method" )
def get_disabled_str( self, disabled=False ):
if disabled:
return ' disabled="disabled"'
else:
return ''
@staticmethod
def form_field_types():
return ['TextField', 'TextArea', 'SelectField', 'CheckboxField', 'AddressField', 'WorkflowField']
@staticmethod
def sample_field_types():
return ['TextField', 'SelectField', 'CheckboxField', 'WorkflowField']
class TextField(BaseField):
"""
A standard text input box.
>>> print TextField( "foo" ).get_html()
>>> print TextField( "bins", size=4, value="default" ).get_html()
"""
def __init__( self, name, size=None, value=None ):
self.name = name
self.size = int( size or 10 )
self.value = value or ""
def get_html( self, prefix="", disabled=False ):
return '' \
% ( prefix, self.name, self.size, escape( str( self.value ), quote=True ), self.get_disabled_str( disabled ) )
def set_size(self, size):
self.size = int( size )
class PasswordField(BaseField):
"""
A password input box. text appears as "******"
>>> print PasswordField( "foo" ).get_html()
>>> print PasswordField( "bins", size=4, value="default" ).get_html()
"""
def __init__( self, name, size=None, value=None ):
self.name = name
self.size = int( size or 10 )
self.value = value or ""
def get_html( self, prefix="" ):
return '' \
% ( prefix, self.name, self.size, escape( str( self.value ), quote=True ) )
def set_size(self, size):
self.size = int( size )
class TextArea(BaseField):
"""
A standard text area box.
>>> print TextArea( "foo" ).get_html()
>>> print TextArea( "bins", size="4x5", value="default" ).get_html()
"""
def __init__( self, name, size="5x25", value=None ):
self.name = name
self.size = size.split("x")
self.rows = int(self.size[0])
self.cols = int(self.size[-1])
self.value = value or ""
def get_html( self, prefix="", disabled=False ):
return '' \
% ( prefix, self.name, self.rows, self.cols, self.get_disabled_str( disabled ), escape( str( self.value ), quote=True ) )
def set_size(self, rows, cols):
self.rows = rows
self.cols = cols
class CheckboxField(BaseField):
"""
A checkbox (boolean input)
>>> print CheckboxField( "foo" ).get_html()
>>> print CheckboxField( "bar", checked="yes" ).get_html()
"""
def __init__( self, name, checked=None ):
self.name = name
self.checked = ( checked == True ) or ( isinstance( checked, basestring ) and ( checked.lower() in ( "yes", "true", "on" ) ) )
def get_html( self, prefix="", disabled=False ):
if self.checked:
checked_text = "checked"
else:
checked_text = ""
# The hidden field is necessary because if the check box is not checked on the form, it will
# not be included in the request params. The hidden field ensure that this will happen. When
# parsing the request, the value 'true' in the hidden field actually means it is NOT checked.
# See the is_checked() method below. The prefix is necessary in each case to ensure functional
# correctness when the param is inside a conditional.
return '' \
% ( prefix, self.name, checked_text, self.get_disabled_str( disabled ), prefix, self.name, self.get_disabled_str( disabled ) )
@staticmethod
def is_checked( value ):
if value == True:
return True
# This may look strange upon initial inspection, but see the comments in the get_html() method
# above for clarification. Basically, if value is not True, then it will always be a list with
# 2 input fields ( a checkbox and a hidden field ) if the checkbox is checked. If it is not
# checked, then value will be only the hidden field.
return isinstance( value, list ) and len( value ) == 2
def set_checked(self, value):
if isinstance( value, basestring ):
self.checked = value.lower() in [ "yes", "true", "on" ]
else:
self.checked = value
class FileField(BaseField):
"""
A file upload input.
>>> print FileField( "foo" ).get_html()
>>> print FileField( "foo", ajax = True ).get_html()
"""
def __init__( self, name, value = None, ajax=False ):
self.name = name
self.ajax = ajax
self.value = value
def get_html( self, prefix="" ):
value_text = ""
if self.value:
value_text = ' value="%s"' % self.value
ajax_text = ""
if self.ajax:
ajax_text = ' galaxy-ajax-upload="true"'
return '' % ( prefix, self.name, ajax_text, value_text )
class HiddenField(BaseField):
"""
A hidden field.
>>> print HiddenField( "foo", 100 ).get_html()
"""
def __init__( self, name, value=None ):
self.name = name
self.value = value or ""
def get_html( self, prefix="" ):
return '' % ( prefix, self.name, escape( str( self.value ), quote=True ) )
class SelectField(BaseField):
"""
A select field.
>>> t = SelectField( "foo", multiple=True )
>>> t.add_option( "tuti", 1 )
>>> t.add_option( "fruity", "x" )
>>> print t.get_html()
>>> t = SelectField( "bar" )
>>> t.add_option( "automatic", 3 )
>>> t.add_option( "bazooty", 4, selected=True )
>>> print t.get_html()
>>> t = SelectField( "foo", display="radio" )
>>> t.add_option( "tuti", 1 )
>>> t.add_option( "fruity", "x" )
>>> print t.get_html()
'''
else:
self.select_address.add_option( 'Add a new address', 'new' )
return self.select_address.get_html( disabled=disabled ) + address_html
class WorkflowField(BaseField):
def __init__(self, name, user=None, value=None, params=None):
self.name = name
self.user = user
self.value = value
self.select_workflow = None
self.params = params
def get_html( self, disabled=False ):
self.select_workflow = SelectField( self.name )
if self.value == 'none':
self.select_workflow.add_option( 'Select one', 'none', selected=True )
else:
self.select_workflow.add_option( 'Select one', 'none' )
if self.user:
for a in self.user.stored_workflows:
if not a.deleted:
if str( self.value ) == str( a.id ):
self.select_workflow.add_option( a.name, str( a.id ), selected=True )
else:
self.select_workflow.add_option( a.name, str( a.id ) )
return self.select_workflow.get_html( disabled=disabled )
def get_suite():
"""Get unittest suite for this module"""
import doctest, sys
return doctest.DocTestSuite( sys.modules[__name__] )
# --------- Utility methods -----------------------------
def build_select_field( trans, objs, label_attr, select_field_name, initial_value='none',
selected_value='none', refresh_on_change=False, multiple=False, display=None, size=None ):
"""
Build a SelectField given a set of objects. The received params are:
- objs: the set of object used to populate the option list
- label_attr: the attribute of each obj (e.g., name, email, etc ) whose value is used to populate each option label. If the string
'self' is passed as label_attr, each obj in objs is assumed to be a string, so the obj itself is used
- select_field_name: the name of the SelectField
- initial_value: the vlaue of the first option in the SelectField - allows for an option telling the user to select something
- selected_value: the value of the currently selected option
- refresh_on_change: True if the SelectField should perform a refresh_on_change
"""
values = [ initial_value ]
for obj in objs:
if label_attr == 'self':
# Each obj is a string
values.append( obj )
else:
values.append( trans.security.encode_id( obj.id ) )
if refresh_on_change:
refresh_on_change_values = values
else:
refresh_on_change_values = []
select_field = SelectField( name=select_field_name,
multiple=multiple,
display=display,
refresh_on_change=refresh_on_change,
refresh_on_change_values=refresh_on_change_values,
size=size )
if display is None:
# only insert an initial "Select one" option if we are not displaying check boxes or radio buttons
if selected_value == initial_value:
select_field.add_option( 'Select one', initial_value, selected=True )
else:
select_field.add_option( 'Select one', initial_value )
for obj in objs:
if label_attr == 'self':
# Each obj is a string
if str( selected_value ) == str( obj ):
select_field.add_option( obj, obj, selected=True )
else:
select_field.add_option( obj, obj )
else:
label = getattr( obj, label_attr )
if str( selected_value ) == str( obj.id ) or str( selected_value ) == trans.security.encode_id( obj.id ):
select_field.add_option( label, trans.security.encode_id( obj.id ), selected=True )
else:
select_field.add_option( label, trans.security.encode_id( obj.id ) )
return select_field