Commit bd95c03d by Calen Pennington

Merge pull request #396 from MITx/feature/ichuang/xqa-and-patches

Provide content QA (quality assessment) interface
parents a3d7c489 47c48e9c
...@@ -249,7 +249,7 @@ def load_preview_module(request, preview_id, descriptor, instance_state, shared_ ...@@ -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 = descriptor.xmodule_constructor(system)(instance_state, shared_state)
module.get_html = replace_static_urls( module.get_html = replace_static_urls(
wrap_xmodule(module.get_html, module, "xmodule_display.html"), 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(), save_preview_state(request, preview_id, descriptor.location.url(),
module.get_instance_state(), module.get_shared_state()) module.get_instance_state(), module.get_shared_state())
......
...@@ -297,6 +297,7 @@ def _do_create_account(post_vars): ...@@ -297,6 +297,7 @@ def _do_create_account(post_vars):
try: try:
user.save() user.save()
except IntegrityError: except IntegrityError:
js = {'success': False}
# Figure out the cause of the integrity error # Figure out the cause of the integrity error
if len(User.objects.filter(username=post_vars['username'])) > 0: if len(User.objects.filter(username=post_vars['username'])) > 0:
js['value'] = "An account with this username already exists." js['value'] = "An account with this username already exists."
...@@ -402,7 +403,10 @@ def create_account(request, post_override=None): ...@@ -402,7 +403,10 @@ def create_account(request, post_override=None):
return HttpResponse(json.dumps(js)) return HttpResponse(json.dumps(js))
# Ok, looks like everything is legit. Create the account. # 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'], d = {'name': post_vars['name'],
'key': registration.activation_key, 'key': registration.activation_key,
......
...@@ -34,7 +34,7 @@ def wrap_xmodule(get_html, module, template): ...@@ -34,7 +34,7 @@ def wrap_xmodule(get_html, module, template):
return _get_html 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 Updates the supplied module with a new get_html function that wraps
the old get_html function and substitutes urls of the form /static/... the old get_html function and substitutes urls of the form /static/...
...@@ -69,14 +69,14 @@ def grade_histogram(module_id): ...@@ -69,14 +69,14 @@ def grade_histogram(module_id):
return grades 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 Updates the supplied module with a new get_html function that wraps
the output of the old get_html function with additional information the output of the old get_html function with additional information
for admin users only, including a histogram of student answers and the for admin users only, including a histogram of student answers and the
definition of the xmodule definition of the xmodule
Does nothing if module is a SequenceModule Does nothing if module is a SequenceModule or a VerticalModule.
""" """
@wraps(get_html) @wraps(get_html)
def _get_html(): def _get_html():
...@@ -97,14 +97,20 @@ def add_histogram(get_html, module): ...@@ -97,14 +97,20 @@ def add_histogram(get_html, module):
# doesn't like symlinks) # doesn't like symlinks)
filepath = filename filepath = filename
data_dir = osfs.root_path.rsplit('/')[-1] 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: else:
edit_link = False edit_link = False
staff_context = {'definition': module.definition.get('data'), staff_context = {'definition': module.definition.get('data'),
'metadata': json.dumps(module.metadata, indent=4), '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, '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), 'histogram': json.dumps(histogram),
'render_histogram': render_histogram, 'render_histogram': render_histogram,
'module_content': get_html()} 'module_content': get_html()}
......
...@@ -393,9 +393,10 @@ class LoncapaProblem(object): ...@@ -393,9 +393,10 @@ class LoncapaProblem(object):
context['script_code'] += code # store code source in context context['script_code'] += code # store code source in context
try: try:
exec code in context, context # use "context" for global context; thus defs in code are global within code 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) 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('<','&lt;')
raise responsetypes.LoncapaProblemError(msg)
finally: finally:
sys.path = original_path sys.path = original_path
......
...@@ -319,7 +319,8 @@ class XModuleDescriptor(Plugin, HTMLSnippet): ...@@ -319,7 +319,8 @@ class XModuleDescriptor(Plugin, HTMLSnippet):
# A list of metadata that this module can inherit from its parent module # A list of metadata that this module can inherit from its parent module
inheritable_metadata = ( inheritable_metadata = (
'graded', 'start', 'due', 'graceperiod', 'showanswer', 'rerandomize', '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 # 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 # static files, and will need to be removed when that code is removed
'data_dir' 'data_dir'
......
from xmodule.x_module import XModuleDescriptor from xmodule.x_module import XModuleDescriptor
from xmodule.modulestore import Location from xmodule.modulestore import Location
from lxml import etree from lxml import etree
import json
import copy import copy
import logging import logging
import traceback import traceback
...@@ -32,7 +33,15 @@ def is_pointer_tag(xml_obj): ...@@ -32,7 +33,15 @@ def is_pointer_tag(xml_obj):
actual_attr = set(xml_obj.attrib.keys()) actual_attr = set(xml_obj.attrib.keys())
return len(xml_obj) == 0 and actual_attr == expected_attr 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') _AttrMapBase = namedtuple('_AttrMap', 'from_xml to_xml')
...@@ -71,6 +80,7 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -71,6 +80,7 @@ class XmlDescriptor(XModuleDescriptor):
metadata_attributes = ('format', 'graceperiod', 'showanswer', 'rerandomize', metadata_attributes = ('format', 'graceperiod', 'showanswer', 'rerandomize',
'start', 'due', 'graded', 'display_name', 'url_name', 'hide_from_toc', 'start', 'due', 'graded', 'display_name', 'url_name', 'hide_from_toc',
'ispublic', # if True, then course is listed for all users; see 'ispublic', # if True, then course is listed for all users; see
'xqa_key', # for xqaa server access
# VS[compat] Remove once unused. # VS[compat] Remove once unused.
'name', 'slug') 'name', 'slug')
...@@ -180,8 +190,11 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -180,8 +190,11 @@ class XmlDescriptor(XModuleDescriptor):
definition_xml = cls.load_file(filepath, system.resources_fs, location) 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) cls.clean_metadata_from_xml(definition_xml)
definition = cls.definition_from_xml(definition_xml, system) definition = cls.definition_from_xml(definition_xml, system)
if definition_metadata:
definition['definition_metadata'] = definition_metadata
# TODO (ichuang): remove this after migration # TODO (ichuang): remove this after migration
# for Fall 2012 LMS migration: keep filename (and unmangled filename) # for Fall 2012 LMS migration: keep filename (and unmangled filename)
...@@ -236,9 +249,9 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -236,9 +249,9 @@ class XmlDescriptor(XModuleDescriptor):
filepath = cls._format_filepath(xml_object.tag, url_name) filepath = cls._format_filepath(xml_object.tag, url_name)
definition_xml = cls.load_file(filepath, system.resources_fs, location) definition_xml = cls.load_file(filepath, system.resources_fs, location)
else: 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 # VS[compat] -- make Ike's github preview links work in both old and
# new file layouts # new file layouts
if is_pointer_tag(xml_object): if is_pointer_tag(xml_object):
...@@ -246,6 +259,17 @@ class XmlDescriptor(XModuleDescriptor): ...@@ -246,6 +259,17 @@ class XmlDescriptor(XModuleDescriptor):
definition['filename'] = [filepath, filepath] definition['filename'] = [filepath, filepath]
metadata = cls.load_metadata(definition_xml) 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( return cls(
system, system,
definition, definition,
......
...@@ -199,17 +199,18 @@ def get_module(user, request, location, student_module_cache, position=None): ...@@ -199,17 +199,18 @@ def get_module(user, request, location, student_module_cache, position=None):
) )
# pass position specified in URL to module through ModuleSystem # pass position specified in URL to module through ModuleSystem
system.set('position', position) system.set('position', position)
system.set('DEBUG',settings.DEBUG)
module = descriptor.xmodule_constructor(system)(instance_state, shared_state) module = descriptor.xmodule_constructor(system)(instance_state, shared_state)
module.get_html = replace_static_urls( module.get_html = replace_static_urls(
wrap_xmodule(module.get_html, module, 'xmodule_display.html'), 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 settings.MITX_FEATURES.get('DISPLAY_HISTOGRAMS_TO_STAFF'):
if has_staff_access_to_course(user, module.location.course): 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 return module
......
...@@ -56,6 +56,8 @@ MITX_FEATURES = { ...@@ -56,6 +56,8 @@ MITX_FEATURES = {
'ENABLE_SQL_TRACKING_LOGS': False, 'ENABLE_SQL_TRACKING_LOGS': False,
'ENABLE_LMS_MIGRATION': False, 'ENABLE_LMS_MIGRATION': False,
'DISABLE_LOGIN_BUTTON': False, # used in systems where login is automatic, eg MIT SSL
# extrernal access methods # extrernal access methods
'ACCESS_REQUIRE_STAFF_FOR_COURSE': False, 'ACCESS_REQUIRE_STAFF_FOR_COURSE': False,
'AUTH_USE_OPENID': False, 'AUTH_USE_OPENID': False,
......
...@@ -62,6 +62,7 @@ SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd' ...@@ -62,6 +62,7 @@ SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
################################ LMS Migration ################################# ################################ LMS Migration #################################
MITX_FEATURES['ENABLE_LMS_MIGRATION'] = True 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['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'] LMS_MIGRATION_ALLOWED_IPS = ['127.0.0.1']
......
...@@ -10,14 +10,27 @@ sessions. Assumes structure: ...@@ -10,14 +10,27 @@ sessions. Assumes structure:
from .common import * from .common import *
from .logsettings import get_logger_config from .logsettings import get_logger_config
from .dev import * from .dev import *
import socket
WIKI_ENABLED = False WIKI_ENABLED = False
MITX_FEATURES['ENABLE_TEXTBOOK'] = False MITX_FEATURES['ENABLE_TEXTBOOK'] = False
MITX_FEATURES['ENABLE_DISCUSSION'] = 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 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 # disable django debug toolbars
INSTALLED_APPS = tuple([ app for app in INSTALLED_APPS if not app.startswith('debug_toolbar') ]) 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') ]) 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') ])
...@@ -189,6 +189,10 @@ p.mini { ...@@ -189,6 +189,10 @@ p.mini {
color: #999; color: #999;
} }
img.help-tooltip {
cursor: help;
}
p img, h1 img, h2 img, h3 img, h4 img, td img { p img, h1 img, h2 img, h3 img, h4 img, td img {
vertical-align: middle; vertical-align: middle;
} }
...@@ -259,7 +263,7 @@ tfoot td { ...@@ -259,7 +263,7 @@ tfoot td {
color: #666; color: #666;
padding: 2px 5px; padding: 2px 5px;
font-size: 11px; 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-left: 1px solid #ddd;
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
} }
...@@ -305,25 +309,84 @@ tr.alt { ...@@ -305,25 +309,84 @@ tr.alt {
/* SORTABLE TABLES */ /* SORTABLE TABLES */
thead th {
padding: 2px 5px;
line-height: normal;
}
thead th a:link, thead th a:visited { thead th a:link, thead th a:visited {
color: #666; 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.sortable:hover {
background: white url(../img/nav-bg-reverse.gif) 0 -5px repeat-x;
}
thead th.sorted a.sortremove {
visibility: hidden;
}
table thead th.sorted:hover a.sortremove {
visibility: visible;
}
table thead th.sorted .sortoptions {
display: block; 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 { table thead th.sorted .sortoptions a.ascending {
background-position: bottom left !important; background: url(../img/sorting-icons.gif) -5px -50px no-repeat;
} }
table thead th.sorted a { table thead th.sorted .sortoptions a.ascending:hover {
padding-right: 13px; background: url(../img/sorting-icons.gif) -5px -72px no-repeat;
} }
table thead th.ascending a { table thead th.sorted .sortoptions a.descending {
background: url(../img/admin/arrow-up.gif) right .4em no-repeat; background: url(../img/sorting-icons.gif) -5px -94px no-repeat;
} }
table thead th.descending a { table thead th.sorted .sortoptions a.descending:hover {
background: url(../img/admin/arrow-down.gif) right .4em no-repeat; background: url(../img/sorting-icons.gif) -5px -115px no-repeat;
} }
/* ORDERABLE TABLES */ /* ORDERABLE TABLES */
...@@ -334,7 +397,7 @@ table.orderable tbody tr td:hover { ...@@ -334,7 +397,7 @@ table.orderable tbody tr td:hover {
table.orderable tbody tr td:first-child { table.orderable tbody tr td:first-child {
padding-left: 14px; padding-left: 14px;
background-image: url(../img/admin/nav-bg-grabber.gif); background-image: url(../img/nav-bg-grabber.gif);
background-repeat: repeat-y; background-repeat: repeat-y;
} }
...@@ -364,7 +427,7 @@ input[type=text], input[type=password], textarea, select, .vTextField { ...@@ -364,7 +427,7 @@ input[type=text], input[type=password], textarea, select, .vTextField {
/* FORM BUTTONS */ /* FORM BUTTONS */
.button, input[type=submit], input[type=button], .submit-row input { .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; padding: 3px 5px;
color: black; color: black;
border: 1px solid #bbb; border: 1px solid #bbb;
...@@ -372,31 +435,31 @@ input[type=text], input[type=password], textarea, select, .vTextField { ...@@ -372,31 +435,31 @@ input[type=text], input[type=password], textarea, select, .vTextField {
} }
.button:active, input[type=submit]:active, input[type=button]:active { .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; background-position: top;
} }
.button[disabled], input[type=submit][disabled], input[type=button][disabled] { .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; background-position: bottom;
opacity: 0.4; opacity: 0.4;
} }
.button.default, input[type=submit].default, .submit-row input.default { .button.default, input[type=submit].default, .submit-row input.default {
border: 2px solid #5b80b2; 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; font-weight: bold;
color: white; color: white;
float: right; float: right;
} }
.button.default:active, input[type=submit].default:active { .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; background-position: top;
} }
.button[disabled].default, input[type=submit][disabled].default, input[type=button][disabled].default { .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; background-position: bottom;
opacity: 0.4; opacity: 0.4;
} }
...@@ -433,7 +496,7 @@ input[type=text], input[type=password], textarea, select, .vTextField { ...@@ -433,7 +496,7 @@ input[type=text], input[type=password], textarea, select, .vTextField {
font-size: 11px; font-size: 11px;
text-align: left; text-align: left;
font-weight: bold; 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; color: white;
} }
...@@ -455,15 +518,15 @@ ul.messagelist li { ...@@ -455,15 +518,15 @@ ul.messagelist li {
margin: 0 0 3px 0; margin: 0 0 3px 0;
border-bottom: 1px solid #ddd; border-bottom: 1px solid #ddd;
color: #666; 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{ ul.messagelist li.warning{
background-image: url(../img/admin/icon_alert.gif); background-image: url(../img/icon_alert.gif);
} }
ul.messagelist li.error{ ul.messagelist li.error{
background-image: url(../img/admin/icon_error.gif); background-image: url(../img/icon_error.gif);
} }
.errornote { .errornote {
...@@ -473,7 +536,7 @@ ul.messagelist li.error{ ...@@ -473,7 +536,7 @@ ul.messagelist li.error{
margin: 0 0 3px 0; margin: 0 0 3px 0;
border: 1px solid red; border: 1px solid red;
color: 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 { ul.errorlist {
...@@ -488,7 +551,7 @@ ul.errorlist { ...@@ -488,7 +551,7 @@ ul.errorlist {
margin: 0 0 3px 0; margin: 0 0 3px 0;
border: 1px solid red; border: 1px solid red;
color: white; 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 { .errorlist li a {
...@@ -524,7 +587,7 @@ div.system-message p.system-message-title { ...@@ -524,7 +587,7 @@ div.system-message p.system-message-title {
padding: 4px 5px 4px 25px; padding: 4px 5px 4px 25px;
margin: 0; margin: 0;
color: 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;
} }
.description { .description {
...@@ -535,7 +598,7 @@ div.system-message p.system-message-title { ...@@ -535,7 +598,7 @@ div.system-message p.system-message-title {
/* BREADCRUMBS */ /* BREADCRUMBS */
div.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; padding: 2px 8px 3px 8px;
font-size: 11px; font-size: 11px;
color: #999; color: #999;
...@@ -548,17 +611,17 @@ div.breadcrumbs { ...@@ -548,17 +611,17 @@ div.breadcrumbs {
.addlink { .addlink {
padding-left: 12px; 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 { .changelink {
padding-left: 12px; 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 { .deletelink {
padding-left: 12px; 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 { a.deletelink:link, a.deletelink:visited {
...@@ -593,14 +656,14 @@ a.deletelink:hover { ...@@ -593,14 +656,14 @@ a.deletelink:hover {
.object-tools li { .object-tools li {
display: block; display: block;
float: left; 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; padding: 0 0 0 8px;
margin-left: 2px; margin-left: 2px;
height: 16px; height: 16px;
} }
.object-tools li:hover { .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 { .object-tools a:link, .object-tools a:visited {
...@@ -609,29 +672,29 @@ a.deletelink:hover { ...@@ -609,29 +672,29 @@ a.deletelink:hover {
color: white; color: white;
padding: .1em 14px .1em 8px; padding: .1em 14px .1em 8px;
height: 14px; 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 { .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 { .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; padding-right: 28px;
} }
.object-tools a.viewsitelink:hover, .object-tools a.golink:hover { .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 { .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; padding-right: 28px;
} }
.object-tools a.addlink:hover { .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 */ /* OBJECT HISTORY */
...@@ -766,7 +829,7 @@ table#change-history tbody th { ...@@ -766,7 +829,7 @@ table#change-history tbody th {
} }
#content-related .module h2 { #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; color: #666;
} }
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
} }
.change-list .filtered { .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 { .change-list .filtered .results, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull {
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
color: #666; color: #666;
border-top: 1px solid #eee; border-top: 1px solid #eee;
border-bottom: 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; overflow: hidden;
} }
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
/* CHANGELIST TABLES */ /* CHANGELIST TABLES */
#changelist table thead th { #changelist table thead th {
padding: 0;
white-space: nowrap; white-space: nowrap;
vertical-align: middle; vertical-align: middle;
} }
...@@ -82,7 +83,7 @@ ...@@ -82,7 +83,7 @@
#changelist #toolbar { #changelist #toolbar {
padding: 3px; padding: 3px;
border-bottom: 1px solid #ddd; 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; color: #666;
} }
...@@ -156,7 +157,7 @@ ...@@ -156,7 +157,7 @@
.change-list ul.toplinks { .change-list ul.toplinks {
display: block; 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; border-top: 1px solid white;
float: left; float: left;
padding: 0 !important; padding: 0 !important;
...@@ -165,11 +166,10 @@ ...@@ -165,11 +166,10 @@
} }
.change-list ul.toplinks li { .change-list ul.toplinks li {
float: left;
width: 9em;
padding: 3px 6px; padding: 3px 6px;
font-weight: bold; font-weight: bold;
list-style-type: none; list-style-type: none;
display: inline-block;
} }
.change-list ul.toplinks .date-back a { .change-list ul.toplinks .date-back a {
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
padding: 3px; padding: 3px;
border-top: 1px solid #fff; border-top: 1px solid #fff;
border-bottom: 1px solid #ddd; 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 { #changelist .actions.selected {
......
...@@ -140,7 +140,7 @@ fieldset.collapsed h2, fieldset.collapsed { ...@@ -140,7 +140,7 @@ fieldset.collapsed h2, fieldset.collapsed {
} }
fieldset.collapsed h2 { fieldset.collapsed h2 {
background-image: url(../img/admin/nav-bg.gif); background-image: url(../img/nav-bg.gif);
background-position: bottom left; background-position: bottom left;
color: #999; color: #999;
} }
...@@ -161,12 +161,16 @@ fieldset.monospace textarea { ...@@ -161,12 +161,16 @@ fieldset.monospace textarea {
.submit-row { .submit-row {
padding: 5px 7px; padding: 5px 7px;
text-align: right; 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; border: 1px solid #ccc;
margin: 5px 0; margin: 5px 0;
overflow: hidden; overflow: hidden;
} }
body.popup .submit-row {
overflow: auto;
}
.submit-row input { .submit-row input {
margin: 0 0 0 5px; margin: 0 0 0 5px;
} }
...@@ -180,7 +184,7 @@ fieldset.monospace textarea { ...@@ -180,7 +184,7 @@ fieldset.monospace textarea {
} }
.submit-row .deletelink { .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; padding-left: 14px;
} }
...@@ -247,7 +251,7 @@ fieldset.monospace textarea { ...@@ -247,7 +251,7 @@ fieldset.monospace textarea {
color: #666; color: #666;
padding: 3px 5px; padding: 3px 5px;
font-size: 11px; 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; border-bottom: 1px solid #ddd;
} }
...@@ -332,7 +336,7 @@ fieldset.monospace textarea { ...@@ -332,7 +336,7 @@ fieldset.monospace textarea {
color: #666; color: #666;
padding: 3px 5px; padding: 3px 5px;
border-bottom: 1px solid #ddd; 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 { .inline-group .tabular tr.add-row td {
...@@ -343,7 +347,7 @@ fieldset.monospace textarea { ...@@ -343,7 +347,7 @@ fieldset.monospace textarea {
.inline-group ul.tools a.add, .inline-group ul.tools a.add,
.inline-group div.add-row a, .inline-group div.add-row a,
.inline-group .tabular tr.add-row td 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; padding-left: 14px;
font-size: 11px; font-size: 11px;
outline: 0; /* Remove dotted border around link */ outline: 0; /* Remove dotted border around link */
...@@ -352,9 +356,3 @@ fieldset.monospace textarea { ...@@ -352,9 +356,3 @@ fieldset.monospace textarea {
.empty-form { .empty-form {
display: none; display: none;
} }
/* IE7 specific bug fixes */
.submit-row input {
float: right;
}
\ No newline at end of file
...@@ -53,5 +53,11 @@ ...@@ -53,5 +53,11 @@
/* IE doesn't know alpha transparency in PNGs */ /* IE doesn't know alpha transparency in PNGs */
.inline-deletelink { .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
...@@ -52,3 +52,6 @@ body.login { ...@@ -52,3 +52,6 @@ body.login {
padding: 1em 0 0 9.4em; padding: 1em 0 0 9.4em;
} }
.login .password-reset-link {
text-align: center;
}
...@@ -80,15 +80,8 @@ div.breadcrumbs { ...@@ -80,15 +80,8 @@ div.breadcrumbs {
/* SORTABLE TABLES */ /* SORTABLE TABLES */
table thead th.sorted .sortoptions {
table thead th.sorted a { float: left;
padding-left: 13px;
padding-right: 0px;
}
table thead th.ascending a,
table thead th.descending a {
background-position: left;
} }
/* dashboard styles */ /* dashboard styles */
...@@ -100,12 +93,8 @@ table thead th.descending a { ...@@ -100,12 +93,8 @@ table thead th.descending a {
/* changelists styles */ /* changelists styles */
.change-list ul.toplinks li {
float: right;
}
.change-list .filtered { .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 { .change-list .filtered table {
...@@ -162,7 +151,7 @@ table thead th.descending a { ...@@ -162,7 +151,7 @@ table thead th.descending a {
} }
.submit-row .deletelink { .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; padding-right: 14px;
} }
...@@ -183,6 +172,7 @@ input[type=submit].default, .submit-row input.default { ...@@ -183,6 +172,7 @@ input[type=submit].default, .submit-row input.default {
fieldset .field-box { fieldset .field-box {
float: right; float: right;
margin-left: 20px; margin-left: 20px;
margin-right: 0;
} }
.errorlist li { .errorlist li {
...@@ -236,9 +226,20 @@ fieldset .field-box { ...@@ -236,9 +226,20 @@ fieldset .field-box {
padding-left: inherit; padding-left: inherit;
left: 10px; left: 10px;
right: inherit; right: inherit;
float:left;
} }
.inline-related h3 span.delete label { .inline-related h3 span.delete label {
margin-left: inherit; margin-left: inherit;
margin-right: 2px; margin-right: 2px;
} }
/* IE7 specific bug fixes */
div.colM {
position: relative;
}
.submit-row input {
float: left;
}
\ No newline at end of file
...@@ -17,12 +17,16 @@ ...@@ -17,12 +17,16 @@
margin-bottom: 5px; margin-bottom: 5px;
} }
.selector-chosen select {
border-top: none;
}
.selector-available h2, .selector-chosen h2 { .selector-available h2, .selector-chosen h2 {
border: 1px solid #ccc; border: 1px solid #ccc;
} }
.selector .selector-available h2 { .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; color: #666;
} }
...@@ -37,8 +41,10 @@ ...@@ -37,8 +41,10 @@
text-align: left; text-align: left;
} }
.selector .selector-chosen .selector-filter { .selector .selector-filter label,
padding: 4px 5px; .inline-group .aligned .selector .selector-filter label {
width: 16px;
padding: 2px;
} }
.selector .selector-available input { .selector .selector-available input {
...@@ -49,8 +55,8 @@ ...@@ -49,8 +55,8 @@
float: left; float: left;
width: 22px; width: 22px;
height: 50px; height: 50px;
background: url(../img/admin/chooser-bg.gif) top center no-repeat; background: url(../img/chooser-bg.gif) top center no-repeat;
margin: 8em 3px 0 3px; margin: 10em 5px 0 5px;
padding: 0; padding: 0;
} }
...@@ -61,7 +67,7 @@ ...@@ -61,7 +67,7 @@
} }
.selector select { .selector select {
margin-bottom: 5px; margin-bottom: 10px;
margin-top: 0; margin-top: 0;
} }
...@@ -74,38 +80,66 @@ ...@@ -74,38 +80,66 @@
} }
.selector-add { .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; margin-bottom: 2px;
} }
.active.selector-add {
background: url(../img/selector-icons.gif) 0 -187px no-repeat;
cursor: pointer;
}
.selector-remove { .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 { a.selector-chooseall, a.selector-clearall {
display: block; display: inline-block;
width: 6em;
text-align: left; text-align: left;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
font-weight: bold; font-weight: bold;
color: #666; color: #666;
}
a.selector-chooseall {
padding: 3px 18px 3px 0;
}
a.selector-clearall {
padding: 3px 0 3px 18px; 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; color: #036;
} }
a.selector-chooseall { a.selector-chooseall {
width: 7em; background: url(../img/selector-icons.gif) right -263px no-repeat;
background: url(../img/admin/selector-addall.gif) left center no-repeat; cursor: default;
}
a.active.selector-chooseall {
background: url(../img/selector-icons.gif) right -289px no-repeat;
cursor: pointer;
} }
a.selector-clearall { 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 */ /* STACKED SELECTORS */
...@@ -135,7 +169,7 @@ a.selector-clearall { ...@@ -135,7 +169,7 @@ a.selector-clearall {
height: 22px; height: 22px;
width: 50px; width: 50px;
margin: 0 0 3px 40%; 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 { .stacked .selector-chooser li {
...@@ -148,13 +182,24 @@ a.selector-clearall { ...@@ -148,13 +182,24 @@ a.selector-clearall {
} }
.stacked .selector-add { .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 { .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 */ /* DATE AND TIME */
...@@ -231,7 +276,7 @@ span.clearable-file-input label { ...@@ -231,7 +276,7 @@ span.clearable-file-input label {
padding: 0; padding: 0;
border-collapse: collapse; border-collapse: collapse;
background: white; background: white;
width: 99%; width: 100%;
} }
.calendar caption, .calendarbox h2 { .calendar caption, .calendarbox h2 {
...@@ -246,7 +291,7 @@ span.clearable-file-input label { ...@@ -246,7 +291,7 @@ span.clearable-file-input label {
color: #666; color: #666;
padding: 2px 3px; padding: 2px 3px;
text-align: center; 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; border-bottom: 1px solid #ddd;
} }
...@@ -314,7 +359,7 @@ span.clearable-file-input label { ...@@ -314,7 +359,7 @@ span.clearable-file-input label {
position: absolute; position: absolute;
font-weight: bold; font-weight: bold;
font-size: 12px; 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; padding: 1px 4px 2px 4px;
color: white; color: white;
} }
...@@ -335,15 +380,19 @@ span.clearable-file-input label { ...@@ -335,15 +380,19 @@ span.clearable-file-input label {
.calendar-cancel { .calendar-cancel {
margin: 0 !important; margin: 0 !important;
padding: 0; padding: 0 !important;
font-size: 10px; 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; border-top: 1px solid #ddd;
} }
.calendar-cancel:hover {
background: #e1e1e1 url(../img/nav-bg-reverse.gif) 0 50% repeat-x;
}
.calendar-cancel a { .calendar-cancel a {
padding: 2px; color: black;
color: #999; display: block;
} }
ul.timelist, .timelist li { ul.timelist, .timelist li {
...@@ -374,7 +423,7 @@ ul.orderer li { ...@@ -374,7 +423,7 @@ ul.orderer li {
border-width: 0 1px 1px 0; border-width: 0 1px 1px 0;
white-space: nowrap; white-space: nowrap;
overflow: hidden; 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 { ul.orderer li:hover {
...@@ -406,7 +455,7 @@ ul.orderer li.selected { ...@@ -406,7 +455,7 @@ ul.orderer li.selected {
} }
ul.orderer li.deleted { 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 { 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 { ...@@ -414,7 +463,7 @@ ul.orderer li.deleted a:link, ul.orderer li.deleted a:visited {
} }
ul.orderer li.deleted .inline-deletelink { 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 { 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 { ...@@ -426,7 +475,7 @@ ul.orderer li.deleted:hover, ul.orderer li.deleted a.selector:hover {
.inline-deletelink { .inline-deletelink {
float: right; float: right;
text-indent: -9999px; text-indent: -9999px;
background: transparent url(../img/admin/inline-delete.png) no-repeat; background: transparent url(../img/inline-delete.png) no-repeat;
width: 15px; width: 15px;
height: 15px; height: 15px;
border: 0px none; border: 0px none;
...@@ -465,11 +514,11 @@ ul.orderer li.deleted:hover, ul.orderer li.deleted a.selector:hover { ...@@ -465,11 +514,11 @@ ul.orderer li.deleted:hover, ul.orderer li.deleted a.selector:hover {
} }
.editinline tr.deleted { .editinline tr.deleted {
background: #ddd url(../img/admin/deleted-overlay.gif); background: #ddd url(../img/deleted-overlay.gif);
} }
.editinline tr.deleted .inline-deletelink { .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 { .editinline tr.deleted td:hover {
...@@ -500,13 +549,13 @@ ul.orderer li.deleted:hover, ul.orderer li.deleted a.selector:hover { ...@@ -500,13 +549,13 @@ ul.orderer li.deleted:hover, ul.orderer li.deleted a.selector:hover {
.editinline-stacked .inline-splitter { .editinline-stacked .inline-splitter {
float: left; float: left;
width: 9px; 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; border-right: 1px solid #ccc;
} }
.editinline-stacked .controls { .editinline-stacked .controls {
clear: both; 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; padding: 3px 4px;
font-size: 11px; font-size: 11px;
border-top: 1px solid #ddd; border-top: 1px solid #ddd;
......
/* /*
SelectFilter2 - Turns a multiple-select box into a filter interface. 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. Requires core.js, SelectBox.js and addevent.js.
*/ */
(function($) {
function findForm(node) { function findForm(node) {
// returns the node of the form containing the given node // returns the node of the form containing the given node
if (node.tagName.toLowerCase() != 'form') { if (node.tagName.toLowerCase() != 'form') {
...@@ -14,7 +12,7 @@ function findForm(node) { ...@@ -14,7 +12,7 @@ function findForm(node) {
return node; return node;
} }
var SelectFilter = { window.SelectFilter = {
init: function(field_id, field_name, is_stacked, admin_media_prefix) { init: function(field_id, field_name, is_stacked, admin_media_prefix) {
if (field_id.match(/__prefix__/)){ if (field_id.match(/__prefix__/)){
// Don't intialize on empty forms. // Don't intialize on empty forms.
...@@ -44,41 +42,42 @@ var SelectFilter = { ...@@ -44,41 +42,42 @@ var SelectFilter = {
// <div class="selector-available"> // <div class="selector-available">
var selector_available = quickElement('div', selector_div, ''); var selector_available = quickElement('div', selector_div, '');
selector_available.className = 'selector-available'; selector_available.className = 'selector-available';
quickElement('h2', selector_available, interpolate(gettext('Available %s'), [field_name])); var title_available = quickElement('h2', selector_available, interpolate(gettext('Available %s') + ' ', [field_name]));
var filter_p = quickElement('p', selector_available, ''); 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'; 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'); 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]));
search_selector_img.alt = gettext("Filter");
filter_p.appendChild(document.createTextNode(' ')); 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'; filter_input.id = field_id + '_input';
selector_available.appendChild(from_box); 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'; choose_all.className = 'selector-chooseall';
// <ul class="selector-chooser"> // <ul class="selector-chooser">
var selector_chooser = quickElement('ul', selector_div, ''); var selector_chooser = quickElement('ul', selector_div, '');
selector_chooser.className = 'selector-chooser'; selector_chooser.className = 'selector-chooser';
var add_link = quickElement('a', quickElement('li', selector_chooser, ''), gettext('Add'), 'href', 'javascript: (function(){ SelectBox.move("' + field_id + '_from","' + field_id + '_to");})()'); var add_link = quickElement('a', quickElement('li', selector_chooser, ''), gettext('Choose'), 'title', gettext('Choose'), 'href', 'javascript: (function(){ SelectBox.move("' + field_id + '_from","' + field_id + '_to"); SelectFilter.refresh_icons("' + field_id + '");})()', 'id', field_id + '_add_link');
add_link.className = 'selector-add'; add_link.className = 'selector-add';
var remove_link = quickElement('a', quickElement('li', selector_chooser, ''), gettext('Remove'), 'href', 'javascript: (function(){ SelectBox.move("' + field_id + '_to","' + field_id + '_from");})()'); var remove_link = quickElement('a', quickElement('li', selector_chooser, ''), gettext('Remove'), 'title', gettext('Remove'), 'href', 'javascript: (function(){ SelectBox.move("' + field_id + '_to","' + field_id + '_from"); SelectFilter.refresh_icons("' + field_id + '");})()', 'id', field_id + '_remove_link');
remove_link.className = 'selector-remove'; remove_link.className = 'selector-remove';
// <div class="selector-chosen"> // <div class="selector-chosen">
var selector_chosen = quickElement('div', selector_div, ''); var selector_chosen = quickElement('div', selector_div, '');
selector_chosen.className = 'selector-chosen'; selector_chosen.className = 'selector-chosen';
quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s'), [field_name])); var title_chosen = quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s') + ' ', [field_name]));
var selector_filter = quickElement('p', selector_chosen, gettext('Select your choice(s) and click ')); quickElement('img', title_chosen, '', 'src', admin_media_prefix + 'img/icon-unknown.gif', 'width', '10', 'height', '10', 'class', 'help help-tooltip', 'title', interpolate(gettext('This is the list of chosen %s. You may remove some by selecting them in the box below and then clicking the "Remove" arrow between the two boxes.'), [field_name]));
selector_filter.className = 'selector-filter';
quickElement('img', selector_filter, '', 'src', admin_media_prefix + (is_stacked ? 'img/admin/selector_stacked-add.gif':'img/admin/selector-add.gif'), 'alt', 'Add');
var to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', 'multiple', 'size', from_box.size, 'name', from_box.getAttribute('name')); var to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', 'multiple', 'size', from_box.size, 'name', from_box.getAttribute('name'));
to_box.className = 'filtered'; to_box.className = 'filtered';
var clear_all = quickElement('a', selector_chosen, gettext('Clear all'), 'href', 'javascript: (function() { SelectBox.move_all("' + field_id + '_to", "' + field_id + '_from");})()'); var clear_all = quickElement('a', selector_chosen, gettext('Remove all'), 'title', interpolate(gettext('Click to remove all chosen %s at once.'), [field_name]), 'href', 'javascript: (function() { SelectBox.move_all("' + field_id + '_to", "' + field_id + '_from"); SelectFilter.refresh_icons("' + field_id + '");})()', 'id', field_id + '_remove_all_link');
clear_all.className = 'selector-clearall'; clear_all.className = 'selector-clearall';
from_box.setAttribute('name', from_box.getAttribute('name') + '_old'); from_box.setAttribute('name', from_box.getAttribute('name') + '_old');
...@@ -86,16 +85,46 @@ var SelectFilter = { ...@@ -86,16 +85,46 @@ var SelectFilter = {
// Set up the JavaScript event handlers for the select box filter interface // Set up the JavaScript event handlers for the select box filter interface
addEvent(filter_input, 'keyup', function(e) { SelectFilter.filter_key_up(e, field_id); }); addEvent(filter_input, 'keyup', function(e) { SelectFilter.filter_key_up(e, field_id); });
addEvent(filter_input, 'keydown', function(e) { SelectFilter.filter_key_down(e, field_id); }); addEvent(filter_input, 'keydown', function(e) { SelectFilter.filter_key_down(e, field_id); });
addEvent(from_box, 'dblclick', function() { SelectBox.move(field_id + '_from', field_id + '_to'); }); addEvent(from_box, 'change', function(e) { SelectFilter.refresh_icons(field_id) });
addEvent(to_box, 'dblclick', function() { SelectBox.move(field_id + '_to', field_id + '_from'); }); addEvent(to_box, 'change', function(e) { SelectFilter.refresh_icons(field_id) });
addEvent(from_box, 'dblclick', function() { SelectBox.move(field_id + '_from', field_id + '_to'); SelectFilter.refresh_icons(field_id); });
addEvent(to_box, 'dblclick', function() { SelectBox.move(field_id + '_to', field_id + '_from'); SelectFilter.refresh_icons(field_id); });
addEvent(findForm(from_box), 'submit', function() { SelectBox.select_all(field_id + '_to'); }); addEvent(findForm(from_box), 'submit', function() { SelectBox.select_all(field_id + '_to'); });
SelectBox.init(field_id + '_from'); SelectBox.init(field_id + '_from');
SelectBox.init(field_id + '_to'); SelectBox.init(field_id + '_to');
// Move selected from_box options to to_box // Move selected from_box options to to_box
SelectBox.move(field_id + '_from', field_id + '_to'); SelectBox.move(field_id + '_from', field_id + '_to');
if (!is_stacked) {
// In horizontal mode, give the same height to the two boxes.
var j_from_box = $(from_box);
var j_to_box = $(to_box);
var resize_filters = function() { j_to_box.height($(filter_p).outerHeight() + j_from_box.outerHeight()); }
if (j_from_box.outerHeight() > 0) {
resize_filters(); // This fieldset is already open. Resize now.
} else {
// This fieldset is probably collapsed. Wait for its 'show' event.
j_to_box.closest('fieldset').one('show.fieldset', resize_filters);
}
}
// Initial icon refresh
SelectFilter.refresh_icons(field_id);
},
refresh_icons: function(field_id) {
var from = $('#' + field_id + '_from');
var to = $('#' + field_id + '_to');
var is_from_selected = from.find('option:selected').length > 0;
var is_to_selected = to.find('option:selected').length > 0;
// Active if at least one item is selected
$('#' + field_id + '_add_link').toggleClass('active', is_from_selected);
$('#' + field_id + '_remove_link').toggleClass('active', is_to_selected);
// Active if the corresponding box isn't empty
$('#' + field_id + '_add_all_link').toggleClass('active', from.find('option').length > 0);
$('#' + field_id + '_remove_all_link').toggleClass('active', to.find('option').length > 0);
}, },
filter_key_up: function(event, field_id) { filter_key_up: function(event, field_id) {
from = document.getElementById(field_id + '_from'); var from = document.getElementById(field_id + '_from');
// don't submit form if user pressed Enter // don't submit form if user pressed Enter
if ((event.which && event.which == 13) || (event.keyCode && event.keyCode == 13)) { if ((event.which && event.which == 13) || (event.keyCode && event.keyCode == 13)) {
from.selectedIndex = 0; from.selectedIndex = 0;
...@@ -109,7 +138,7 @@ var SelectFilter = { ...@@ -109,7 +138,7 @@ var SelectFilter = {
return true; return true;
}, },
filter_key_down: function(event, field_id) { filter_key_down: function(event, field_id) {
from = document.getElementById(field_id + '_from'); var from = document.getElementById(field_id + '_from');
// right arrow -- move across // right arrow -- move across
if ((event.which && event.which == 39) || (event.keyCode && event.keyCode == 39)) { if ((event.which && event.which == 39) || (event.keyCode && event.keyCode == 39)) {
var old_index = from.selectedIndex; var old_index = from.selectedIndex;
...@@ -128,3 +157,5 @@ var SelectFilter = { ...@@ -128,3 +157,5 @@ var SelectFilter = {
return true; return true;
} }
} }
})(django.jQuery);
(function(a){a.fn.actions=function(h){var b=a.extend({},a.fn.actions.defaults,h),e=a(this),f=false;checker=function(c){c?showQuestion():reset();a(e).attr("checked",c).parent().parent().toggleClass(b.selectedClass,c)};updateCounter=function(){var c=a(e).filter(":checked").length;a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:_actions_icnt},true));a(b.allToggle).attr("checked",function(){if(c==e.length){value=true;showQuestion()}else{value= (function(a){a.fn.actions=function(g){var b=a.extend({},a.fn.actions.defaults,g),f=a(this),e=!1;checker=function(c){c?showQuestion():reset();a(f).attr("checked",c).parent().parent().toggleClass(b.selectedClass,c)};updateCounter=function(){var c=a(f).filter(":checked").length;a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:_actions_icnt},!0));a(b.allToggle).attr("checked",function(){c==f.length?(value=!0,showQuestion()):(value=
false;clearAcross()}return value})};showQuestion=function(){a(b.acrossClears).hide();a(b.acrossQuestions).show();a(b.allContainer).hide()};showClear=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()};reset=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()};clearAcross=function(){reset();a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)}; !1,clearAcross());return value})};showQuestion=function(){a(b.acrossClears).hide();a(b.acrossQuestions).show();a(b.allContainer).hide()};showClear=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()};reset=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()};clearAcross=function(){reset();a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)};
a(b.counterContainer).show();a(this).filter(":checked").each(function(){a(this).parent().parent().toggleClass(b.selectedClass);updateCounter();a(b.acrossInput).val()==1&&showClear()});a(b.allToggle).show().click(function(){checker(a(this).attr("checked"));updateCounter()});a("div.actions span.question a").click(function(c){c.preventDefault();a(b.acrossInput).val(1);showClear()});a("div.actions span.clear a").click(function(c){c.preventDefault();a(b.allToggle).attr("checked",false);clearAcross();checker(0); a(b.counterContainer).show();a(this).filter(":checked").each(function(){a(this).parent().parent().toggleClass(b.selectedClass);updateCounter();1==a(b.acrossInput).val()&&showClear()});a(b.allToggle).show().click(function(){checker(a(this).attr("checked"));updateCounter()});a("div.actions span.question a").click(function(c){c.preventDefault();a(b.acrossInput).val(1);showClear()});a("div.actions span.clear a").click(function(c){c.preventDefault();a(b.allToggle).attr("checked",!1);clearAcross();checker(0);
updateCounter()});lastChecked=null;a(e).click(function(c){if(!c)c=window.event;var d=c.target?c.target:c.srcElement;if(lastChecked&&a.data(lastChecked)!=a.data(d)&&c.shiftKey==true){var g=false;a(lastChecked).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked);a(e).each(function(){if(a.data(this)==a.data(lastChecked)||a.data(this)==a.data(d))g=g?false:true;g&&a(this).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked)})}a(d).parent().parent().toggleClass(b.selectedClass, updateCounter()});lastChecked=null;a(f).click(function(c){if(!c)c=window.event;var d=c.target?c.target:c.srcElement;if(lastChecked&&a.data(lastChecked)!=a.data(d)&&!0==c.shiftKey){var e=!1;a(lastChecked).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked);a(f).each(function(){if(a.data(this)==a.data(lastChecked)||a.data(this)==a.data(d))e=e?!1:!0;e&&a(this).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked)})}a(d).parent().parent().toggleClass(b.selectedClass,
d.checked);lastChecked=d;updateCounter()});a("form#changelist-form table#result_list tr").find("td:gt(0) :input").change(function(){f=true});a('form#changelist-form button[name="index"]').click(function(){if(f)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))});a('form#changelist-form input[name="_save"]').click(function(){var c=false;a("div.actions select option:selected").each(function(){if(a(this).val())c= d.checked);lastChecked=d;updateCounter()});a("form#changelist-form table#result_list tr").find("td:gt(0) :input").change(function(){e=!0});a('form#changelist-form button[name="index"]').click(function(){if(e)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))});a('form#changelist-form input[name="_save"]').click(function(){var b=!1;a("div.actions select option:selected").each(function(){a(this).val()&&(b=!0)});
true});if(c)return f?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})};a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across", if(b)return e?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})};a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across",
acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"}})(django.jQuery); acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"}})(django.jQuery);
...@@ -50,7 +50,7 @@ var DateTimeShortcuts = { ...@@ -50,7 +50,7 @@ var DateTimeShortcuts = {
var clock_link = document.createElement('a'); var clock_link = document.createElement('a');
clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');'); clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');');
clock_link.id = DateTimeShortcuts.clockLinkName + num; clock_link.id = DateTimeShortcuts.clockLinkName + num;
quickElement('img', clock_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_clock.gif', 'alt', gettext('Clock')); quickElement('img', clock_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/icon_clock.gif', 'alt', gettext('Clock'));
shortcuts_span.appendChild(document.createTextNode('\240')); shortcuts_span.appendChild(document.createTextNode('\240'));
shortcuts_span.appendChild(now_link); shortcuts_span.appendChild(now_link);
shortcuts_span.appendChild(document.createTextNode('\240|\240')); shortcuts_span.appendChild(document.createTextNode('\240|\240'));
...@@ -79,17 +79,24 @@ var DateTimeShortcuts = { ...@@ -79,17 +79,24 @@ var DateTimeShortcuts = {
addEvent(clock_box, 'click', DateTimeShortcuts.cancelEventPropagation); addEvent(clock_box, 'click', DateTimeShortcuts.cancelEventPropagation);
quickElement('h2', clock_box, gettext('Choose a time')); quickElement('h2', clock_box, gettext('Choose a time'));
time_list = quickElement('ul', clock_box, ''); var time_list = quickElement('ul', clock_box, '');
time_list.className = 'timelist'; time_list.className = 'timelist';
time_format = get_format('TIME_INPUT_FORMATS')[0]; var time_format = get_format('TIME_INPUT_FORMATS')[0];
quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + time_format + "'));"); quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + time_format + "'));"); quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + time_format + "'));"); quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + time_format + "'));"); quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + time_format + "'));");
cancel_p = quickElement('p', clock_box, ''); var cancel_p = quickElement('p', clock_box, '');
cancel_p.className = 'calendar-cancel'; cancel_p.className = 'calendar-cancel';
quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissClock(' + num + ');'); quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissClock(' + num + ');');
django.jQuery(document).bind('keyup', function(event) {
if (event.which == 27) {
// ESC key closes popup
DateTimeShortcuts.dismissClock(num);
event.preventDefault();
}
});
}, },
openClock: function(num) { openClock: function(num) {
var clock_box = document.getElementById(DateTimeShortcuts.clockDivName+num) var clock_box = document.getElementById(DateTimeShortcuts.clockDivName+num)
...@@ -138,7 +145,7 @@ var DateTimeShortcuts = { ...@@ -138,7 +145,7 @@ var DateTimeShortcuts = {
var cal_link = document.createElement('a'); var cal_link = document.createElement('a');
cal_link.setAttribute('href', 'javascript:DateTimeShortcuts.openCalendar(' + num + ');'); cal_link.setAttribute('href', 'javascript:DateTimeShortcuts.openCalendar(' + num + ');');
cal_link.id = DateTimeShortcuts.calendarLinkName + num; cal_link.id = DateTimeShortcuts.calendarLinkName + num;
quickElement('img', cal_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/admin/icon_calendar.gif', 'alt', gettext('Calendar')); quickElement('img', cal_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/icon_calendar.gif', 'alt', gettext('Calendar'));
shortcuts_span.appendChild(document.createTextNode('\240')); shortcuts_span.appendChild(document.createTextNode('\240'));
shortcuts_span.appendChild(today_link); shortcuts_span.appendChild(today_link);
shortcuts_span.appendChild(document.createTextNode('\240|\240')); shortcuts_span.appendChild(document.createTextNode('\240|\240'));
...@@ -195,6 +202,13 @@ var DateTimeShortcuts = { ...@@ -195,6 +202,13 @@ var DateTimeShortcuts = {
var cancel_p = quickElement('p', cal_box, ''); var cancel_p = quickElement('p', cal_box, '');
cancel_p.className = 'calendar-cancel'; cancel_p.className = 'calendar-cancel';
quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissCalendar(' + num + ');'); quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissCalendar(' + num + ');');
django.jQuery(document).bind('keyup', function(event) {
if (event.which == 27) {
// ESC key closes popup
DateTimeShortcuts.dismissCalendar(num);
event.preventDefault();
}
});
}, },
openCalendar: function(num) { openCalendar: function(num) {
var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num) var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num)
......
...@@ -74,11 +74,12 @@ function dismissAddAnotherPopup(win, newId, newRepr) { ...@@ -74,11 +74,12 @@ function dismissAddAnotherPopup(win, newId, newRepr) {
var name = windowname_to_id(win.name); var name = windowname_to_id(win.name);
var elem = document.getElementById(name); var elem = document.getElementById(name);
if (elem) { if (elem) {
if (elem.nodeName == 'SELECT') { var elemName = elem.nodeName.toUpperCase();
if (elemName == 'SELECT') {
var o = new Option(newRepr, newId); var o = new Option(newRepr, newId);
elem.options[elem.options.length] = o; elem.options[elem.options.length] = o;
o.selected = true; o.selected = true;
} else if (elem.nodeName == 'INPUT') { } else if (elemName == 'INPUT') {
if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) { if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
elem.value += ',' + newId; elem.value += ',' + newId;
} else { } else {
......
...@@ -11,7 +11,7 @@ function reorder_init() { ...@@ -11,7 +11,7 @@ function reorder_init() {
setOrder(input.value.split(',')); setOrder(input.value.split(','));
input.disabled = true; input.disabled = true;
draw(); draw();
// Now initialise the dragging behaviour // Now initialize the dragging behavior
var limit = (lis.length - 1) * height; var limit = (lis.length - 1) * height;
for (var i = 0; i < lis.length; i++) { for (var i = 0; i < lis.length; i++) {
var li = lis[i]; var li = lis[i];
......
...@@ -3,9 +3,8 @@ ...@@ -3,9 +3,8 @@
// Add anchor tag for Show/Hide link // Add anchor tag for Show/Hide link
$("fieldset.collapse").each(function(i, elem) { $("fieldset.collapse").each(function(i, elem) {
// Don't hide if fields in this fieldset have errors // Don't hide if fields in this fieldset have errors
if ( $(elem).find("div.errors").length == 0 ) { if ($(elem).find("div.errors").length == 0) {
$(elem).addClass("collapsed"); $(elem).addClass("collapsed").find("h2").first().append(' (<a id="fieldsetcollapser' +
$(elem).find("h2").first().append(' (<a id="fieldsetcollapser' +
i +'" class="collapse-toggle" href="#">' + gettext("Show") + i +'" class="collapse-toggle" href="#">' + gettext("Show") +
'</a>)'); '</a>)');
} }
...@@ -13,13 +12,11 @@ ...@@ -13,13 +12,11 @@
// Add toggle to anchor tag // Add toggle to anchor tag
$("fieldset.collapse a.collapse-toggle").toggle( $("fieldset.collapse a.collapse-toggle").toggle(
function() { // Show function() { // Show
$(this).text(gettext("Hide")); $(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset", [$(this).attr("id")]);
$(this).closest("fieldset").removeClass("collapsed");
return false; return false;
}, },
function() { // Hide function() { // Hide
$(this).text(gettext("Show")); $(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", [$(this).attr("id")]);
$(this).closest("fieldset").addClass("collapsed");
return false; return false;
} }
); );
......
(function(a){a(document).ready(function(){a("fieldset.collapse").each(function(c,b){if(a(b).find("div.errors").length==0){a(b).addClass("collapsed");a(b).find("h2").first().append(' (<a id="fieldsetcollapser'+c+'" class="collapse-toggle" href="#">'+gettext("Show")+"</a>)")}});a("fieldset.collapse a.collapse-toggle").toggle(function(){a(this).text(gettext("Hide"));a(this).closest("fieldset").removeClass("collapsed");return false},function(){a(this).text(gettext("Show"));a(this).closest("fieldset").addClass("collapsed"); (function(a){a(document).ready(function(){a("fieldset.collapse").each(function(c,b){0==a(b).find("div.errors").length&&a(b).addClass("collapsed").find("h2").first().append(' (<a id="fieldsetcollapser'+c+'" class="collapse-toggle" href="#">'+gettext("Show")+"</a>)")});a("fieldset.collapse a.collapse-toggle").toggle(function(){a(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset",[a(this).attr("id")]);return!1},function(){a(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset",
return false})})})(django.jQuery); [a(this).attr("id")]);return!1})})})(django.jQuery);
...@@ -108,12 +108,6 @@ function findPosY(obj) { ...@@ -108,12 +108,6 @@ function findPosY(obj) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Date object extensions // Date object extensions
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
Date.prototype.getCorrectYear = function() {
// Date.getYear() is unreliable --
// see http://www.quirksmode.org/js/introdate.html#year
var y = this.getYear() % 100;
return (y < 38) ? y + 2000 : y + 1900;
}
Date.prototype.getTwelveHours = function() { Date.prototype.getTwelveHours = function() {
hours = this.getHours(); hours = this.getHours();
...@@ -149,10 +143,6 @@ Date.prototype.getTwoDigitSecond = function() { ...@@ -149,10 +143,6 @@ Date.prototype.getTwoDigitSecond = function() {
return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds(); return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds();
} }
Date.prototype.getISODate = function() {
return this.getCorrectYear() + '-' + this.getTwoDigitMonth() + '-' + this.getTwoDigitDate();
}
Date.prototype.getHourMinute = function() { Date.prototype.getHourMinute = function() {
return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute(); return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute();
} }
......
(function(b){b.fn.formset=function(g){var a=b.extend({},b.fn.formset.defaults,g),k=function(c,f,d){var e=new RegExp("("+f+"-(\\d+|__prefix__))");f=f+"-"+d;b(c).attr("for")&&b(c).attr("for",b(c).attr("for").replace(e,f));if(c.id)c.id=c.id.replace(e,f);if(c.name)c.name=c.name.replace(e,f)};g=b("#id_"+a.prefix+"-TOTAL_FORMS").attr("autocomplete","off");var l=parseInt(g.val()),h=b("#id_"+a.prefix+"-MAX_NUM_FORMS").attr("autocomplete","off");g=h.val()==""||h.val()-g.val()>0;b(this).each(function(){b(this).not("."+ (function(b){b.fn.formset=function(c){var a=b.extend({},b.fn.formset.defaults,c),j=function(a,e,d){var i=RegExp("("+e+"-(\\d+|__prefix__))"),e=e+"-"+d;b(a).attr("for")&&b(a).attr("for",b(a).attr("for").replace(i,e));if(a.id)a.id=a.id.replace(i,e);if(a.name)a.name=a.name.replace(i,e)},c=b("#id_"+a.prefix+"-TOTAL_FORMS").attr("autocomplete","off"),g=parseInt(c.val()),f=b("#id_"+a.prefix+"-MAX_NUM_FORMS").attr("autocomplete","off"),c=""==f.val()||0<f.val()-c.val();b(this).each(function(){b(this).not("."+
a.emptyCssClass).addClass(a.formCssClass)});if(b(this).length&&g){var j;if(b(this).attr("tagName")=="TR"){g=this.eq(0).children().length;b(this).parent().append('<tr class="'+a.addCssClass+'"><td colspan="'+g+'"><a href="javascript:void(0)">'+a.addText+"</a></tr>");j=b(this).parent().find("tr:last a")}else{b(this).filter(":last").after('<div class="'+a.addCssClass+'"><a href="javascript:void(0)">'+a.addText+"</a></div>");j=b(this).filter(":last").next().find("a")}j.click(function(){var c=b("#id_"+ a.emptyCssClass).addClass(a.formCssClass)});if(b(this).length&&c){var h;"TR"==b(this).attr("tagName")?(c=this.eq(0).children().length,b(this).parent().append('<tr class="'+a.addCssClass+'"><td colspan="'+c+'"><a href="javascript:void(0)">'+a.addText+"</a></tr>"),h=b(this).parent().find("tr:last a")):(b(this).filter(":last").after('<div class="'+a.addCssClass+'"><a href="javascript:void(0)">'+a.addText+"</a></div>"),h=b(this).filter(":last").next().find("a"));h.click(function(){var c=b("#id_"+a.prefix+
a.prefix+"-TOTAL_FORMS"),f=b("#"+a.prefix+"-empty"),d=f.clone(true);d.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+l);if(d.is("tr"))d.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></div>");else d.is("ul")||d.is("ol")?d.append('<li><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></li>"):d.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+ "-TOTAL_FORMS"),e=b("#"+a.prefix+"-empty"),d=e.clone(!0);d.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+g);d.is("tr")?d.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></div>"):d.is("ul")||d.is("ol")?d.append('<li><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></li>"):d.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+
a.deleteText+"</a></span>");d.find("*").each(function(){k(this,a.prefix,c.val())});d.insertBefore(b(f));b(c).val(parseInt(c.val())+1);l+=1;h.val()!=""&&h.val()-c.val()<=0&&j.parent().hide();d.find("a."+a.deleteCssClass).click(function(){var e=b(this).parents("."+a.formCssClass);e.remove();l-=1;a.removed&&a.removed(e);e=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(e.length);if(h.val()==""||h.val()-e.length>0)j.parent().show();for(var i=0,m=e.length;i<m;i++){k(b(e).get(i),a.prefix,i); "</a></span>");d.find("*").each(function(){j(this,a.prefix,c.val())});d.insertBefore(b(e));b(c).val(parseInt(c.val())+1);g+=1;""!=f.val()&&0>=f.val()-c.val()&&h.parent().hide();d.find("a."+a.deleteCssClass).click(function(){var c=b(this).parents("."+a.formCssClass);c.remove();g-=1;a.removed&&a.removed(c);c=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(c.length);(""==f.val()||0<f.val()-c.length)&&h.parent().show();for(var d=0,e=c.length;d<e;d++)j(b(c).get(d),a.prefix,d),b(c.get(d)).find("*").each(function(){j(this,
b(e.get(i)).find("*").each(function(){k(this,a.prefix,i)})}return false});a.added&&a.added(d);return false})}return this};b.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null}})(django.jQuery); a.prefix,d)});return!1});a.added&&a.added(d);return!1})}return this};b.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null}})(django.jQuery);
// Puts the included jQuery into our own namespace /* Puts the included jQuery into our own namespace using noConflict and passing
* it 'true'. This ensures that the included jQuery doesn't pollute the global
* namespace (i.e. this preserves pre-existing values for both window.$ and
* window.jQuery).
*/
var django = { var django = {
"jQuery": jQuery.noConflict(true) "jQuery": jQuery.noConflict(true)
}; };
(function(a){a.fn.prepopulate=function(d,g){return this.each(function(){var b=a(this);b.data("_changed",false);b.change(function(){b.data("_changed",true)});var c=function(){if(b.data("_changed")!=true){var e=[];a.each(d,function(h,f){a(f).val().length>0&&e.push(a(f).val())});b.val(URLify(e.join(" "),g))}};a(d.join(",")).keyup(c).change(c).focus(c)})}})(django.jQuery); (function(a){a.fn.prepopulate=function(d,e){return this.each(function(){var b=a(this);b.data("_changed",!1);b.change(function(){b.data("_changed",!0)});var c=function(){if(!0!=b.data("_changed")){var c=[];a.each(d,function(b,d){0<a(d).val().length&&c.push(a(d).val())});b.val(URLify(c.join(" "),e))}};a(d.join(",")).keyup(c).change(c).focus(c)})}})(django.jQuery);
...@@ -42,11 +42,15 @@ ...@@ -42,11 +42,15 @@
<a href="${reverse('about_edx')}">About</a> <a href="${reverse('about_edx')}">About</a>
<a href="http://edxonline.tumblr.com/">Blog</a> <a href="http://edxonline.tumblr.com/">Blog</a>
<a href="${reverse('jobs')}">Jobs</a> <a href="${reverse('jobs')}">Jobs</a>
% if not settings.MITX_FEATURES['DISABLE_LOGIN_BUTTON']:
<a href="#login-modal" id="login" rel="leanModal">Log In</a> <a href="#login-modal" id="login" rel="leanModal">Log In</a>
% endif
</li> </li>
% if not settings.MITX_FEATURES['DISABLE_LOGIN_BUTTON']:
<li class="primary"> <li class="primary">
<a href="#signup-modal" id="signup" rel="leanModal">Sign Up</a> <a href="#signup-modal" id="signup" rel="leanModal">Sign Up</a>
</li> </li>
% endif
</ol> </ol>
</nav> </nav>
%endif %endif
......
${module_content} ${module_content}
%if edit_link: %if edit_link:
<div><a href="${edit_link}">Edit</a></div> <div><a href="${edit_link}">Edit</a> / <a href="#${element_id}_xqa-modal" onclick="getlog_${element_id}()" id="${element_id}_xqa_log">QA</a></div>
% endif % endif
<div><a href="javascript:void(0)" onclick="javascript:$('#${element_id}_debug').slideToggle()">Staff Debug Info</a></div> <div><a href="#${element_id}_debug" id="${element_id}_trig">Staff Debug Info</a></div>
<span style="display:none" id="${element_id}_debug"> <section id="${element_id}_xqa-modal" class="modal xqa-modal" style="width:80%; left:20%; height:80%; overflow:auto" >
<div class="staff_info"> <div class="inner-wrapper">
<header>
<h2>edX Content Quality Assessment</h2>
</header>
<form id="${element_id}_xqa_form" class="xqa_form">
<label>Comment</label>
<input id="${element_id}_xqa_entry" type="text" placeholder="comment">
<label>Tag</label>
<span style="color:black;vertical-align: -10pt">Optional tag (eg "done" or "broken"):&nbsp; </span>
<input id="${element_id}_xqa_tag" type="text" placeholder="tag" style="width:80px;display:inline">
<div class="submit">
<button name="submit" type="submit">Add comment</button>
</div>
<hr>
<div id="${element_id}_xqa_log_data"></div>
</form>
</div>
</section>
<section class="modal staff-modal" id="${element_id}_debug" style="width:80%; left:20%; height:80%; overflow:auto;" >
<div class="inner-wrapper" style="color:black">
<header>
<h2>Staff Debug</h2>
</header>
<div class="staff_info">
location = ${location | h}
github = <a href="${edit_link}">${edit_link | h}</a>
definition = <pre>${definition | h}</pre> definition = <pre>${definition | h}</pre>
metadata = ${metadata | h} metadata = ${metadata | h}
</div> category = ${category | h}
%if render_histogram: </div>
<div id="histogram_${element_id}" class="histogram" data-histogram="${histogram}"></div> %if render_histogram:
%endif <div id="histogram_${element_id}" class="histogram" data-histogram="${histogram}"></div>
</span> %endif
</div>
</section>
<div id="${element_id}_setup"></div>
## leanModal needs to be included here otherwise this breaks when in a <vertical>
<script type="text/javascript" src="/static/js/vendor/jquery.leanModal.min.js"></script>
<script type="text/javascript">
function setup_debug_${element_id}(){
$('#${element_id}_trig').leanModal();
$('#${element_id}_xqa_log').leanModal();
$('#${element_id}_xqa_form').submit(sendlog_${element_id});
}
setup_debug_${element_id}();
function sendlog_${element_id}(){
var xqaLog = {authkey: '${xqa_key}',
location: '${location}',
%if edit_link:
giturl: '${edit_link}',
%endif
category : '${category}',
username : '${user.username}',
return : 'query',
format : 'html',
email : '${user.email}',
tag:$('#${element_id}_xqa_tag').val(),
entry: $('#${element_id}_xqa_entry').val()};
$.ajax({
url: '${xqa_server}/log',
type: 'GET',
contentType: 'application/json',
data: JSON.stringify(xqaLog),
crossDomain: true,
dataType: 'jsonp',
beforeSend: function (xhr) { xhr.setRequestHeader ("Authorization", "Basic eHFhOmFnYXJ3YWw="); },
timeout : 1000,
success: function(result) {
$('#${element_id}_xqa_log_data').html(result);
},
error: function() {
alert('Error: cannot connect to XQA server');
console.log('error!');
}
});
return false;
};
function getlog_${element_id}(){
var xqaQuery = {authkey: '${xqa_key}',
location: '${location}',
format: 'html'};
$.ajax({
url: '${xqa_server}/query',
type: 'GET',
contentType: 'application/json',
data: JSON.stringify(xqaQuery),
crossDomain: true,
dataType: 'jsonp',
timeout : 1000,
success: function(result) {
$('#${element_id}_xqa_log_data').html(result);
},
error: function() {
alert('Error: cannot connect to XQA server');
}
});
};
</script>
...@@ -18,6 +18,7 @@ except Exception as err: ...@@ -18,6 +18,7 @@ except Exception as err:
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User, Group from django.contrib.auth.models import User, Group
from path import path from path import path
from lxml import etree
data_dir = settings.DATA_DIR data_dir = settings.DATA_DIR
print "data_dir = %s" % data_dir print "data_dir = %s" % data_dir
...@@ -26,7 +27,17 @@ for course_dir in os.listdir(data_dir): ...@@ -26,7 +27,17 @@ for course_dir in os.listdir(data_dir):
# print course_dir # print course_dir
if not os.path.isdir(path(data_dir) / course_dir): if not os.path.isdir(path(data_dir) / course_dir):
continue continue
gname = 'staff_%s' % course_dir
cxfn = path(data_dir) / course_dir / 'course.xml'
coursexml = etree.parse(cxfn)
cxmlroot = coursexml.getroot()
course = cxmlroot.get('course')
if course is None:
print "oops, can't get course id for %s" % course_dir
continue
print "course=%s for course_dir=%s" % (course,course_dir)
gname = 'staff_%s' % course
if Group.objects.filter(name=gname): if Group.objects.filter(name=gname):
print "group exists for %s" % gname print "group exists for %s" % gname
continue continue
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment