diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py index 0305795e52..31be96ad7b 100644 --- a/cms/djangoapps/contentstore/views.py +++ b/cms/djangoapps/contentstore/views.py @@ -249,7 +249,7 @@ def load_preview_module(request, preview_id, descriptor, instance_state, shared_ module = descriptor.xmodule_constructor(system)(instance_state, shared_state) module.get_html = replace_static_urls( wrap_xmodule(module.get_html, module, "xmodule_display.html"), - module.metadata['data_dir'] + module.metadata['data_dir'], module ) save_preview_state(request, preview_id, descriptor.location.url(), module.get_instance_state(), module.get_shared_state()) diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index ab22cc0d82..1951426ea7 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -297,6 +297,7 @@ def _do_create_account(post_vars): try: user.save() except IntegrityError: + js = {'success': False} # Figure out the cause of the integrity error if len(User.objects.filter(username=post_vars['username'])) > 0: js['value'] = "An account with this username already exists." @@ -402,7 +403,10 @@ def create_account(request, post_override=None): return HttpResponse(json.dumps(js)) # Ok, looks like everything is legit. Create the account. - (user, profile, registration) = _do_create_account(post_vars) + ret = _do_create_account(post_vars) + if isinstance(ret,HttpResponse): # if there was an error then return that + return ret + (user, profile, registration) = ret d = {'name': post_vars['name'], 'key': registration.activation_key, diff --git a/common/djangoapps/xmodule_modifiers.py b/common/djangoapps/xmodule_modifiers.py index 380388b545..0aeaa59d69 100644 --- a/common/djangoapps/xmodule_modifiers.py +++ b/common/djangoapps/xmodule_modifiers.py @@ -34,7 +34,7 @@ def wrap_xmodule(get_html, module, template): return _get_html -def replace_static_urls(get_html, prefix): +def replace_static_urls(get_html, prefix, module): """ Updates the supplied module with a new get_html function that wraps the old get_html function and substitutes urls of the form /static/... @@ -69,14 +69,14 @@ def grade_histogram(module_id): return grades -def add_histogram(get_html, module): +def add_histogram(get_html, module, user): """ Updates the supplied module with a new get_html function that wraps the output of the old get_html function with additional information for admin users only, including a histogram of student answers and the definition of the xmodule - Does nothing if module is a SequenceModule + Does nothing if module is a SequenceModule or a VerticalModule. """ @wraps(get_html) def _get_html(): @@ -97,14 +97,20 @@ def add_histogram(get_html, module): # doesn't like symlinks) filepath = filename data_dir = osfs.root_path.rsplit('/')[-1] - edit_link = "https://github.com/MITx/%s/tree/master/%s" % (data_dir,filepath) + giturl = module.metadata.get('giturl','https://github.com/MITx') + edit_link = "%s/%s/tree/master/%s" % (giturl,data_dir,filepath) else: edit_link = False staff_context = {'definition': module.definition.get('data'), 'metadata': json.dumps(module.metadata, indent=4), - 'element_id': module.location.html_id(), + 'location': module.location, + 'xqa_key': module.metadata.get('xqa_key',''), + 'category': str(module.__class__.__name__), + 'element_id': module.location.html_id().replace('-','_'), 'edit_link': edit_link, + 'user': user, + 'xqa_server' : settings.MITX_FEATURES.get('USE_XQA_SERVER','http://xqa:server@content-qa.mitx.mit.edu/xqa'), 'histogram': json.dumps(histogram), 'render_histogram': render_histogram, 'module_content': get_html()} diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index d1798f2c67..71c9ca41c7 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -393,9 +393,10 @@ class LoncapaProblem(object): context['script_code'] += code # store code source in context try: exec code in context, context # use "context" for global context; thus defs in code are global within code - except Exception: + except Exception as err: log.exception("Error while execing script code: " + code) - raise responsetypes.LoncapaProblemError("Error while executing script code") + msg = "Error while executing script code: %s" % str(err).replace('<','<') + raise responsetypes.LoncapaProblemError(msg) finally: sys.path = original_path diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 3b89f29989..3491fcae63 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -319,7 +319,8 @@ class XModuleDescriptor(Plugin, HTMLSnippet): # A list of metadata that this module can inherit from its parent module inheritable_metadata = ( 'graded', 'start', 'due', 'graceperiod', 'showanswer', 'rerandomize', - + # TODO (ichuang): used for Fall 2012 xqa server access + 'xqa_key', # TODO: This is used by the XMLModuleStore to provide for locations for # static files, and will need to be removed when that code is removed 'data_dir' diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py index 69c770e279..399d5d3f91 100644 --- a/common/lib/xmodule/xmodule/xml_module.py +++ b/common/lib/xmodule/xmodule/xml_module.py @@ -1,6 +1,7 @@ from xmodule.x_module import XModuleDescriptor from xmodule.modulestore import Location from lxml import etree +import json import copy import logging import traceback @@ -32,7 +33,15 @@ def is_pointer_tag(xml_obj): actual_attr = set(xml_obj.attrib.keys()) return len(xml_obj) == 0 and actual_attr == expected_attr - +def get_metadata_from_xml(xml_object, remove=True): + meta = xml_object.find('meta') + if meta is None: + return '' + dmdata = meta.text + log.debug('meta for %s loaded: %s' % (xml_object,dmdata)) + if remove: + xml_object.remove(meta) + return dmdata _AttrMapBase = namedtuple('_AttrMap', 'from_xml to_xml') @@ -71,6 +80,7 @@ class XmlDescriptor(XModuleDescriptor): metadata_attributes = ('format', 'graceperiod', 'showanswer', 'rerandomize', 'start', 'due', 'graded', 'display_name', 'url_name', 'hide_from_toc', 'ispublic', # if True, then course is listed for all users; see + 'xqa_key', # for xqaa server access # VS[compat] Remove once unused. 'name', 'slug') @@ -180,8 +190,11 @@ class XmlDescriptor(XModuleDescriptor): definition_xml = cls.load_file(filepath, system.resources_fs, location) + definition_metadata = get_metadata_from_xml(definition_xml) cls.clean_metadata_from_xml(definition_xml) definition = cls.definition_from_xml(definition_xml, system) + if definition_metadata: + definition['definition_metadata'] = definition_metadata # TODO (ichuang): remove this after migration # for Fall 2012 LMS migration: keep filename (and unmangled filename) @@ -236,9 +249,9 @@ class XmlDescriptor(XModuleDescriptor): filepath = cls._format_filepath(xml_object.tag, url_name) definition_xml = cls.load_file(filepath, system.resources_fs, location) else: - definition_xml = xml_object + definition_xml = xml_object # this is just a pointer, not the real definition content - definition = cls.load_definition(definition_xml, system, location) + definition = cls.load_definition(definition_xml, system, location) # note this removes metadata # VS[compat] -- make Ike's github preview links work in both old and # new file layouts if is_pointer_tag(xml_object): @@ -246,6 +259,17 @@ class XmlDescriptor(XModuleDescriptor): definition['filename'] = [filepath, filepath] metadata = cls.load_metadata(definition_xml) + + # move definition metadata into dict + dmdata = definition.get('definition_metadata','') + if dmdata: + metadata['definition_metadata_raw'] = dmdata + try: + metadata.update(json.loads(dmdata)) + except Exception as err: + log.debug('Error %s in loading metadata %s' % (err,dmdata)) + metadata['definition_metadata_err'] = str(err) + return cls( system, definition, diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 0a47346a09..3acdb1aad3 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -199,17 +199,18 @@ def get_module(user, request, location, student_module_cache, position=None): ) # pass position specified in URL to module through ModuleSystem system.set('position', position) + system.set('DEBUG',settings.DEBUG) module = descriptor.xmodule_constructor(system)(instance_state, shared_state) module.get_html = replace_static_urls( wrap_xmodule(module.get_html, module, 'xmodule_display.html'), - module.metadata['data_dir'] + module.metadata['data_dir'], module ) if settings.MITX_FEATURES.get('DISPLAY_HISTOGRAMS_TO_STAFF'): if has_staff_access_to_course(user, module.location.course): - module.get_html = add_histogram(module.get_html, module) + module.get_html = add_histogram(module.get_html, module, user) return module diff --git a/lms/envs/common.py b/lms/envs/common.py index 9772b98fc3..393540d078 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -56,6 +56,8 @@ MITX_FEATURES = { 'ENABLE_SQL_TRACKING_LOGS': False, 'ENABLE_LMS_MIGRATION': False, + 'DISABLE_LOGIN_BUTTON': False, # used in systems where login is automatic, eg MIT SSL + # extrernal access methods 'ACCESS_REQUIRE_STAFF_FOR_COURSE': False, 'AUTH_USE_OPENID': False, diff --git a/lms/envs/dev.py b/lms/envs/dev.py index bc5b621b32..85850e81e3 100644 --- a/lms/envs/dev.py +++ b/lms/envs/dev.py @@ -62,6 +62,7 @@ SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd' ################################ LMS Migration ################################# MITX_FEATURES['ENABLE_LMS_MIGRATION'] = True MITX_FEATURES['ACCESS_REQUIRE_STAFF_FOR_COURSE'] = False # require that user be in the staff_* group to be able to enroll +MITX_FEATURES['USE_XQA_SERVER'] = 'http://xqa:server@content-qa.mitx.mit.edu/xqa' LMS_MIGRATION_ALLOWED_IPS = ['127.0.0.1'] diff --git a/lms/envs/dev_ike.py b/lms/envs/dev_ike.py index 288a99bf3b..309ea1ac42 100644 --- a/lms/envs/dev_ike.py +++ b/lms/envs/dev_ike.py @@ -10,14 +10,27 @@ sessions. Assumes structure: from .common import * from .logsettings import get_logger_config from .dev import * +import socket WIKI_ENABLED = False MITX_FEATURES['ENABLE_TEXTBOOK'] = False MITX_FEATURES['ENABLE_DISCUSSION'] = False MITX_FEATURES['ACCESS_REQUIRE_STAFF_FOR_COURSE'] = True # require that user be in the staff_* group to be able to enroll +myhost = socket.gethostname() +if ('edxvm' in myhost) or ('ocw' in myhost): + MITX_FEATURES['DISABLE_LOGIN_BUTTON'] = True # auto-login with MIT certificate + MITX_FEATURES['USE_XQA_SERVER'] = 'https://qisx.mit.edu/xqa' # needs to be ssl or browser blocks it + +if ('domU' in myhost): + EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' + MITX_FEATURES['REROUTE_ACTIVATION_EMAIL'] = 'ichuang@mitx.mit.edu' # nonempty string = address for all activation emails + +SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https') # django 1.4 for nginx ssl proxy + #----------------------------------------------------------------------------- # disable django debug toolbars INSTALLED_APPS = tuple([ app for app in INSTALLED_APPS if not app.startswith('debug_toolbar') ]) MIDDLEWARE_CLASSES = tuple([ mcl for mcl in MIDDLEWARE_CLASSES if not mcl.startswith('debug_toolbar') ]) +TEMPLATE_LOADERS = tuple([ app for app in TEMPLATE_LOADERS if not app.startswith('askbot') ]) diff --git a/lms/static/admin/css/base.css b/lms/static/admin/css/base.css index c5e385d508..5e5fc58a77 100644 --- a/lms/static/admin/css/base.css +++ b/lms/static/admin/css/base.css @@ -189,6 +189,10 @@ p.mini { color: #999; } +img.help-tooltip { + cursor: help; +} + p img, h1 img, h2 img, h3 img, h4 img, td img { vertical-align: middle; } @@ -259,7 +263,7 @@ tfoot td { color: #666; padding: 2px 5px; font-size: 11px; - background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; + background: #e1e1e1 url(../img/nav-bg.gif) top left repeat-x; border-left: 1px solid #ddd; border-bottom: 1px solid #ddd; } @@ -305,25 +309,84 @@ tr.alt { /* SORTABLE TABLES */ +thead th { + padding: 2px 5px; + line-height: normal; +} + thead th a:link, thead th a:visited { color: #666; +} + +thead th.sorted { + background: #c5c5c5 url(../img/nav-bg-selected.gif) top left repeat-x; +} + +table thead th .text span { + padding: 2px 5px; + display:block; +} + +table thead th .text a { display: block; + cursor: pointer; + padding: 2px 5px; } -table thead th.sorted { - background-position: bottom left !important; +table thead th.sortable:hover { + background: white url(../img/nav-bg-reverse.gif) 0 -5px repeat-x; } -table thead th.sorted a { - padding-right: 13px; +thead th.sorted a.sortremove { + visibility: hidden; } -table thead th.ascending a { - background: url(../img/admin/arrow-up.gif) right .4em no-repeat; +table thead th.sorted:hover a.sortremove { + visibility: visible; } -table thead th.descending a { - background: url(../img/admin/arrow-down.gif) right .4em no-repeat; +table thead th.sorted .sortoptions { + display: block; + padding: 4px 5px 0 5px; + float: right; + text-align: right; +} + +table thead th.sorted .sortpriority { + font-size: .8em; + min-width: 12px; + text-align: center; + vertical-align: top; +} + +table thead th.sorted .sortoptions a { + width: 14px; + height: 12px; + display: inline-block; +} + +table thead th.sorted .sortoptions a.sortremove { + background: url(../img/sorting-icons.gif) -4px -5px no-repeat; +} + +table thead th.sorted .sortoptions a.sortremove:hover { + background: url(../img/sorting-icons.gif) -4px -27px no-repeat; +} + +table thead th.sorted .sortoptions a.ascending { + background: url(../img/sorting-icons.gif) -5px -50px no-repeat; +} + +table thead th.sorted .sortoptions a.ascending:hover { + background: url(../img/sorting-icons.gif) -5px -72px no-repeat; +} + +table thead th.sorted .sortoptions a.descending { + background: url(../img/sorting-icons.gif) -5px -94px no-repeat; +} + +table thead th.sorted .sortoptions a.descending:hover { + background: url(../img/sorting-icons.gif) -5px -115px no-repeat; } /* ORDERABLE TABLES */ @@ -334,7 +397,7 @@ table.orderable tbody tr td:hover { table.orderable tbody tr td:first-child { padding-left: 14px; - background-image: url(../img/admin/nav-bg-grabber.gif); + background-image: url(../img/nav-bg-grabber.gif); background-repeat: repeat-y; } @@ -364,7 +427,7 @@ input[type=text], input[type=password], textarea, select, .vTextField { /* FORM BUTTONS */ .button, input[type=submit], input[type=button], .submit-row input { - background: white url(../img/admin/nav-bg.gif) bottom repeat-x; + background: white url(../img/nav-bg.gif) bottom repeat-x; padding: 3px 5px; color: black; border: 1px solid #bbb; @@ -372,31 +435,31 @@ input[type=text], input[type=password], textarea, select, .vTextField { } .button:active, input[type=submit]:active, input[type=button]:active { - background-image: url(../img/admin/nav-bg-reverse.gif); + background-image: url(../img/nav-bg-reverse.gif); background-position: top; } .button[disabled], input[type=submit][disabled], input[type=button][disabled] { - background-image: url(../img/admin/nav-bg.gif); + background-image: url(../img/nav-bg.gif); background-position: bottom; opacity: 0.4; } .button.default, input[type=submit].default, .submit-row input.default { border: 2px solid #5b80b2; - background: #7CA0C7 url(../img/admin/default-bg.gif) bottom repeat-x; + background: #7CA0C7 url(../img/default-bg.gif) bottom repeat-x; font-weight: bold; color: white; float: right; } .button.default:active, input[type=submit].default:active { - background-image: url(../img/admin/default-bg-reverse.gif); + background-image: url(../img/default-bg-reverse.gif); background-position: top; } .button[disabled].default, input[type=submit][disabled].default, input[type=button][disabled].default { - background-image: url(../img/admin/default-bg.gif); + background-image: url(../img/default-bg.gif); background-position: bottom; opacity: 0.4; } @@ -433,7 +496,7 @@ input[type=text], input[type=password], textarea, select, .vTextField { font-size: 11px; text-align: left; font-weight: bold; - background: #7CA0C7 url(../img/admin/default-bg.gif) top left repeat-x; + background: #7CA0C7 url(../img/default-bg.gif) top left repeat-x; color: white; } @@ -455,15 +518,15 @@ ul.messagelist li { margin: 0 0 3px 0; border-bottom: 1px solid #ddd; color: #666; - background: #ffc url(../img/admin/icon_success.gif) 5px .3em no-repeat; + background: #ffc url(../img/icon_success.gif) 5px .3em no-repeat; } ul.messagelist li.warning{ - background-image: url(../img/admin/icon_alert.gif); + background-image: url(../img/icon_alert.gif); } ul.messagelist li.error{ - background-image: url(../img/admin/icon_error.gif); + background-image: url(../img/icon_error.gif); } .errornote { @@ -473,7 +536,7 @@ ul.messagelist li.error{ margin: 0 0 3px 0; border: 1px solid red; color: red; - background: #ffc url(../img/admin/icon_error.gif) 5px .3em no-repeat; + background: #ffc url(../img/icon_error.gif) 5px .3em no-repeat; } ul.errorlist { @@ -488,7 +551,7 @@ ul.errorlist { margin: 0 0 3px 0; border: 1px solid red; color: white; - background: red url(../img/admin/icon_alert.gif) 5px .3em no-repeat; + background: red url(../img/icon_alert.gif) 5px .3em no-repeat; } .errorlist li a { @@ -524,7 +587,7 @@ div.system-message p.system-message-title { padding: 4px 5px 4px 25px; margin: 0; color: red; - background: #ffc url(../img/admin/icon_error.gif) 5px .3em no-repeat; + background: #ffc url(../img/icon_error.gif) 5px .3em no-repeat; } .description { @@ -535,7 +598,7 @@ div.system-message p.system-message-title { /* BREADCRUMBS */ div.breadcrumbs { - background: white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x; + background: white url(../img/nav-bg-reverse.gif) 0 -10px repeat-x; padding: 2px 8px 3px 8px; font-size: 11px; color: #999; @@ -548,17 +611,17 @@ div.breadcrumbs { .addlink { padding-left: 12px; - background: url(../img/admin/icon_addlink.gif) 0 .2em no-repeat; + background: url(../img/icon_addlink.gif) 0 .2em no-repeat; } .changelink { padding-left: 12px; - background: url(../img/admin/icon_changelink.gif) 0 .2em no-repeat; + background: url(../img/icon_changelink.gif) 0 .2em no-repeat; } .deletelink { padding-left: 12px; - background: url(../img/admin/icon_deletelink.gif) 0 .25em no-repeat; + background: url(../img/icon_deletelink.gif) 0 .25em no-repeat; } a.deletelink:link, a.deletelink:visited { @@ -593,14 +656,14 @@ a.deletelink:hover { .object-tools li { display: block; float: left; - background: url(../img/admin/tool-left.gif) 0 0 no-repeat; + background: url(../img/tool-left.gif) 0 0 no-repeat; padding: 0 0 0 8px; margin-left: 2px; height: 16px; } .object-tools li:hover { - background: url(../img/admin/tool-left_over.gif) 0 0 no-repeat; + background: url(../img/tool-left_over.gif) 0 0 no-repeat; } .object-tools a:link, .object-tools a:visited { @@ -609,29 +672,29 @@ a.deletelink:hover { color: white; padding: .1em 14px .1em 8px; height: 14px; - background: #999 url(../img/admin/tool-right.gif) 100% 0 no-repeat; + background: #999 url(../img/tool-right.gif) 100% 0 no-repeat; } .object-tools a:hover, .object-tools li:hover a { - background: #5b80b2 url(../img/admin/tool-right_over.gif) 100% 0 no-repeat; + background: #5b80b2 url(../img/tool-right_over.gif) 100% 0 no-repeat; } .object-tools a.viewsitelink, .object-tools a.golink { - background: #999 url(../img/admin/tooltag-arrowright.gif) top right no-repeat; + background: #999 url(../img/tooltag-arrowright.gif) top right no-repeat; padding-right: 28px; } .object-tools a.viewsitelink:hover, .object-tools a.golink:hover { - background: #5b80b2 url(../img/admin/tooltag-arrowright_over.gif) top right no-repeat; + background: #5b80b2 url(../img/tooltag-arrowright_over.gif) top right no-repeat; } .object-tools a.addlink { - background: #999 url(../img/admin/tooltag-add.gif) top right no-repeat; + background: #999 url(../img/tooltag-add.gif) top right no-repeat; padding-right: 28px; } .object-tools a.addlink:hover { - background: #5b80b2 url(../img/admin/tooltag-add_over.gif) top right no-repeat; + background: #5b80b2 url(../img/tooltag-add_over.gif) top right no-repeat; } /* OBJECT HISTORY */ @@ -766,7 +829,7 @@ table#change-history tbody th { } #content-related .module h2 { - background: #eee url(../img/admin/nav-bg.gif) bottom left repeat-x; + background: #eee url(../img/nav-bg.gif) bottom left repeat-x; color: #666; } diff --git a/lms/static/admin/css/changelists.css b/lms/static/admin/css/changelists.css index 315b8c7a38..3c1a8c16a9 100644 --- a/lms/static/admin/css/changelists.css +++ b/lms/static/admin/css/changelists.css @@ -20,7 +20,7 @@ } .change-list .filtered { - background: white url(../img/admin/changelist-bg.gif) top right repeat-y !important; + background: white url(../img/changelist-bg.gif) top right repeat-y !important; } .change-list .filtered .results, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { @@ -40,7 +40,7 @@ color: #666; border-top: 1px solid #eee; border-bottom: 1px solid #eee; - background: white url(../img/admin/nav-bg.gif) 0 180% repeat-x; + background: white url(../img/nav-bg.gif) 0 180% repeat-x; overflow: hidden; } @@ -51,6 +51,7 @@ /* CHANGELIST TABLES */ #changelist table thead th { + padding: 0; white-space: nowrap; vertical-align: middle; } @@ -82,7 +83,7 @@ #changelist #toolbar { padding: 3px; border-bottom: 1px solid #ddd; - background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; + background: #e1e1e1 url(../img/nav-bg.gif) top left repeat-x; color: #666; } @@ -156,7 +157,7 @@ .change-list ul.toplinks { display: block; - background: white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x; + background: white url(../img/nav-bg-reverse.gif) 0 -10px repeat-x; border-top: 1px solid white; float: left; padding: 0 !important; @@ -165,11 +166,10 @@ } .change-list ul.toplinks li { - float: left; - width: 9em; padding: 3px 6px; font-weight: bold; list-style-type: none; + display: inline-block; } .change-list ul.toplinks .date-back a { @@ -246,7 +246,7 @@ padding: 3px; border-top: 1px solid #fff; border-bottom: 1px solid #ddd; - background: white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x; + background: white url(../img/nav-bg-reverse.gif) 0 -10px repeat-x; } #changelist .actions.selected { diff --git a/lms/static/admin/css/forms.css b/lms/static/admin/css/forms.css index 1cedf24b5b..0ecfca784c 100644 --- a/lms/static/admin/css/forms.css +++ b/lms/static/admin/css/forms.css @@ -140,7 +140,7 @@ fieldset.collapsed h2, fieldset.collapsed { } fieldset.collapsed h2 { - background-image: url(../img/admin/nav-bg.gif); + background-image: url(../img/nav-bg.gif); background-position: bottom left; color: #999; } @@ -161,12 +161,16 @@ fieldset.monospace textarea { .submit-row { padding: 5px 7px; text-align: right; - background: white url(../img/admin/nav-bg.gif) 0 100% repeat-x; + background: white url(../img/nav-bg.gif) 0 100% repeat-x; border: 1px solid #ccc; margin: 5px 0; overflow: hidden; } +body.popup .submit-row { + overflow: auto; +} + .submit-row input { margin: 0 0 0 5px; } @@ -180,7 +184,7 @@ fieldset.monospace textarea { } .submit-row .deletelink { - background: url(../img/admin/icon_deletelink.gif) 0 50% no-repeat; + background: url(../img/icon_deletelink.gif) 0 50% no-repeat; padding-left: 14px; } @@ -247,7 +251,7 @@ fieldset.monospace textarea { color: #666; padding: 3px 5px; font-size: 11px; - background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; + background: #e1e1e1 url(../img/nav-bg.gif) top left repeat-x; border-bottom: 1px solid #ddd; } @@ -332,7 +336,7 @@ fieldset.monospace textarea { color: #666; padding: 3px 5px; border-bottom: 1px solid #ddd; - background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; + background: #e1e1e1 url(../img/nav-bg.gif) top left repeat-x; } .inline-group .tabular tr.add-row td { @@ -343,7 +347,7 @@ fieldset.monospace textarea { .inline-group ul.tools a.add, .inline-group div.add-row a, .inline-group .tabular tr.add-row td a { - background: url(../img/admin/icon_addlink.gif) 0 50% no-repeat; + background: url(../img/icon_addlink.gif) 0 50% no-repeat; padding-left: 14px; font-size: 11px; outline: 0; /* Remove dotted border around link */ @@ -352,9 +356,3 @@ fieldset.monospace textarea { .empty-form { display: none; } - -/* IE7 specific bug fixes */ - -.submit-row input { - float: right; -} \ No newline at end of file diff --git a/lms/static/admin/css/ie.css b/lms/static/admin/css/ie.css index 5fd1ce364b..fd00f7f204 100644 --- a/lms/static/admin/css/ie.css +++ b/lms/static/admin/css/ie.css @@ -53,5 +53,11 @@ /* IE doesn't know alpha transparency in PNGs */ .inline-deletelink { - background: transparent url(../img/admin/inline-delete-8bit.png) no-repeat; + background: transparent url(../img/inline-delete-8bit.png) no-repeat; +} + +/* IE7 doesn't support inline-block */ +.change-list ul.toplinks li { + zoom: 1; + *display: inline; } \ No newline at end of file diff --git a/lms/static/admin/css/login.css b/lms/static/admin/css/login.css index 8d90d12901..8872ade70b 100644 --- a/lms/static/admin/css/login.css +++ b/lms/static/admin/css/login.css @@ -52,3 +52,6 @@ body.login { padding: 1em 0 0 9.4em; } +.login .password-reset-link { + text-align: center; +} diff --git a/lms/static/admin/css/rtl.css b/lms/static/admin/css/rtl.css index c02241d13d..82d16024e6 100644 --- a/lms/static/admin/css/rtl.css +++ b/lms/static/admin/css/rtl.css @@ -80,15 +80,8 @@ div.breadcrumbs { /* SORTABLE TABLES */ - -table thead th.sorted a { - padding-left: 13px; - padding-right: 0px; -} - -table thead th.ascending a, -table thead th.descending a { - background-position: left; +table thead th.sorted .sortoptions { + float: left; } /* dashboard styles */ @@ -100,12 +93,8 @@ table thead th.descending a { /* changelists styles */ -.change-list ul.toplinks li { - float: right; -} - .change-list .filtered { - background: white url(../img/admin/changelist-bg_rtl.gif) top left repeat-y !important; + background: white url(../img/changelist-bg_rtl.gif) top left repeat-y !important; } .change-list .filtered table { @@ -162,7 +151,7 @@ table thead th.descending a { } .submit-row .deletelink { - background: url(../img/admin/icon_deletelink.gif) 0 50% no-repeat; + background: url(../img/icon_deletelink.gif) 0 50% no-repeat; padding-right: 14px; } @@ -183,6 +172,7 @@ input[type=submit].default, .submit-row input.default { fieldset .field-box { float: right; margin-left: 20px; + margin-right: 0; } .errorlist li { @@ -236,9 +226,20 @@ fieldset .field-box { padding-left: inherit; left: 10px; right: inherit; + float:left; } .inline-related h3 span.delete label { margin-left: inherit; margin-right: 2px; } + +/* IE7 specific bug fixes */ + +div.colM { + position: relative; +} + +.submit-row input { + float: left; +} \ No newline at end of file diff --git a/lms/static/admin/css/widgets.css b/lms/static/admin/css/widgets.css index 26400fac50..0a7012c7b2 100644 --- a/lms/static/admin/css/widgets.css +++ b/lms/static/admin/css/widgets.css @@ -17,12 +17,16 @@ margin-bottom: 5px; } +.selector-chosen select { + border-top: none; +} + .selector-available h2, .selector-chosen h2 { border: 1px solid #ccc; } .selector .selector-available h2 { - background: white url(../img/admin/nav-bg.gif) bottom left repeat-x; + background: white url(../img/nav-bg.gif) bottom left repeat-x; color: #666; } @@ -37,8 +41,10 @@ text-align: left; } -.selector .selector-chosen .selector-filter { - padding: 4px 5px; +.selector .selector-filter label, +.inline-group .aligned .selector .selector-filter label { + width: 16px; + padding: 2px; } .selector .selector-available input { @@ -49,8 +55,8 @@ float: left; width: 22px; height: 50px; - background: url(../img/admin/chooser-bg.gif) top center no-repeat; - margin: 8em 3px 0 3px; + background: url(../img/chooser-bg.gif) top center no-repeat; + margin: 10em 5px 0 5px; padding: 0; } @@ -61,7 +67,7 @@ } .selector select { - margin-bottom: 5px; + margin-bottom: 10px; margin-top: 0; } @@ -74,38 +80,66 @@ } .selector-add { - background: url(../img/admin/selector-add.gif) top center no-repeat; + background: url(../img/selector-icons.gif) 0 -161px no-repeat; + cursor: default; margin-bottom: 2px; } +.active.selector-add { + background: url(../img/selector-icons.gif) 0 -187px no-repeat; + cursor: pointer; +} + .selector-remove { - background: url(../img/admin/selector-remove.gif) top center no-repeat; + background: url(../img/selector-icons.gif) 0 -109px no-repeat; + cursor: default; +} + +.active.selector-remove { + background: url(../img/selector-icons.gif) 0 -135px no-repeat; + cursor: pointer; } a.selector-chooseall, a.selector-clearall { - display: block; - width: 6em; + display: inline-block; text-align: left; margin-left: auto; margin-right: auto; font-weight: bold; color: #666; +} + +a.selector-chooseall { + padding: 3px 18px 3px 0; +} + +a.selector-clearall { padding: 3px 0 3px 18px; } -a.selector-chooseall:hover, a.selector-clearall:hover { +a.active.selector-chooseall:hover, a.active.selector-clearall:hover { color: #036; } a.selector-chooseall { - width: 7em; - background: url(../img/admin/selector-addall.gif) left center no-repeat; + background: url(../img/selector-icons.gif) right -263px no-repeat; + cursor: default; +} + +a.active.selector-chooseall { + background: url(../img/selector-icons.gif) right -289px no-repeat; + cursor: pointer; } a.selector-clearall { - background: url(../img/admin/selector-removeall.gif) left center no-repeat; + background: url(../img/selector-icons.gif) left -211px no-repeat; + cursor: default; } +a.active.selector-clearall { + background: url(../img/selector-icons.gif) left -237px no-repeat; + cursor: pointer; +} /* STACKED SELECTORS */ @@ -135,7 +169,7 @@ a.selector-clearall { height: 22px; width: 50px; margin: 0 0 3px 40%; - background: url(../img/admin/chooser_stacked-bg.gif) top center no-repeat; + background: url(../img/chooser_stacked-bg.gif) top center no-repeat; } .stacked .selector-chooser li { @@ -148,13 +182,24 @@ a.selector-clearall { } .stacked .selector-add { - background-image: url(../img/admin/selector_stacked-add.gif); + background: url(../img/selector-icons.gif) 0 -57px no-repeat; + cursor: default; +} + +.stacked .active.selector-add { + background: url(../img/selector-icons.gif) 0 -83px no-repeat; + cursor: pointer; } .stacked .selector-remove { - background-image: url(../img/admin/selector_stacked-remove.gif); + background: url(../img/selector-icons.gif) 0 -5px no-repeat; + cursor: default; } +.stacked .active.selector-remove { + background: url(../img/selector-icons.gif) 0 -31px no-repeat; + cursor: pointer; +} /* DATE AND TIME */ @@ -231,7 +276,7 @@ span.clearable-file-input label { padding: 0; border-collapse: collapse; background: white; - width: 99%; + width: 100%; } .calendar caption, .calendarbox h2 { @@ -246,7 +291,7 @@ span.clearable-file-input label { color: #666; padding: 2px 3px; text-align: center; - background: #e1e1e1 url(../img/admin/nav-bg.gif) 0 50% repeat-x; + background: #e1e1e1 url(../img/nav-bg.gif) 0 50% repeat-x; border-bottom: 1px solid #ddd; } @@ -314,7 +359,7 @@ span.clearable-file-input label { position: absolute; font-weight: bold; font-size: 12px; - background: #C9DBED url(../img/admin/default-bg.gif) bottom left repeat-x; + background: #C9DBED url(../img/default-bg.gif) bottom left repeat-x; padding: 1px 4px 2px 4px; color: white; } @@ -335,15 +380,19 @@ span.clearable-file-input label { .calendar-cancel { margin: 0 !important; - padding: 0; + padding: 0 !important; font-size: 10px; - background: #e1e1e1 url(../img/admin/nav-bg.gif) 0 50% repeat-x; + background: #e1e1e1 url(../img/nav-bg.gif) 0 50% repeat-x; border-top: 1px solid #ddd; } +.calendar-cancel:hover { + background: #e1e1e1 url(../img/nav-bg-reverse.gif) 0 50% repeat-x; +} + .calendar-cancel a { - padding: 2px; - color: #999; + color: black; + display: block; } ul.timelist, .timelist li { @@ -374,7 +423,7 @@ ul.orderer li { border-width: 0 1px 1px 0; white-space: nowrap; overflow: hidden; - background: #e2e2e2 url(../img/admin/nav-bg-grabber.gif) repeat-y; + background: #e2e2e2 url(../img/nav-bg-grabber.gif) repeat-y; } ul.orderer li:hover { @@ -406,7 +455,7 @@ ul.orderer li.selected { } ul.orderer li.deleted { - background: #bbb url(../img/admin/deleted-overlay.gif); + background: #bbb url(../img/deleted-overlay.gif); } ul.orderer li.deleted a:link, ul.orderer li.deleted a:visited { @@ -414,7 +463,7 @@ ul.orderer li.deleted a:link, ul.orderer li.deleted a:visited { } ul.orderer li.deleted .inline-deletelink { - background-image: url(../img/admin/inline-restore.png); + background-image: url(../img/inline-restore.png); } ul.orderer li.deleted:hover, ul.orderer li.deleted a.selector:hover { @@ -426,7 +475,7 @@ ul.orderer li.deleted:hover, ul.orderer li.deleted a.selector:hover { .inline-deletelink { float: right; text-indent: -9999px; - background: transparent url(../img/admin/inline-delete.png) no-repeat; + background: transparent url(../img/inline-delete.png) no-repeat; width: 15px; height: 15px; border: 0px none; @@ -465,11 +514,11 @@ ul.orderer li.deleted:hover, ul.orderer li.deleted a.selector:hover { } .editinline tr.deleted { - background: #ddd url(../img/admin/deleted-overlay.gif); + background: #ddd url(../img/deleted-overlay.gif); } .editinline tr.deleted .inline-deletelink { - background-image: url(../img/admin/inline-restore.png); + background-image: url(../img/inline-restore.png); } .editinline tr.deleted td:hover { @@ -500,13 +549,13 @@ ul.orderer li.deleted:hover, ul.orderer li.deleted a.selector:hover { .editinline-stacked .inline-splitter { float: left; width: 9px; - background: #f8f8f8 url(../img/admin/inline-splitter-bg.gif) 50% 50% no-repeat; + background: #f8f8f8 url(../img/inline-splitter-bg.gif) 50% 50% no-repeat; border-right: 1px solid #ccc; } .editinline-stacked .controls { clear: both; - background: #e1e1e1 url(../img/admin/nav-bg.gif) top left repeat-x; + background: #e1e1e1 url(../img/nav-bg.gif) top left repeat-x; padding: 3px 4px; font-size: 11px; border-top: 1px solid #ddd; diff --git a/lms/static/admin/img/changelist-bg.gif b/lms/static/admin/img/changelist-bg.gif new file mode 100644 index 0000000000..7f4699470a Binary files /dev/null and b/lms/static/admin/img/changelist-bg.gif differ diff --git a/lms/static/admin/img/changelist-bg_rtl.gif b/lms/static/admin/img/changelist-bg_rtl.gif new file mode 100644 index 0000000000..237971257f Binary files /dev/null and b/lms/static/admin/img/changelist-bg_rtl.gif differ diff --git a/lms/static/admin/img/chooser-bg.gif b/lms/static/admin/img/chooser-bg.gif new file mode 100644 index 0000000000..30e83c2518 Binary files /dev/null and b/lms/static/admin/img/chooser-bg.gif differ diff --git a/lms/static/admin/img/chooser_stacked-bg.gif b/lms/static/admin/img/chooser_stacked-bg.gif new file mode 100644 index 0000000000..5d104b6d98 Binary files /dev/null and b/lms/static/admin/img/chooser_stacked-bg.gif differ diff --git a/lms/static/admin/img/default-bg-reverse.gif b/lms/static/admin/img/default-bg-reverse.gif new file mode 100644 index 0000000000..0873281e51 Binary files /dev/null and b/lms/static/admin/img/default-bg-reverse.gif differ diff --git a/lms/static/admin/img/default-bg.gif b/lms/static/admin/img/default-bg.gif new file mode 100644 index 0000000000..003aeca59f Binary files /dev/null and b/lms/static/admin/img/default-bg.gif differ diff --git a/lms/static/admin/img/deleted-overlay.gif b/lms/static/admin/img/deleted-overlay.gif new file mode 100644 index 0000000000..dc3828fe06 Binary files /dev/null and b/lms/static/admin/img/deleted-overlay.gif differ diff --git a/lms/static/admin/img/icon-no.gif b/lms/static/admin/img/icon-no.gif new file mode 100644 index 0000000000..1b4ee58145 Binary files /dev/null and b/lms/static/admin/img/icon-no.gif differ diff --git a/lms/static/admin/img/icon-unknown.gif b/lms/static/admin/img/icon-unknown.gif new file mode 100644 index 0000000000..cfd2b02ad9 Binary files /dev/null and b/lms/static/admin/img/icon-unknown.gif differ diff --git a/lms/static/admin/img/icon-yes.gif b/lms/static/admin/img/icon-yes.gif new file mode 100644 index 0000000000..7399282740 Binary files /dev/null and b/lms/static/admin/img/icon-yes.gif differ diff --git a/lms/static/admin/img/icon_addlink.gif b/lms/static/admin/img/icon_addlink.gif new file mode 100644 index 0000000000..ee70e1adba Binary files /dev/null and b/lms/static/admin/img/icon_addlink.gif differ diff --git a/lms/static/admin/img/icon_alert.gif b/lms/static/admin/img/icon_alert.gif new file mode 100644 index 0000000000..a1dde26254 Binary files /dev/null and b/lms/static/admin/img/icon_alert.gif differ diff --git a/lms/static/admin/img/icon_calendar.gif b/lms/static/admin/img/icon_calendar.gif new file mode 100644 index 0000000000..7587b305a4 Binary files /dev/null and b/lms/static/admin/img/icon_calendar.gif differ diff --git a/lms/static/admin/img/icon_changelink.gif b/lms/static/admin/img/icon_changelink.gif new file mode 100644 index 0000000000..e1b9afde65 Binary files /dev/null and b/lms/static/admin/img/icon_changelink.gif differ diff --git a/lms/static/admin/img/icon_clock.gif b/lms/static/admin/img/icon_clock.gif new file mode 100644 index 0000000000..ff2d57e0a3 Binary files /dev/null and b/lms/static/admin/img/icon_clock.gif differ diff --git a/lms/static/admin/img/icon_deletelink.gif b/lms/static/admin/img/icon_deletelink.gif new file mode 100644 index 0000000000..72523e3a3b Binary files /dev/null and b/lms/static/admin/img/icon_deletelink.gif differ diff --git a/lms/static/admin/img/icon_error.gif b/lms/static/admin/img/icon_error.gif new file mode 100644 index 0000000000..3730a00b26 Binary files /dev/null and b/lms/static/admin/img/icon_error.gif differ diff --git a/lms/static/admin/img/icon_searchbox.png b/lms/static/admin/img/icon_searchbox.png new file mode 100644 index 0000000000..8ab579e526 Binary files /dev/null and b/lms/static/admin/img/icon_searchbox.png differ diff --git a/lms/static/admin/img/icon_success.gif b/lms/static/admin/img/icon_success.gif new file mode 100644 index 0000000000..5cf90a15aa Binary files /dev/null and b/lms/static/admin/img/icon_success.gif differ diff --git a/lms/static/admin/img/inline-delete-8bit.png b/lms/static/admin/img/inline-delete-8bit.png new file mode 100644 index 0000000000..95caf59a8d Binary files /dev/null and b/lms/static/admin/img/inline-delete-8bit.png differ diff --git a/lms/static/admin/img/inline-delete.png b/lms/static/admin/img/inline-delete.png new file mode 100644 index 0000000000..d59bcd2444 Binary files /dev/null and b/lms/static/admin/img/inline-delete.png differ diff --git a/lms/static/admin/img/inline-restore-8bit.png b/lms/static/admin/img/inline-restore-8bit.png new file mode 100644 index 0000000000..e087c8ead3 Binary files /dev/null and b/lms/static/admin/img/inline-restore-8bit.png differ diff --git a/lms/static/admin/img/inline-restore.png b/lms/static/admin/img/inline-restore.png new file mode 100644 index 0000000000..efdd92ac39 Binary files /dev/null and b/lms/static/admin/img/inline-restore.png differ diff --git a/lms/static/admin/img/inline-splitter-bg.gif b/lms/static/admin/img/inline-splitter-bg.gif new file mode 100644 index 0000000000..32ac5b3498 Binary files /dev/null and b/lms/static/admin/img/inline-splitter-bg.gif differ diff --git a/lms/static/admin/img/nav-bg-grabber.gif b/lms/static/admin/img/nav-bg-grabber.gif new file mode 100644 index 0000000000..0a784fa769 Binary files /dev/null and b/lms/static/admin/img/nav-bg-grabber.gif differ diff --git a/lms/static/admin/img/nav-bg-reverse.gif b/lms/static/admin/img/nav-bg-reverse.gif new file mode 100644 index 0000000000..f11029f90f Binary files /dev/null and b/lms/static/admin/img/nav-bg-reverse.gif differ diff --git a/lms/static/admin/img/nav-bg-selected.gif b/lms/static/admin/img/nav-bg-selected.gif new file mode 100644 index 0000000000..98c5672ab3 Binary files /dev/null and b/lms/static/admin/img/nav-bg-selected.gif differ diff --git a/lms/static/admin/img/nav-bg.gif b/lms/static/admin/img/nav-bg.gif new file mode 100644 index 0000000000..f8402b809d Binary files /dev/null and b/lms/static/admin/img/nav-bg.gif differ diff --git a/lms/static/admin/img/selector-icons.gif b/lms/static/admin/img/selector-icons.gif new file mode 100644 index 0000000000..8809c4fb9a Binary files /dev/null and b/lms/static/admin/img/selector-icons.gif differ diff --git a/lms/static/admin/img/selector-search.gif b/lms/static/admin/img/selector-search.gif new file mode 100644 index 0000000000..6d5f4c7492 Binary files /dev/null and b/lms/static/admin/img/selector-search.gif differ diff --git a/lms/static/admin/img/sorting-icons.gif b/lms/static/admin/img/sorting-icons.gif new file mode 100644 index 0000000000..451aae5987 Binary files /dev/null and b/lms/static/admin/img/sorting-icons.gif differ diff --git a/lms/static/admin/img/tool-left.gif b/lms/static/admin/img/tool-left.gif new file mode 100644 index 0000000000..011490ff3a Binary files /dev/null and b/lms/static/admin/img/tool-left.gif differ diff --git a/lms/static/admin/img/tool-left_over.gif b/lms/static/admin/img/tool-left_over.gif new file mode 100644 index 0000000000..937e07bb1a Binary files /dev/null and b/lms/static/admin/img/tool-left_over.gif differ diff --git a/lms/static/admin/img/tool-right.gif b/lms/static/admin/img/tool-right.gif new file mode 100644 index 0000000000..cdc140cc59 Binary files /dev/null and b/lms/static/admin/img/tool-right.gif differ diff --git a/lms/static/admin/img/tool-right_over.gif b/lms/static/admin/img/tool-right_over.gif new file mode 100644 index 0000000000..4db977e838 Binary files /dev/null and b/lms/static/admin/img/tool-right_over.gif differ diff --git a/lms/static/admin/img/tooltag-add.gif b/lms/static/admin/img/tooltag-add.gif new file mode 100644 index 0000000000..8b53d49ae5 Binary files /dev/null and b/lms/static/admin/img/tooltag-add.gif differ diff --git a/lms/static/admin/img/tooltag-add_over.gif b/lms/static/admin/img/tooltag-add_over.gif new file mode 100644 index 0000000000..bfc52f10de Binary files /dev/null and b/lms/static/admin/img/tooltag-add_over.gif differ diff --git a/lms/static/admin/img/tooltag-arrowright.gif b/lms/static/admin/img/tooltag-arrowright.gif new file mode 100644 index 0000000000..cdaaae77ed Binary files /dev/null and b/lms/static/admin/img/tooltag-arrowright.gif differ diff --git a/lms/static/admin/img/tooltag-arrowright_over.gif b/lms/static/admin/img/tooltag-arrowright_over.gif new file mode 100644 index 0000000000..7163189604 Binary files /dev/null and b/lms/static/admin/img/tooltag-arrowright_over.gif differ diff --git a/lms/static/admin/js/SelectFilter2.js b/lms/static/admin/js/SelectFilter2.js index 92eff2ecfa..0accd080b7 100644 --- a/lms/static/admin/js/SelectFilter2.js +++ b/lms/static/admin/js/SelectFilter2.js @@ -1,11 +1,9 @@ /* SelectFilter2 - Turns a multiple-select box into a filter interface. -Different than SelectFilter because this is coupled to the admin framework. - Requires core.js, SelectBox.js and addevent.js. */ - +(function($) { function findForm(node) { // returns the node of the form containing the given node if (node.tagName.toLowerCase() != 'form') { @@ -14,7 +12,7 @@ function findForm(node) { return node; } -var SelectFilter = { +window.SelectFilter = { init: function(field_id, field_name, is_stacked, admin_media_prefix) { if (field_id.match(/__prefix__/)){ // Don't intialize on empty forms. @@ -44,41 +42,42 @@ var SelectFilter = { //
var selector_available = quickElement('div', selector_div, ''); selector_available.className = 'selector-available'; - quickElement('h2', selector_available, interpolate(gettext('Available %s'), [field_name])); - var filter_p = quickElement('p', selector_available, ''); + var title_available = quickElement('h2', selector_available, interpolate(gettext('Available %s') + ' ', [field_name])); + quickElement('img', title_available, '', 'src', admin_media_prefix + 'img/icon-unknown.gif', 'width', '10', 'height', '10', 'class', 'help help-tooltip', 'title', interpolate(gettext('This is the list of available %s. You may choose some by selecting them in the box below and then clicking the "Choose" arrow between the two boxes.'), [field_name])); + + var filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter'); filter_p.className = 'selector-filter'; - var search_filter_label = quickElement('label', filter_p, '', 'for', field_id + "_input", 'style', 'width:16px;padding:2px'); + var search_filter_label = quickElement('label', filter_p, '', 'for', field_id + "_input"); - var search_selector_img = quickElement('img', search_filter_label, '', 'src', admin_media_prefix + 'img/admin/selector-search.gif'); - search_selector_img.alt = gettext("Filter"); + var search_selector_img = quickElement('img', search_filter_label, '', 'src', admin_media_prefix + 'img/selector-search.gif', 'class', 'help-tooltip', 'alt', '', 'title', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name])); filter_p.appendChild(document.createTextNode(' ')); - var filter_input = quickElement('input', filter_p, '', 'type', 'text'); + var filter_input = quickElement('input', filter_p, '', 'type', 'text', 'placeholder', gettext("Filter")); filter_input.id = field_id + '_input'; + selector_available.appendChild(from_box); - var choose_all = quickElement('a', selector_available, gettext('Choose all'), 'href', 'javascript: (function(){ SelectBox.move_all("' + field_id + '_from", "' + field_id + '_to"); })()'); + var choose_all = quickElement('a', selector_available, gettext('Choose all'), 'title', interpolate(gettext('Click to choose all %s at once.'), [field_name]), 'href', 'javascript: (function(){ SelectBox.move_all("' + field_id + '_from", "' + field_id + '_to"); SelectFilter.refresh_icons("' + field_id + '");})()', 'id', field_id + '_add_all_link'); choose_all.className = 'selector-chooseall'; //