diff --git a/.github/workflows/check-consistent-dependencies.yml b/.github/workflows/check-consistent-dependencies.yml
index cef731a7d175..a84ef40bbcab 100644
--- a/.github/workflows/check-consistent-dependencies.yml
+++ b/.github/workflows/check-consistent-dependencies.yml
@@ -46,7 +46,7 @@ jobs:
- uses: actions/setup-python@v6
if: ${{ env.RELEVANT == 'true' }}
with:
- python-version: '3.11'
+ python-version: '3.12'
- name: "Recompile requirements"
if: ${{ env.RELEVANT == 'true' }}
diff --git a/.github/workflows/ci-static-analysis.yml b/.github/workflows/ci-static-analysis.yml
index a5ab117acdfc..94fb9e863d87 100644
--- a/.github/workflows/ci-static-analysis.yml
+++ b/.github/workflows/ci-static-analysis.yml
@@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
python-version:
- - "3.11"
+ - "3.12"
os: ["ubuntu-24.04"]
steps:
diff --git a/.github/workflows/compile-python-requirements.yml b/.github/workflows/compile-python-requirements.yml
index 1da50b9b6bdd..fe8fdc6ff542 100644
--- a/.github/workflows/compile-python-requirements.yml
+++ b/.github/workflows/compile-python-requirements.yml
@@ -26,7 +26,7 @@ jobs:
- name: Set up Python environment
uses: actions/setup-python@v6
with:
- python-version: "3.11"
+ python-version: "3.12"
- name: Run make compile-requirements
env:
diff --git a/.github/workflows/js-tests.yml b/.github/workflows/js-tests.yml
index 69e487e06ac4..dd21d12e3d25 100644
--- a/.github/workflows/js-tests.yml
+++ b/.github/workflows/js-tests.yml
@@ -16,7 +16,7 @@ jobs:
os: [ubuntu-latest]
node-version: [20]
python-version:
- - "3.11"
+ - "3.12"
steps:
- uses: actions/checkout@v6
diff --git a/.github/workflows/lint-imports.yml b/.github/workflows/lint-imports.yml
index 2debc4cb1028..8b119d31e6b5 100644
--- a/.github/workflows/lint-imports.yml
+++ b/.github/workflows/lint-imports.yml
@@ -19,7 +19,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
- python-version: "3.11"
+ python-version: "3.12"
- name: Install system requirements
run: sudo apt update && sudo apt install -y libxmlsec1-dev
diff --git a/.github/workflows/migrations-check.yml b/.github/workflows/migrations-check.yml
index c63b5ef02fba..20540fb43906 100644
--- a/.github/workflows/migrations-check.yml
+++ b/.github/workflows/migrations-check.yml
@@ -16,7 +16,7 @@ jobs:
matrix:
os: [ubuntu-24.04]
python-version:
- - "3.11"
+ - "3.12"
# 'pinned' is used to install the latest patch version of Django
# within the global constraint i.e. Django==4.2.8 in current case
# because we have global constraint of Django<4.2
diff --git a/.github/workflows/pylint-checks.yml b/.github/workflows/pylint-checks.yml
index 03160b77a7e4..21d4421b0950 100644
--- a/.github/workflows/pylint-checks.yml
+++ b/.github/workflows/pylint-checks.yml
@@ -40,7 +40,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
- python-version: 3.11
+ python-version: 3.12
- name: Get pip cache dir
id: pip-cache-dir
diff --git a/.github/workflows/quality-checks.yml b/.github/workflows/quality-checks.yml
index 77f094ba3d8d..b57b713eb93a 100644
--- a/.github/workflows/quality-checks.yml
+++ b/.github/workflows/quality-checks.yml
@@ -16,7 +16,7 @@ jobs:
matrix:
os: [ubuntu-24.04]
python-version:
- - "3.11"
+ - "3.12"
node-version: [20]
steps:
diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml
index 557ba0227c5d..c201f30aa799 100644
--- a/.github/workflows/semgrep.yml
+++ b/.github/workflows/semgrep.yml
@@ -20,7 +20,7 @@ jobs:
matrix:
os: ["ubuntu-latest"]
python-version:
- - "3.11"
+ - "3.12"
steps:
- uses: actions/checkout@v6
diff --git a/.github/workflows/static-assets-check.yml b/.github/workflows/static-assets-check.yml
index 8e83a9a46ce1..41159e3526c5 100644
--- a/.github/workflows/static-assets-check.yml
+++ b/.github/workflows/static-assets-check.yml
@@ -15,7 +15,7 @@ jobs:
matrix:
os: [ubuntu-24.04]
python-version:
- - "3.11"
+ - "3.12"
node-version: [20]
npm-version: [10.7.x]
mongo-version:
@@ -71,6 +71,13 @@ jobs:
- name: Install Limited Python Deps for Build
run: |
+ # Install pip-tools.txt first to pin setuptools<82 before installing
+ # assets.txt. setuptools 82+ removed pkg_resources, which pyfilesystem2
+ # (fs) still uses for namespace package declarations. The constraints.txt
+ # pin covers full installs, but this step only installs assets.txt so we
+ # pre-install pip-tools.txt to ensure setuptools 81.x is in place.
+ # See: https://github.com/PyFilesystem/pyfilesystem2/issues/577
+ pip install -r requirements/pip-tools.txt
pip install -r requirements/edx/assets.txt
- name: Add node_modules bin to $Path
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index 58cd39a80868..7b7b14a43e88 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -22,7 +22,6 @@ jobs:
strategy:
matrix:
python-version:
- - "3.11"
- "3.12"
django-version:
- "pinned"
@@ -57,18 +56,18 @@ jobs:
#
# We're testing the older version of Ubuntu and running the xmodule tests since those rely on many
# dependent complex libraries and will hopefully catch most issues quickly.
- include:
- - shard_name: "xmodule-with-cms"
- python-version: "3.11"
- django-version: "pinned"
- mongo-version: "7.0"
- os-version: "ubuntu-22.04"
- - shard_name: "xmodule-with-lms"
- python-version: "3.11"
- django-version: "pinned"
- mongo-version: "7.0"
- os-version: "ubuntu-22.04"
-
+ #
+ # include:
+ # - shard_name: "xmodule-with-cms"
+ # python-version: "3.12"
+ # django-version: "pinned"
+ # mongo-version: "7.0"
+ # os-version: "ubuntu-24.04"
+ # - shard_name: "xmodule-with-lms"
+ # python-version: "3.12"
+ # django-version: "pinned"
+ # mongo-version: "7.0"
+ # os-version: "ubuntu-24.04"
steps:
- name: checkout repo
uses: actions/checkout@v6
@@ -156,7 +155,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v6
with:
- python-version: 3.11
+ python-version: 3.12
- name: install system requirements
run: |
@@ -278,7 +277,7 @@ jobs:
strategy:
matrix:
python-version:
- - 3.11
+ - 3.12
steps:
- name: Checkout repo
uses: actions/checkout@v6
diff --git a/.github/workflows/upgrade-one-python-dependency.yml b/.github/workflows/upgrade-one-python-dependency.yml
index 36a6b361887f..fc4610baf49d 100644
--- a/.github/workflows/upgrade-one-python-dependency.yml
+++ b/.github/workflows/upgrade-one-python-dependency.yml
@@ -39,7 +39,7 @@ jobs:
- name: Set up Python environment
uses: actions/setup-python@v6
with:
- python-version: "3.11"
+ python-version: "3.12"
- name: Update any pinned dependencies
env:
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index efd38bc796ac..fef9e3c2a9d2 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -3,7 +3,7 @@ version: 2
build:
os: "ubuntu-lts-latest"
tools:
- python: "3.11"
+ python: "3.12"
sphinx:
configuration: docs/conf.py
diff --git a/README.rst b/README.rst
index b315cdcbf2b6..8a09c9a603b5 100644
--- a/README.rst
+++ b/README.rst
@@ -78,7 +78,7 @@ OS:
Interpreters/Tools:
-* Python 3.11 or 3.12
+* Python 3.12
* Node: See the ``.nvmrc`` file in this repository.
diff --git a/cms/djangoapps/contentstore/rest_api/v2/views/utils.py b/cms/djangoapps/contentstore/rest_api/v2/views/utils.py
index 8a6fe461fdb7..740608c6ae77 100644
--- a/cms/djangoapps/contentstore/rest_api/v2/views/utils.py
+++ b/cms/djangoapps/contentstore/rest_api/v2/views/utils.py
@@ -5,7 +5,7 @@
from rest_framework.generics import GenericAPIView
from rest_framework import permissions
from cms.djangoapps.contentstore.rest_api.v2.serializers.utils import NumericalInputValidationRequestSerializer
-from xmodule.capa.inputtypes import preview_numeric_input
+from xblocks_contrib.problem.capa.inputtypes import preview_numeric_input
class NumericalInputValidationView(GenericAPIView):
diff --git a/cms/envs/common.py b/cms/envs/common.py
index f4f6fd8b9c9d..f7f690236c39 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -289,7 +289,6 @@
MAKO_TEMPLATE_DIRS_BASE.insert(3, COMMON_ROOT / 'static')
MAKO_TEMPLATE_DIRS_BASE.append(CMS_ROOT / 'djangoapps' / 'pipeline_js' / 'templates')
-MAKO_TEMPLATE_DIRS_BASE.append(XMODULE_ROOT / 'capa' / 'templates')
def make_lms_template_path(settings):
@@ -787,6 +786,9 @@ def make_lms_template_path(settings):
'common.djangoapps.xblock_django',
+ # Agreements
+ 'openedx.core.djangoapps.agreements',
+
# Catalog integration
'openedx.core.djangoapps.catalog',
@@ -907,6 +909,9 @@ def make_lms_template_path(settings):
'openedx_events',
+ # Core models to represent courses
+ "openedx_catalog",
+
# Core apps that power libraries
"openedx_content",
*openedx_content_backcompat_apps_to_install(),
diff --git a/cms/envs/devstack.py b/cms/envs/devstack.py
index 7eae8a892ab9..23f0c17cc531 100644
--- a/cms/envs/devstack.py
+++ b/cms/envs/devstack.py
@@ -344,9 +344,11 @@ def should_show_debug_toolbar(request): # lint-amnesty, pylint: disable=missing
access token endpoint: `{LMS_ROOT_URL}/oauth2/access_token`.
Please see separately provided documentation.
\n - How to test: You must be logged in as course author for whatever course you want to test with.
- You can use the [Swagger UI](https://{CMS_BASE}/authoring-api/ui/) to "Try out" the API with your test course. To do this, you must select the "Local" server.
+ You can use the [Swagger UI](https://{CMS_BASE}/authoring-api/ui/) to "Try out" the API
+ with your test course. To do this, you must select the "Local" server.
\n - Public vs. Local servers: The "Public" server is where you can reach the API externally. The "Local" server is
- for development with a local edx-platform version, and for use via the [Swagger UI](https://{CMS_BASE}/authoring-api/ui/).
+ for development with a local edx-platform version, and for use via the
+ [Swagger UI](https://{CMS_BASE}/authoring-api/ui/).
\n - Swaggerfile: [Download link](https://{CMS_BASE}/authoring-api/schema/)''',
'VERSION': '0.1.0',
'SERVE_INCLUDE_SCHEMA': False,
diff --git a/cms/envs/production.py b/cms/envs/production.py
index 95f88ed23ad2..c5ce5d9f5544 100644
--- a/cms/envs/production.py
+++ b/cms/envs/production.py
@@ -409,9 +409,11 @@ def get_env_setting(setting):
access token endpoint: `{LMS_ROOT_URL}/oauth2/access_token`.
Please see separately provided documentation.
\n - How to test: You must be logged in as course author for whatever course you want to test with.
- You can use the [Swagger UI](https://{CMS_BASE}/authoring-api/ui/) to "Try out" the API with your test course. To do this, you must select the "Local" server.
+ You can use the [Swagger UI](https://{CMS_BASE}/authoring-api/ui/) to "Try out" the API
+ with your test course. To do this, you must select the "Local" server.
\n - Public vs. Local servers: The "Public" server is where you can reach the API externally. The "Local" server is
- for development with a local edx-platform version, and for use via the [Swagger UI](https://{CMS_BASE}/authoring-api/ui/).
+ for development with a local edx-platform version, and for use via the
+ [Swagger UI](https://{CMS_BASE}/authoring-api/ui/).
\n - Swaggerfile: [Download link](https://{CMS_BASE}/authoring-api/schema/)''',
'VERSION': '0.1.0',
'SERVE_INCLUDE_SCHEMA': False,
diff --git a/common/djangoapps/edxmako/services.py b/common/djangoapps/edxmako/services.py
index d300e32cf75a..f3fb5bfe7ce1 100644
--- a/common/djangoapps/edxmako/services.py
+++ b/common/djangoapps/edxmako/services.py
@@ -54,7 +54,6 @@ def render_lms_template(self, template_file, dictionary):
Templates which are in these dirs will only work with this function:
edx-platform/lms/templates/
- edx-platform/xmodule/capa/templates/
openedx/features/course_experience/templates
"""
return render_to_string(template_file, dictionary, namespace=lms_mako_namespace)
diff --git a/common/djangoapps/student/roles.py b/common/djangoapps/student/roles.py
index 40e4ebe970eb..3ae766dffc89 100644
--- a/common/djangoapps/student/roles.py
+++ b/common/djangoapps/student/roles.py
@@ -16,6 +16,7 @@
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locator import CourseLocator
from openedx_authz.api import users as authz_api
+from openedx_authz.api.data import RoleAssignmentData, CourseOverviewData
from openedx_authz.constants import roles as authz_roles
from common.djangoapps.student.models import CourseAccessRole
@@ -73,6 +74,24 @@ def authz_add_role(user: User, authz_role: str, course_key: str):
legacy_role = get_legacy_role_from_authz_role(authz_role)
emit_course_access_role_added(user, course_locator, course_locator.org, legacy_role)
+def authz_get_all_course_assignments_for_user(user: User) -> list[RoleAssignmentData]:
+ """
+ Get all course assignments for a user.
+ """
+ assignments = authz_api.get_user_role_assignments(user_external_key=user.username)
+ # filter courses only
+ filtered_assignments = [
+ assignment for assignment in assignments
+ if isinstance(assignment.scope, CourseOverviewData)
+ ]
+ return filtered_assignments
+
+def get_org_from_key(key: str) -> str:
+ """
+ Get the org from a course key.
+ """
+ parsed_key = CourseKey.from_string(key)
+ return parsed_key.org
def register_access_role(cls):
"""
@@ -136,13 +155,12 @@ def get_authz_compat_course_access_roles_for_user(user: User) -> set[AuthzCompat
Retrieve all CourseAccessRole objects for a given user and convert them to AuthzCompatCourseAccessRole objects.
"""
compat_role_assignments = set()
- assignments = authz_api.get_user_role_assignments(user_external_key=user.username)
+ assignments = authz_get_all_course_assignments_for_user(user)
for assignment in assignments:
for role in assignment.roles:
legacy_role = get_legacy_role_from_authz_role(authz_role=role.external_key)
course_key = assignment.scope.external_key
- parsed_key = CourseKey.from_string(course_key)
- org = parsed_key.org
+ org = get_org_from_key(course_key)
compat_role = AuthzCompatCourseAccessRole(
user_id=user.id,
username=user.username,
@@ -825,9 +843,7 @@ def courses_with_role(self) -> set[AuthzCompatCourseAccessRole]:
# Get all assignments for a user to a role
new_authz_roles = [get_authz_role_from_legacy_role(role) for role in roles]
- all_authz_user_assignments = authz_api.get_user_role_assignments(
- user_external_key=self.user.username
- )
+ all_authz_user_assignments = authz_get_all_course_assignments_for_user(self.user)
all_assignments = set()
@@ -847,8 +863,7 @@ def courses_with_role(self) -> set[AuthzCompatCourseAccessRole]:
continue
legacy_role = get_legacy_role_from_authz_role(authz_role=role.external_key)
course_key = assignment.scope.external_key
- parsed_key = CourseKey.from_string(course_key)
- org = parsed_key.org
+ org = get_org_from_key(course_key)
all_assignments.add(AuthzCompatCourseAccessRole(
user_id=self.user.id,
username=self.user.username,
@@ -880,9 +895,7 @@ def has_courses_with_role(self, org: str | None = None) -> bool:
# Then check for authz assignments
new_authz_roles = [get_authz_role_from_legacy_role(role) for role in roles]
- all_authz_user_assignments = authz_api.get_user_role_assignments(
- user_external_key=self.user.username
- )
+ all_authz_user_assignments = authz_get_all_course_assignments_for_user(self.user)
for assignment in all_authz_user_assignments:
for role in assignment.roles:
@@ -892,7 +905,7 @@ def has_courses_with_role(self, org: str | None = None) -> bool:
# There is at least one assignment, short circuit
return True
course_key = assignment.scope.external_key
- parsed_key = CourseKey.from_string(course_key)
- if org == parsed_key.org:
+ parsed_org = get_org_from_key(course_key)
+ if org == parsed_org:
return True
return False
diff --git a/common/djangoapps/student/tests/test_roles.py b/common/djangoapps/student/tests/test_roles.py
index 48e4e36ed0ea..9485a7ca84d1 100644
--- a/common/djangoapps/student/tests/test_roles.py
+++ b/common/djangoapps/student/tests/test_roles.py
@@ -4,6 +4,7 @@
import ddt
+from unittest.mock import patch
from django.contrib.auth.models import Permission
from django.test import TestCase
from edx_toggles.toggles.testutils import override_waffle_flag
@@ -11,6 +12,7 @@
from opaque_keys.edx.locator import LibraryLocator
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
+from openedx_authz.api.data import ContentLibraryData, RoleAssignmentData, RoleData, UserData
from openedx_authz.engine.enforcer import AuthzEnforcer
from common.djangoapps.student.admin import CourseAccessRoleHistoryAdmin
@@ -32,6 +34,7 @@
OrgInstructorRole,
OrgStaffRole,
RoleCache,
+ get_authz_compat_course_access_roles_for_user,
get_role_cache_key_for_course,
ROLE_CACHE_UNGROUPED_ROLES__KEY
)
@@ -236,6 +239,23 @@ def test_get_orgs_for_user(self):
role_second_org.add_users(self.student)
assert len(role.get_orgs_for_user(self.student)) == 2
+ def test_get_authz_compat_course_access_roles_for_user(self):
+ """
+ Thest that get_authz_compat_course_access_roles_for_user doesn't crash when the user
+ has Libraries V2 or other non-course roles in their assignments.
+ """
+ lib_assignment = RoleAssignmentData(
+ subject=UserData(external_key=self.student.username),
+ roles=[RoleData(external_key='test-role')],
+ scope=ContentLibraryData(external_key='lib:edX:test-lib'),
+ )
+ with patch(
+ 'openedx_authz.api.users.get_subject_role_assignments',
+ return_value=[lib_assignment],
+ ):
+ result = get_authz_compat_course_access_roles_for_user(self.student)
+ assert result == set()
+
@ddt.ddt
class RoleCacheTestCase(TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
diff --git a/common/djangoapps/third_party_auth/apps.py b/common/djangoapps/third_party_auth/apps.py
index 7f6b82cfde1f..e9d129962d84 100644
--- a/common/djangoapps/third_party_auth/apps.py
+++ b/common/djangoapps/third_party_auth/apps.py
@@ -12,15 +12,11 @@ def ready(self):
# Import signal handlers to register them
from .signals import handlers # noqa: F401 pylint: disable=unused-import
- # To override the settings before loading social_django.
- if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH', False):
- self._enable_third_party_auth()
-
- def _enable_third_party_auth(self):
- """
- Enable the use of third_party_auth, which allows users to sign in to edX
- using other identity providers. For configuration details, see
- common/djangoapps/third_party_auth/settings.py.
- """
- from common.djangoapps.third_party_auth import settings as auth_settings
- auth_settings.apply_settings(settings)
+ # Note: Third-party auth settings are now defined statically in lms/envs/common.py
+ # However, the enterprise pipeline step must be inserted dynamically because
+ # it requires checking if enterprise is enabled, which can't be done at
+ # settings load time.
+ # Only insert enterprise elements if SOCIAL_AUTH_PIPELINE exists (LMS only, not CMS).
+ if hasattr(settings, 'SOCIAL_AUTH_PIPELINE'):
+ from openedx.features.enterprise_support.api import insert_enterprise_pipeline_elements
+ insert_enterprise_pipeline_elements(settings.SOCIAL_AUTH_PIPELINE)
diff --git a/common/djangoapps/third_party_auth/settings.py b/common/djangoapps/third_party_auth/settings.py
deleted file mode 100644
index 0aeb94fbd498..000000000000
--- a/common/djangoapps/third_party_auth/settings.py
+++ /dev/null
@@ -1,107 +0,0 @@
-"""Settings for the third-party auth module.
-
-The flow for settings registration is:
-
-The base settings file contains a boolean, ENABLE_THIRD_PARTY_AUTH, indicating
-whether this module is enabled. startup.py probes the ENABLE_THIRD_PARTY_AUTH.
-If true, it:
-
- a) loads this module.
- b) calls apply_settings(), passing in the Django settings
-"""
-
-
-from django.conf import settings
-from openedx.features.enterprise_support.api import insert_enterprise_pipeline_elements
-
-
-def apply_settings(django_settings):
- """Set provider-independent settings."""
-
- # Whitelisted URL query parameters retrained in the pipeline session.
- # Params not in this whitelist will be silently dropped.
- django_settings.FIELDS_STORED_IN_SESSION = ['auth_entry', 'next']
-
- # Inject exception middleware to make redirects fire.
- django_settings.MIDDLEWARE.extend(
- ['common.djangoapps.third_party_auth.middleware.ExceptionMiddleware']
- )
-
- # Where to send the user if there's an error during social authentication
- # and we cannot send them to a more specific URL
- # (see middleware.ExceptionMiddleware).
- django_settings.SOCIAL_AUTH_LOGIN_ERROR_URL = '/'
-
- # Where to send the user once social authentication is successful.
- django_settings.SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/dashboard'
-
- # Disable sanitizing of redirect urls in social-auth since the platform
- # already does its own sanitization via the LOGIN_REDIRECT_WHITELIST setting.
- django_settings.SOCIAL_AUTH_SANITIZE_REDIRECTS = False
-
- # Adding extra key value pair in the url query string for microsoft as per request
- django_settings.SOCIAL_AUTH_AZUREAD_OAUTH2_AUTH_EXTRA_ARGUMENTS = {'msafed': 0}
-
- # Avoid default username check to allow non-ascii characters
- django_settings.SOCIAL_AUTH_CLEAN_USERNAMES = not settings.FEATURES.get("ENABLE_UNICODE_USERNAME")
-
- # Inject our customized auth pipeline. All auth backends must work with
- # this pipeline.
- django_settings.SOCIAL_AUTH_PIPELINE = [
- 'common.djangoapps.third_party_auth.pipeline.parse_query_params',
- 'social_core.pipeline.social_auth.social_details',
- 'social_core.pipeline.social_auth.social_uid',
- 'social_core.pipeline.social_auth.auth_allowed',
- 'social_core.pipeline.social_auth.social_user',
- 'common.djangoapps.third_party_auth.pipeline.associate_by_email_if_login_api',
- 'common.djangoapps.third_party_auth.pipeline.associate_by_email_if_saml',
- 'common.djangoapps.third_party_auth.pipeline.associate_by_email_if_oauth',
- 'common.djangoapps.third_party_auth.pipeline.get_username',
- 'common.djangoapps.third_party_auth.pipeline.set_pipeline_timeout',
- 'common.djangoapps.third_party_auth.pipeline.ensure_user_information',
- 'social_core.pipeline.user.create_user',
- 'social_core.pipeline.social_auth.associate_user',
- 'social_core.pipeline.social_auth.load_extra_data',
- 'social_core.pipeline.user.user_details',
- 'common.djangoapps.third_party_auth.pipeline.user_details_force_sync',
- 'common.djangoapps.third_party_auth.pipeline.set_id_verification_status',
- 'common.djangoapps.third_party_auth.pipeline.set_logged_in_cookies',
- 'common.djangoapps.third_party_auth.pipeline.login_analytics',
- 'common.djangoapps.third_party_auth.pipeline.ensure_redirect_url_is_safe',
- ]
-
- # Add enterprise pipeline elements if the enterprise app is installed
- insert_enterprise_pipeline_elements(django_settings.SOCIAL_AUTH_PIPELINE)
-
- # Required so that we can use unmodified PSA OAuth2 backends:
- django_settings.SOCIAL_AUTH_STRATEGY = 'common.djangoapps.third_party_auth.strategy.ConfigurationModelStrategy'
-
- # We let the user specify their email address during signup.
- django_settings.SOCIAL_AUTH_PROTECTED_USER_FIELDS = ['email']
-
- # Disable exceptions by default for prod so you get redirect behavior
- # instead of a Django error page. During development you may want to
- # enable this when you want to get stack traces rather than redirections.
- django_settings.SOCIAL_AUTH_RAISE_EXCEPTIONS = False
-
- # Clean username to make sure username is compatible with our system requirements
- django_settings.SOCIAL_AUTH_CLEAN_USERNAME_FUNCTION = 'common.djangoapps.third_party_auth.models.clean_username'
-
- # Allow users to login using social auth even if their account is not verified yet
- # This is required since we [ab]use django's 'is_active' flag to indicate verified
- # accounts; without this set to True, python-social-auth won't allow us to link the
- # user's account to the third party account during registration (since the user is
- # not verified at that point).
- # We also generally allow unverified third party auth users to login (see the logic
- # in ensure_user_information in pipeline.py) because otherwise users who use social
- # auth to register with an invalid email address can become "stuck".
- # TODO: Remove the following if/when email validation is separated from the is_active flag.
- django_settings.SOCIAL_AUTH_INACTIVE_USER_LOGIN = True
- django_settings.SOCIAL_AUTH_INACTIVE_USER_URL = '/auth/inactive'
-
- # Context processors required under Django.
- django_settings.SOCIAL_AUTH_UUID_LENGTH = 10
- django_settings.DEFAULT_TEMPLATE_ENGINE['OPTIONS']['context_processors'] += (
- 'social_django.context_processors.backends',
- 'social_django.context_processors.login_redirect',
- )
diff --git a/common/djangoapps/third_party_auth/tests/test_settings.py b/common/djangoapps/third_party_auth/tests/test_settings.py
index accecca09ec8..2bc647fee616 100644
--- a/common/djangoapps/third_party_auth/tests/test_settings.py
+++ b/common/djangoapps/third_party_auth/tests/test_settings.py
@@ -1,67 +1,70 @@
-"""Unit tests for settings.py."""
+"""Unit tests for third-party auth settings in lms/envs/common.py."""
-from unittest.mock import patch
-from common.djangoapps.third_party_auth import provider, settings
-from common.djangoapps.third_party_auth.tests import testutil
+from django.conf import settings
+from django.test import TestCase, override_settings
+
+from common.djangoapps.third_party_auth import provider
from common.djangoapps.third_party_auth.tests.utils import skip_unless_thirdpartyauth
-_ORIGINAL_AUTHENTICATION_BACKENDS = ['first_authentication_backend']
-_ORIGINAL_INSTALLED_APPS = ['first_installed_app']
-_ORIGINAL_MIDDLEWARE_CLASSES = ['first_middleware_class']
-_ORIGINAL_TEMPLATE_CONTEXT_PROCESSORS = ['first_template_context_preprocessor']
-_SETTINGS_MAP = {
- 'AUTHENTICATION_BACKENDS': _ORIGINAL_AUTHENTICATION_BACKENDS,
- 'INSTALLED_APPS': _ORIGINAL_INSTALLED_APPS,
- 'MIDDLEWARE': _ORIGINAL_MIDDLEWARE_CLASSES,
- 'TEMPLATES': [{
- 'OPTIONS': {
- 'context_processors': _ORIGINAL_TEMPLATE_CONTEXT_PROCESSORS
- }
- }],
- 'FEATURES': {},
-}
-_SETTINGS_MAP['DEFAULT_TEMPLATE_ENGINE'] = _SETTINGS_MAP['TEMPLATES'][0]
+from openedx.core.djangolib.testing.utils import skip_unless_lms
-class SettingsUnitTest(testutil.TestCase):
- """Unit tests for settings management code."""
+@skip_unless_lms
+class SettingsUnitTest(TestCase):
+ """Unit tests for third-party auth settings defined in lms/envs/common.py."""
- # Suppress spurious no-member warning on fakes.
- # pylint: disable=no-member
+ def test_exception_middleware_in_middleware_list(self):
+ """Verify ExceptionMiddleware is included in MIDDLEWARE."""
+ assert 'common.djangoapps.third_party_auth.middleware.ExceptionMiddleware' in settings.MIDDLEWARE
- def setUp(self):
- super().setUp()
- self.settings = testutil.FakeDjangoSettings(_SETTINGS_MAP)
+ def test_fields_stored_in_session_defined(self):
+ """Verify FIELDS_STORED_IN_SESSION is defined with expected values."""
+ assert settings.FIELDS_STORED_IN_SESSION == ['auth_entry', 'next']
- def test_apply_settings_adds_exception_middleware(self):
- settings.apply_settings(self.settings)
- assert 'common.djangoapps.third_party_auth.middleware.ExceptionMiddleware' in self.settings.MIDDLEWARE
+ @skip_unless_thirdpartyauth()
+ def test_no_providers_enabled_by_default(self):
+ """Providers are only enabled via ConfigurationModels in the database."""
+ assert provider.Registry.enabled() == []
- def test_apply_settings_adds_fields_stored_in_session(self):
- settings.apply_settings(self.settings)
- assert ['auth_entry', 'next'] == self.settings.FIELDS_STORED_IN_SESSION
+ def test_social_auth_raise_exceptions_is_false(self):
+ """Guard against submitting a conf change that's convenient in dev but bad in prod."""
+ assert settings.SOCIAL_AUTH_RAISE_EXCEPTIONS is False
- @skip_unless_thirdpartyauth()
- def test_apply_settings_enables_no_providers_by_default(self):
- # Providers are only enabled via ConfigurationModels in the database
- settings.apply_settings(self.settings)
- assert [] == provider.Registry.enabled()
+ def test_social_auth_sanitize_redirects_is_false(self):
+ """Verify redirect sanitization is disabled (platform does its own)."""
+ assert settings.SOCIAL_AUTH_SANITIZE_REDIRECTS is False
+
+ def test_social_auth_login_error_url(self):
+ """Verify SOCIAL_AUTH_LOGIN_ERROR_URL is set."""
+ assert settings.SOCIAL_AUTH_LOGIN_ERROR_URL == '/'
+
+ def test_social_auth_login_redirect_url(self):
+ """Verify SOCIAL_AUTH_LOGIN_REDIRECT_URL is set."""
+ assert settings.SOCIAL_AUTH_LOGIN_REDIRECT_URL == '/dashboard'
+
+ def test_social_auth_strategy(self):
+ """Verify SOCIAL_AUTH_STRATEGY is set to use ConfigurationModelStrategy."""
+ assert settings.SOCIAL_AUTH_STRATEGY == 'common.djangoapps.third_party_auth.strategy.ConfigurationModelStrategy'
- def test_apply_settings_turns_off_raising_social_exceptions(self):
- # Guard against submitting a conf change that's convenient in dev but
- # bad in prod.
- settings.apply_settings(self.settings)
- assert not self.settings.SOCIAL_AUTH_RAISE_EXCEPTIONS
+ def test_social_auth_pipeline_defined(self):
+ """Verify SOCIAL_AUTH_PIPELINE is defined and includes expected steps."""
+ pipeline = settings.SOCIAL_AUTH_PIPELINE
+ assert isinstance(pipeline, list)
+ assert len(pipeline) > 0
+ # Verify some key pipeline steps are present
+ assert 'common.djangoapps.third_party_auth.pipeline.parse_query_params' in pipeline
+ assert 'social_core.pipeline.user.create_user' in pipeline
+ assert 'common.djangoapps.third_party_auth.pipeline.ensure_redirect_url_is_safe' in pipeline
- def test_apply_settings_turns_off_redirect_sanitization(self):
- settings.apply_settings(self.settings)
- assert not self.settings.SOCIAL_AUTH_SANITIZE_REDIRECTS
+ def test_social_auth_context_processors(self):
+ """Verify social_django context processors are included."""
+ # CONTEXT_PROCESSORS is used to build TEMPLATES, so check there
+ context_processors = settings.TEMPLATES[0]['OPTIONS']['context_processors']
+ assert 'social_django.context_processors.backends' in context_processors
+ assert 'social_django.context_processors.login_redirect' in context_processors
- def test_apply_settings_avoids_default_username_check(self):
- # Avoid the default username check where non-ascii characters are not
- # allowed when unicode username is enabled
- settings.apply_settings(self.settings)
- assert self.settings.SOCIAL_AUTH_CLEAN_USERNAMES
- # verify default behavior
- with patch.dict('django.conf.settings.FEATURES', {'ENABLE_UNICODE_USERNAME': True}):
- settings.apply_settings(self.settings)
- assert not self.settings.SOCIAL_AUTH_CLEAN_USERNAMES
+ @override_settings(FEATURES={'ENABLE_UNICODE_USERNAME': False})
+ def test_social_auth_clean_usernames_default(self):
+ """Verify SOCIAL_AUTH_CLEAN_USERNAMES is True when unicode usernames disabled."""
+ # Note: SOCIAL_AUTH_CLEAN_USERNAMES is a Derived setting, computed at settings load time.
+ # This test verifies the default behavior (unicode usernames disabled).
+ assert settings.SOCIAL_AUTH_CLEAN_USERNAMES is True
diff --git a/common/static/applets/capa/Protex.jar b/common/static/applets/capa/Protex.jar
deleted file mode 100644
index 2c6a819ec5d1..000000000000
Binary files a/common/static/applets/capa/Protex.jar and /dev/null differ
diff --git a/common/static/applets/capa/genex.jar b/common/static/applets/capa/genex.jar
deleted file mode 100644
index 75f784b59245..000000000000
Binary files a/common/static/applets/capa/genex.jar and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX2E0-3D-balls.png b/common/static/images/capa/vsepr/AX2E0-3D-balls.png
deleted file mode 100644
index 7595cf2a6c96..000000000000
Binary files a/common/static/images/capa/vsepr/AX2E0-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX2E1-3D-balls.png b/common/static/images/capa/vsepr/AX2E1-3D-balls.png
deleted file mode 100644
index c8816feb114f..000000000000
Binary files a/common/static/images/capa/vsepr/AX2E1-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX2E2-3D-balls.png b/common/static/images/capa/vsepr/AX2E2-3D-balls.png
deleted file mode 100644
index 00faa7e6beef..000000000000
Binary files a/common/static/images/capa/vsepr/AX2E2-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX2E3-3D-balls.png b/common/static/images/capa/vsepr/AX2E3-3D-balls.png
deleted file mode 100644
index 4fb7022f8c03..000000000000
Binary files a/common/static/images/capa/vsepr/AX2E3-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX3E0-3D-balls.png b/common/static/images/capa/vsepr/AX3E0-3D-balls.png
deleted file mode 100644
index eeff5b22a244..000000000000
Binary files a/common/static/images/capa/vsepr/AX3E0-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX3E1-3D-balls.png b/common/static/images/capa/vsepr/AX3E1-3D-balls.png
deleted file mode 100644
index e5386bf0d79a..000000000000
Binary files a/common/static/images/capa/vsepr/AX3E1-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX3E2-3D-balls.png b/common/static/images/capa/vsepr/AX3E2-3D-balls.png
deleted file mode 100644
index 185abaa4ea61..000000000000
Binary files a/common/static/images/capa/vsepr/AX3E2-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX4E0-3D-balls.png b/common/static/images/capa/vsepr/AX4E0-3D-balls.png
deleted file mode 100644
index f690ad1f5a09..000000000000
Binary files a/common/static/images/capa/vsepr/AX4E0-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX4E1-3D-balls.png b/common/static/images/capa/vsepr/AX4E1-3D-balls.png
deleted file mode 100644
index 1e940f7576c3..000000000000
Binary files a/common/static/images/capa/vsepr/AX4E1-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX4E2-3D-balls.png b/common/static/images/capa/vsepr/AX4E2-3D-balls.png
deleted file mode 100644
index ec74eb90fc20..000000000000
Binary files a/common/static/images/capa/vsepr/AX4E2-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX5E1-3D-balls.png b/common/static/images/capa/vsepr/AX5E1-3D-balls.png
deleted file mode 100644
index dc12dd9f749d..000000000000
Binary files a/common/static/images/capa/vsepr/AX5E1-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX5E2-3D-balls.png b/common/static/images/capa/vsepr/AX5E2-3D-balls.png
deleted file mode 100644
index 38755c144de0..000000000000
Binary files a/common/static/images/capa/vsepr/AX5E2-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX6E0-3D-balls.png b/common/static/images/capa/vsepr/AX6E0-3D-balls.png
deleted file mode 100644
index 775ffc46b981..000000000000
Binary files a/common/static/images/capa/vsepr/AX6E0-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX6E1-3D-balls.png b/common/static/images/capa/vsepr/AX6E1-3D-balls.png
deleted file mode 100644
index 3e51b877c1b6..000000000000
Binary files a/common/static/images/capa/vsepr/AX6E1-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX7E0-3D-balls.png b/common/static/images/capa/vsepr/AX7E0-3D-balls.png
deleted file mode 100644
index 95d7aebffd5f..000000000000
Binary files a/common/static/images/capa/vsepr/AX7E0-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX8E0-3D-balls.png b/common/static/images/capa/vsepr/AX8E0-3D-balls.png
deleted file mode 100644
index 3a24f7794a88..000000000000
Binary files a/common/static/images/capa/vsepr/AX8E0-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/AX9E0-3D-balls.png b/common/static/images/capa/vsepr/AX9E0-3D-balls.png
deleted file mode 100644
index b457f58eb5f0..000000000000
Binary files a/common/static/images/capa/vsepr/AX9E0-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Bent-3D-balls.png b/common/static/images/capa/vsepr/Bent-3D-balls.png
deleted file mode 100644
index 71bb9526a89c..000000000000
Binary files a/common/static/images/capa/vsepr/Bent-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Linear-3D-balls.png b/common/static/images/capa/vsepr/Linear-3D-balls.png
deleted file mode 100644
index af5f92c7b102..000000000000
Binary files a/common/static/images/capa/vsepr/Linear-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Linear-stick.png b/common/static/images/capa/vsepr/Linear-stick.png
deleted file mode 100644
index e1306f9a0d31..000000000000
Binary files a/common/static/images/capa/vsepr/Linear-stick.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Octahedral-3D-balls.png b/common/static/images/capa/vsepr/Octahedral-3D-balls.png
deleted file mode 100644
index 0032fe1ed31d..000000000000
Binary files a/common/static/images/capa/vsepr/Octahedral-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Octahedral-stick.png b/common/static/images/capa/vsepr/Octahedral-stick.png
deleted file mode 100644
index 3d2b7ca5fd1e..000000000000
Binary files a/common/static/images/capa/vsepr/Octahedral-stick.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Pentagonal-bipyramidal-3D-balls.png b/common/static/images/capa/vsepr/Pentagonal-bipyramidal-3D-balls.png
deleted file mode 100644
index 23e02daf25b3..000000000000
Binary files a/common/static/images/capa/vsepr/Pentagonal-bipyramidal-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Pentagonal-planar-3D-balls.png b/common/static/images/capa/vsepr/Pentagonal-planar-3D-balls.png
deleted file mode 100644
index 0768ec750463..000000000000
Binary files a/common/static/images/capa/vsepr/Pentagonal-planar-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Pentagonal-pyramidal-3D-balls.png b/common/static/images/capa/vsepr/Pentagonal-pyramidal-3D-balls.png
deleted file mode 100644
index 511db1ea16f2..000000000000
Binary files a/common/static/images/capa/vsepr/Pentagonal-pyramidal-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Pyramidal-3D-balls.png b/common/static/images/capa/vsepr/Pyramidal-3D-balls.png
deleted file mode 100644
index 0383528d3d59..000000000000
Binary files a/common/static/images/capa/vsepr/Pyramidal-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Seesaw-3D-balls.png b/common/static/images/capa/vsepr/Seesaw-3D-balls.png
deleted file mode 100644
index b7665da3b5ef..000000000000
Binary files a/common/static/images/capa/vsepr/Seesaw-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Square-antiprismatic-3D-balls.png b/common/static/images/capa/vsepr/Square-antiprismatic-3D-balls.png
deleted file mode 100644
index 675ba88c5c24..000000000000
Binary files a/common/static/images/capa/vsepr/Square-antiprismatic-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Square-planar-3D-balls.png b/common/static/images/capa/vsepr/Square-planar-3D-balls.png
deleted file mode 100644
index 6a90a0c361d6..000000000000
Binary files a/common/static/images/capa/vsepr/Square-planar-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/T-shaped-3D-balls.png b/common/static/images/capa/vsepr/T-shaped-3D-balls.png
deleted file mode 100644
index b3eaa47f8acc..000000000000
Binary files a/common/static/images/capa/vsepr/T-shaped-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Tetrahedral-3D-balls.png b/common/static/images/capa/vsepr/Tetrahedral-3D-balls.png
deleted file mode 100644
index 9ff8731ac0ea..000000000000
Binary files a/common/static/images/capa/vsepr/Tetrahedral-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Tetrahedral-stick.png b/common/static/images/capa/vsepr/Tetrahedral-stick.png
deleted file mode 100644
index 09a41164b65d..000000000000
Binary files a/common/static/images/capa/vsepr/Tetrahedral-stick.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Trigonal-3D-balls.png b/common/static/images/capa/vsepr/Trigonal-3D-balls.png
deleted file mode 100644
index 20e7c957d879..000000000000
Binary files a/common/static/images/capa/vsepr/Trigonal-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Trigonal-bipyramidal-3D-balls.png b/common/static/images/capa/vsepr/Trigonal-bipyramidal-3D-balls.png
deleted file mode 100644
index ab5f0133965e..000000000000
Binary files a/common/static/images/capa/vsepr/Trigonal-bipyramidal-3D-balls.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Trigonal-bipyramidal-stick.png b/common/static/images/capa/vsepr/Trigonal-bipyramidal-stick.png
deleted file mode 100644
index 3b36dcd5c66b..000000000000
Binary files a/common/static/images/capa/vsepr/Trigonal-bipyramidal-stick.png and /dev/null differ
diff --git a/common/static/images/capa/vsepr/Trigonal-planar-stick.png b/common/static/images/capa/vsepr/Trigonal-planar-stick.png
deleted file mode 100644
index f2fd25c56f80..000000000000
Binary files a/common/static/images/capa/vsepr/Trigonal-planar-stick.png and /dev/null differ
diff --git a/common/static/js/capa/README b/common/static/js/capa/README
deleted file mode 100644
index ca845717fe53..000000000000
--- a/common/static/js/capa/README
+++ /dev/null
@@ -1 +0,0 @@
-These files really should be in the capa block, but we don't have a way to load js from there at the moment. (TODO)
diff --git a/common/static/js/capa/annotationinput.js b/common/static/js/capa/annotationinput.js
deleted file mode 100644
index 09adde930c83..000000000000
--- a/common/static/js/capa/annotationinput.js
+++ /dev/null
@@ -1,98 +0,0 @@
-(function() {
- var debug = false;
-
- var module = {
- debug: debug,
- inputSelector: '.annotation-input',
- tagSelector: '.tag',
- tagsSelector: '.tags',
- commentSelector: 'textarea.comment',
- valueSelector: 'input.value', // stash tag selections and comment here as a JSON string...
-
- singleSelect: true,
-
- init: function() {
- var that = this;
-
- if (this.debug) { console.log('annotation input loaded: '); }
-
- $(this.inputSelector).each(function(index, el) {
- if (!$(el).data('listening')) {
- $(el).delegate(that.tagSelector, 'click', $.proxy(that.onClickTag, that));
- $(el).delegate(that.commentSelector, 'change', $.proxy(that.onChangeComment, that));
- $(el).data('listening', 'yes');
- }
- });
- },
- onChangeComment: function(e) {
- var value_el = this.findValueEl(e.target);
- var current_value = this.loadValue(value_el);
- var target_value = $(e.target).val();
-
- current_value.comment = target_value;
- this.storeValue(value_el, current_value);
- },
- onClickTag: function(e) {
- var target_el = e.target,
- target_value, target_index;
- var value_el, current_value;
-
- value_el = this.findValueEl(e.target);
- current_value = this.loadValue(value_el);
- target_value = $(e.target).data('id');
-
- if (!$(target_el).hasClass('selected')) {
- if (this.singleSelect) {
- current_value.options = [target_value];
- } else {
- current_value.options.push(target_value);
- }
- } else {
- if (this.singleSelect) {
- current_value.options = [];
- } else {
- target_index = current_value.options.indexOf(target_value);
- if (target_index !== -1) {
- current_value.options.splice(target_index, 1);
- }
- }
- }
-
- this.storeValue(value_el, current_value);
-
- if (this.singleSelect) {
- $(target_el).closest(this.tagsSelector)
- .find(this.tagSelector)
- .not(target_el)
- .removeClass('selected');
- }
- $(target_el).toggleClass('selected');
- },
- findValueEl: function(target_el) {
- var input_el = $(target_el).closest(this.inputSelector);
- return $(this.valueSelector, input_el);
- },
- loadValue: function(value_el) {
- var json = $(value_el).val();
-
- var result = JSON.parse(json);
- if (result === null) {
- result = {};
- }
- if (!result.hasOwnProperty('options')) {
- result.options = [];
- }
- if (!result.hasOwnProperty('comment')) {
- result.comment = '';
- }
-
- return result;
- },
- storeValue: function(value_el, new_value) {
- var json = JSON.stringify(new_value);
- $(value_el).val(json);
- }
- };
-
- module.init();
-}).call(this);
diff --git a/common/static/js/capa/chemical_equation_preview.js b/common/static/js/capa/chemical_equation_preview.js
deleted file mode 100644
index d23d8e51d3f6..000000000000
--- a/common/static/js/capa/chemical_equation_preview.js
+++ /dev/null
@@ -1,36 +0,0 @@
-(function() {
- update = function() {
- function create_handler(saved_div) {
- return (function(response) {
- if (response.error) {
- edx.HtmlUtils.setHtml(
- saved_div,
- edx.HtmlUtils.joinHtml(
- edx.HtmlUtils.HTML(""),
- response.error,
- edx.HtmlUtils.HTML('')
- )
- );
- } else {
- saved_div.html(edx.HtmlUtils.HTML(response.preview).toString());
- }
- });
- }
-
- prev_id = '#' + this.id + '_preview';
- preview_div = $(prev_id);
-
- // find the closest parent problems-wrapper and use that url
- url = $(this).closest('.problems-wrapper').data('url');
- // grab the input id from the input
- input_id = $(this).data('input-id');
-
- Problem.inputAjax(url, input_id, 'preview_chemcalc', {formula: this.value}, create_handler(preview_div));
- };
-
- inputs = $('.chemicalequationinput input');
- // update on load
- inputs.each(update);
- // and on every change
- inputs.bind('input', update);
-}).call(this);
diff --git a/common/static/js/capa/choicetextinput.js b/common/static/js/capa/choicetextinput.js
deleted file mode 100644
index 3d08c94ba7f2..000000000000
--- a/common/static/js/capa/choicetextinput.js
+++ /dev/null
@@ -1,73 +0,0 @@
-(function() {
- var update = function() {
- // Whenever a value changes create a new serialized version of this
- // problem's inputs and set the hidden input field's value to equal it.
- var parent = $(this).closest('section.choicetextinput');
- // find the closest parent problems-wrapper and use that as the problem
- // grab the input id from the input
- // real_input is the hidden input field
- var $real_input = $('input.choicetextvalue', parent);
- var $all_inputs = $('input.ctinput', parent);
- var user_inputs = {};
- $($all_inputs).each(function(index, elt) {
- var $node = $(elt);
- var name = $node.attr('id');
- var val = $node.val();
- var radio_value = $node.attr('value');
- var type = $node.attr('type');
- var is_checked = $node.attr('checked');
- if (type === 'radio' || type === 'checkbox') {
- if (is_checked === 'checked' || is_checked === 'true') {
- user_inputs[name] = radio_value;
- }
- } else {
- user_inputs[name] = val;
- }
- });
- var val_string = JSON.stringify(user_inputs);
- // this is what gets submitted as the answer, we deserialize it later
- $real_input.val(val_string);
- };
-
- var check_parent = function(event) {
- // This looks for the containing choice of a textinput
- // and sets it to be checked.
- var $elt = $(event.target);
- var parent_container = $elt.closest('section[id^="forinput"]');
- var choice = parent_container.find("input[type='checkbox'], input[type='radio']");
- choice.attr('checked', 'checked');
- choice.change();
- // need to check it then trigger the change event
- };
-
- var imitate_label = function(event) {
- // This causes a section to check and uncheck
- // a radiobutton/checkbox whenever a user clicks on it
- // If the button/checkbox is disabled, nothing happens
- var $elt = $(event.target);
- var parent_container = $elt.closest('section[id^="forinput"]');
- var choice = parent_container.find("input[type='checkbox'], input[type='radio']");
- if (choice.attr('type') === 'radio') {
- choice.attr('checked', 'checked');
- } else {
- if (choice.attr('checked')) {
- choice.prop('checked', false);
- } else {
- choice.prop('checked', true);
- }
- }
- choice.change();
- update();
- };
- var $choices = $('.mock_label');
- var $inputs = $('.choicetextinput .ctinput');
- var $text_inputs = $('.choicetextinput .ctinput[type="text"]');
- // update on load
- $inputs.each(update);
- // and on every change
- // This allows text inside of choices to behave as if they were part of
- // a label for the choice's button/checkbox
- $choices.click(imitate_label);
- $inputs.bind('change', update);
- $text_inputs.click(check_parent);
-}).call(this);
diff --git a/common/static/js/capa/design-protein-2d.js b/common/static/js/capa/design-protein-2d.js
deleted file mode 100644
index 84a372156e00..000000000000
--- a/common/static/js/capa/design-protein-2d.js
+++ /dev/null
@@ -1,85 +0,0 @@
-(function() {
- var timeout = 1000;
-
- waitForProtex();
-
- function waitForProtex() {
- if (typeof protex !== 'undefined' && protex) {
- protex.onInjectionDone('protex');
- // eslint-disable-next-line brace-style
- }
- /* if (typeof(protex) !== "undefined") {
- //initializeProtex();
- } */
- else {
- setTimeout(function() { waitForProtex(); }, timeout);
- }
- }
-
- // NOTE:
- // Protex uses three global functions:
- // protexSetTargetShape (exported from GWT)
- // exported protexCheckAnswer (exported from GWT)
- // It calls protexIsReady with a deferred command when it has finished
- // initialization and has drawn itself
-
- function updateProtexField() {
- var problem = $('#protex_container').parents('.problem');
- var input_field = problem.find('input[type=hidden]');
- var protex_answer = protexCheckAnswer();
- var value = {protex_answer: protex_answer};
- // console.log(JSON.stringify(value));
- input_field.val(JSON.stringify(value));
- }
-
- protexIsReady = function() {
- // Load target shape
- var target_shape = $('#target_shape').val();
- protexSetTargetShape(target_shape);
-
- // Get answer from protex and store it into the hidden input field
- // when Check button is clicked
- var $fold_button = $('#fold-button');
- $fold_button.on('click', function() {
- var problem = $('#protex_container').parents('.problem');
- var input_field = problem.find('input[type=hidden]');
- var protex_answer = protexCheckAnswer();
- var value = {protex_answer: protex_answer};
- // console.log(JSON.stringify(value));
- input_field.val(JSON.stringify(value));
- });
- updateProtexField();
- };
-
- /* function initializeProtex() {
- //Check to see if the two exported GWT functions protexSetTargetShape
- // and protexCheckAnswer have been appended to global scope -- this
- //happens at the end of onModuleLoad() in GWT
- if (typeof(protexSetTargetShape) === "function" &&
- typeof(protexCheckAnswer) === "function") {
-
- //Load target shape
- var target_shape = $('#target_shape').val();
- //protexSetTargetShape(target_shape);
-
- //Get answer from protex and store it into the hidden input field
- //when Check button is clicked
- var problem = $('#protex_container').parents('.problem');
- var check_button = problem.find('input.check');
- var input_field = problem.find('input[type=hidden]');
- check_button.on('click', function() {
- var protex_answer = protexCheckAnswer();
- var value = {protex_answer: protex_answer};
- input_field.val(JSON.stringify(value));
- });
-
- //TO DO: Fix this, it works but is utterly ugly and unreliable
- setTimeout(function() {
- protexSetTargetShape(target_shape);}, 2000);
-
- }
- else {
- setTimeout(function() {initializeProtex(); }, timeout);
- }
- } */
-}).call(this);
diff --git a/common/static/js/capa/drag_and_drop.js b/common/static/js/capa/drag_and_drop.js
deleted file mode 100644
index aedf86612f11..000000000000
--- a/common/static/js/capa/drag_and_drop.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Wrapper for RequireJS. It will make the standard requirejs(), require(), and
-// define() functions from Require JS available inside the anonymous function.
-//
-// See https://openedx.atlassian.net/wiki/display/PLAT/Integration+of+Require+JS+into+the+system
-(function(requirejs, require, define) {
-// HACK: this should be removed when it is safe to do so
- if (window.baseUrl) {
- requirejs.config({baseUrl: baseUrl});
- }
-
- // The current JS file will be loaded and run each time. It will require a
- // single dependency which will be loaded and stored by RequireJS. On
- // subsequent runs, RequireJS will return the dependency from memory, rather
- // than loading it again from the server. For that reason, it is a good idea to
- // keep the current JS file as small as possible, and move everything else into
- // RequireJS module dependencies.
- require(['js/capa/drag_and_drop/main'], function(Main) {
- Main();
- });
-
-// End of wrapper for RequireJS. As you can see, we are passing
-// namespaced Require JS variables to an anonymous function. Within
-// it, you can use the standard requirejs(), require(), and define()
-// functions as if they were in the global namespace.
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define)
diff --git a/common/static/js/capa/drag_and_drop/base_image.js b/common/static/js/capa/drag_and_drop/base_image.js
deleted file mode 100644
index 736d8d343812..000000000000
--- a/common/static/js/capa/drag_and_drop/base_image.js
+++ /dev/null
@@ -1,45 +0,0 @@
-(function(requirejs, require, define) {
- define(['edx-ui-toolkit/js/utils/html-utils'], function(HtmlUtils) {
- return BaseImage;
-
- function BaseImage(state) {
- var $baseImageElContainer;
-
- $baseImageElContainer = $(HtmlUtils.joinHtml(
- HtmlUtils.HTML('
')
- ).toString());
-
- state.baseImageEl = $('
', {
- alt: gettext('Drop target image')
- });
-
- state.baseImageEl.attr('src', state.config.baseImage);
- state.baseImageEl.load(function() {
- $baseImageElContainer.css({
- width: this.width,
- height: this.height
- });
-
- state.baseImageEl.appendTo($baseImageElContainer);
- $baseImageElContainer.appendTo(state.containerEl);
-
- state.baseImageEl.mousedown(function(event) {
- event.preventDefault();
- });
-
- state.baseImageLoaded = true;
- });
- state.baseImageEl.error(function() {
- var errorMsg = HtmlUtils.joinHtml(
- HtmlUtils.HTML(''),
- HtmlUtils.HTML('ERROR: Image "'), state.config.baseImage, HtmlUtils.HTML('" was not found!'),
- HtmlUtils.HTML('')
- );
- console.log('ERROR: Image "' + state.config.baseImage + '" was not found!');
- HtmlUtils.setHtml($baseImageElContainer, errorMsg);
- $baseImageElContainer.appendTo(state.containerEl);
- });
- }
- }); // End-of: define([], function () {
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
diff --git a/common/static/js/capa/drag_and_drop/config_parser.js b/common/static/js/capa/drag_and_drop/config_parser.js
deleted file mode 100644
index bbd574b0d33a..000000000000
--- a/common/static/js/capa/drag_and_drop/config_parser.js
+++ /dev/null
@@ -1,271 +0,0 @@
-(function(requirejs, require, define) {
- define([], function() {
- return configParser;
-
- function configParser(state, config) {
- state.config = {
- draggables: [],
- baseImage: '',
- targets: [],
- onePerTarget: null, // Specified by user. No default.
- targetOutline: true,
- labelBgColor: '#d6d6d6',
- individualTargets: null, // Depends on 'targets'.
- foundErrors: false // Whether or not we find errors while processing the config.
- };
-
- getDraggables(state, config);
- getBaseImage(state, config);
- getTargets(state, config);
- getOnePerTarget(state, config);
- getTargetOutline(state, config);
- getLabelBgColor(state, config);
-
- setIndividualTargets(state);
-
- if (state.config.foundErrors !== false) {
- return false;
- }
-
- return true;
- }
-
- function getDraggables(state, config) {
- if (config.hasOwnProperty('draggables') === false) {
- console.log('ERROR: "config" does not have a property "draggables".');
- state.config.foundErrors = true;
- } else if ($.isArray(config.draggables) === true) {
- config.draggables.every(function(draggable) {
- if (processDraggable(state, draggable) !== true) {
- state.config.foundErrors = true;
-
- // Exit immediately from .every() call.
- return false;
- }
-
- // Continue to next .every() call.
- return true;
- });
- } else {
- console.log('ERROR: The type of config.draggables is no supported.');
- state.config.foundErrors = true;
- }
- }
-
- function getBaseImage(state, config) {
- if (config.hasOwnProperty('base_image') === false) {
- console.log('ERROR: "config" does not have a property "base_image".');
- state.config.foundErrors = true;
- } else if (typeof config.base_image === 'string') {
- state.config.baseImage = config.base_image;
- } else {
- console.log('ERROR: Property config.base_image is not of type "string".');
- state.config.foundErrors = true;
- }
- }
-
- function getTargets(state, config) {
- if (config.hasOwnProperty('targets') === false) {
- // It is possible that no "targets" were specified. This is not an error.
- // In this case the default value of "[]" (empty array) will be used.
- // Draggables can be positioned anywhere on the image, and the server will
- // get an answer in the form of (x, y) coordinates for each draggable.
- } else if ($.isArray(config.targets) === true) {
- config.targets.every(function(target) {
- if (processTarget(state, target) !== true) {
- state.config.foundErrors = true;
-
- // Exit immediately from .every() call.
- return false;
- }
-
- // Continue to next .every() call.
- return true;
- });
- } else {
- console.log('ERROR: Property config.targets is not of a supported type.');
- state.config.foundErrors = true;
- }
- }
-
- function getOnePerTarget(state, config) {
- if (config.hasOwnProperty('one_per_target') === false) {
- console.log('ERROR: "config" does not have a property "one_per_target".');
- state.config.foundErrors = true;
- } else if (typeof config.one_per_target === 'string') {
- if (config.one_per_target.toLowerCase() === 'true') {
- state.config.onePerTarget = true;
- } else if (config.one_per_target.toLowerCase() === 'false') {
- state.config.onePerTarget = false;
- } else {
- console.log('ERROR: Property config.one_per_target can either be "true", or "false".');
- state.config.foundErrors = true;
- }
- } else {
- console.log('ERROR: Property config.one_per_target is not of a supported type.');
- state.config.foundErrors = true;
- }
- }
-
- function getTargetOutline(state, config) {
- // It is possible that no "target_outline" was specified. This is not an error.
- // In this case the default value of 'true' (boolean) will be used.
-
- if (config.hasOwnProperty('target_outline') === true) {
- if (typeof config.target_outline === 'string') {
- if (config.target_outline.toLowerCase() === 'true') {
- state.config.targetOutline = true;
- } else if (config.target_outline.toLowerCase() === 'false') {
- state.config.targetOutline = false;
- } else {
- console.log('ERROR: Property config.target_outline can either be "true", or "false".');
- state.config.foundErrors = true;
- }
- } else {
- console.log('ERROR: Property config.target_outline is not of a supported type.');
- state.config.foundErrors = true;
- }
- }
- }
-
- function getLabelBgColor(state, config) {
- // It is possible that no "label_bg_color" was specified. This is not an error.
- // In this case the default value of '#d6d6d6' (string) will be used.
-
- if (config.hasOwnProperty('label_bg_color') === true) {
- if (typeof config.label_bg_color === 'string') {
- state.config.labelBgColor = config.label_bg_color;
- } else {
- console.log('ERROR: Property config.label_bg_color is not of a supported type.');
- }
- }
- }
-
- function setIndividualTargets(state) {
- if (state.config.targets.length === 0) {
- state.config.individualTargets = false;
- } else {
- state.config.individualTargets = true;
- }
- }
-
- function processDraggable(state, obj) {
- if (
- (attrIsString(obj, 'id') === false)
- || (attrIsString(obj, 'icon') === false)
- || (attrIsString(obj, 'label') === false)
-
- || (attrIsBoolean(obj, 'can_reuse', false) === false)
-
- || (obj.hasOwnProperty('target_fields') === false)
- ) {
- return false;
- }
-
- // Check that all targets in the 'target_fields' property are proper target objects.
- // We will be testing the return value from .every() call (it can be 'true' or 'false').
- if (obj.target_fields.every(
- function(targetObj) {
- return processTarget(state, targetObj, false);
- }
- ) === false) {
- return false;
- }
-
- state.config.draggables.push(obj);
-
- return true;
- }
-
- // We need 'pushToState' parameter in order to simply test an object for the fact that it is a
- // proper target (without pushing it to the 'state' object). When
- //
- // pushToState === false
- //
- // the object being tested is not going to be pushed to 'state'. The function will onyl return
- // 'true' or 'false.
- function processTarget(state, obj, pushToState) {
- if (
- (attrIsString(obj, 'id') === false)
-
- || (attrIsInteger(obj, 'w') === false)
- || (attrIsInteger(obj, 'h') === false)
-
- || (attrIsInteger(obj, 'x') === false)
- || (attrIsInteger(obj, 'y') === false)
- ) {
- return false;
- }
-
- if (pushToState !== false) {
- state.config.targets.push(obj);
- }
-
- return true;
- }
-
- function attrIsString(obj, attr) {
- if (obj.hasOwnProperty(attr) === false) {
- console.log('ERROR: Attribute "obj.' + attr + '" is not present.');
-
- return false;
- } else if (typeof obj[attr] !== 'string') {
- console.log('ERROR: Attribute "obj.' + attr + '" is not a string.');
-
- return false;
- }
-
- return true;
- }
-
- function attrIsInteger(obj, attr) {
- var tempInt;
-
- if (obj.hasOwnProperty(attr) === false) {
- console.log('ERROR: Attribute "obj.' + attr + '" is not present.');
-
- return false;
- }
-
- tempInt = parseInt(obj[attr], 10);
-
- if (isFinite(tempInt) === false) {
- console.log('ERROR: Attribute "obj.' + attr + '" is not an integer.');
-
- return false;
- }
-
- obj[attr] = tempInt;
-
- return true;
- }
-
- function attrIsBoolean(obj, attr, defaultVal) {
- if (obj.hasOwnProperty(attr) === false) {
- if (defaultVal === undefined) {
- console.log('ERROR: Attribute "obj.' + attr + '" is not present.');
-
- return false;
- } else {
- obj[attr] = defaultVal;
-
- return true;
- }
- }
-
- if (obj[attr] === '') {
- obj[attr] = defaultVal;
- } else if ((obj[attr] === 'false') || (obj[attr] === false)) {
- obj[attr] = false;
- } else if ((obj[attr] === 'true') || (obj[attr] === true)) {
- obj[attr] = true;
- } else {
- console.log('ERROR: Attribute "obj.' + attr + '" is not a boolean.');
-
- return false;
- }
-
- return true;
- }
- }); // End-of: define([], function () {
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
diff --git a/common/static/js/capa/drag_and_drop/container.js b/common/static/js/capa/drag_and_drop/container.js
deleted file mode 100644
index 35107a8b0df4..000000000000
--- a/common/static/js/capa/drag_and_drop/container.js
+++ /dev/null
@@ -1,13 +0,0 @@
-(function(requirejs, require, define) {
- define(['edx-ui-toolkit/js/utils/html-utils'], function(HtmlUtils) {
- return Container;
-
- function Container(state) {
- state.containerEl = $(
- ''
- );
-
- $('#inputtype_' + state.problemId).before(HtmlUtils.HTML(state.containerEl).toString());
- }
- }); // End-of: define([], function () {
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
diff --git a/common/static/js/capa/drag_and_drop/draggable_events.js b/common/static/js/capa/drag_and_drop/draggable_events.js
deleted file mode 100644
index 667cd54fe3ae..000000000000
--- a/common/static/js/capa/drag_and_drop/draggable_events.js
+++ /dev/null
@@ -1,143 +0,0 @@
-(function(requirejs, require, define) {
- define([], function() {
- return {
- attachMouseEventsTo: function(element) {
- var self;
-
- self = this;
-
- this[element].mousedown(function(event) {
- self.mouseDown(event);
- });
- this[element].mouseup(function(event) {
- self.mouseUp(event);
- });
- this[element].mousemove(function(event) {
- self.mouseMove(event);
- });
- },
-
- mouseDown: function(event) {
- if (this.mousePressed === false) {
- // So that the browser does not perform a default drag.
- // If we don't do this, each drag operation will
- // potentially cause the highlghting of the dragged element.
- event.preventDefault();
- event.stopPropagation();
-
- if (this.numDraggablesOnMe > 0) {
- return;
- }
-
- // If this draggable is just being dragged out of the
- // container, we must perform some additional tasks.
- if (this.inContainer === true) {
- if ((this.isReusable === true) && (this.isOriginal === true)) {
- this.makeDraggableCopy(function(draggableCopy) {
- draggableCopy.mouseDown(event);
- });
-
- return;
- }
-
- if (this.isOriginal === true) {
- this.containerEl.hide();
- this.iconEl.detach();
- }
-
- if (this.iconImgEl !== null) {
- this.iconImgEl.css({
- width: this.iconWidth,
- height: this.iconHeight
- });
- }
- this.iconEl.css({
- 'background-color': this.iconElBGColor,
- 'padding-left': this.iconElPadding,
- 'padding-right': this.iconElPadding,
- border: this.iconElBorder,
- width: this.iconWidth,
- height: this.iconHeight,
- left: event.pageX - this.state.baseImageEl.offset().left - this.iconWidth * 0.5 - this.iconElLeftOffset,
- top: event.pageY - this.state.baseImageEl.offset().top - this.iconHeight * 0.5
- });
- this.iconEl.appendTo(this.state.baseImageEl.parent());
-
- if (this.labelEl !== null) {
- if (this.isOriginal === true) {
- this.labelEl.detach();
- }
- this.labelEl.css({
- 'background-color': this.state.config.labelBgColor,
- 'padding-left': 8,
- 'padding-right': 8,
- border: '1px solid black',
- left: event.pageX - this.state.baseImageEl.offset().left - this.labelWidth * 0.5 - 9, // Account for padding, border.
- top: event.pageY - this.state.baseImageEl.offset().top + this.iconHeight * 0.5 + 5
- });
- this.labelEl.appendTo(this.state.baseImageEl.parent());
- }
-
- this.inContainer = false;
- if (this.isOriginal === true) {
- this.state.numDraggablesInSlider -= 1;
- }
- // SR: global "screen reader" object in accessibility_tools.js
- window.SR.readText(gettext('dragging out of slider'));
- } else {
- window.SR.readText(gettext('dragging'));
- }
-
- this.zIndex = 1000;
- this.iconEl.css('z-index', '1000');
- if (this.labelEl !== null) {
- this.labelEl.css('z-index', '1000');
- }
- this.iconEl.attr('aria-grabbed', 'true').focus();
- this.toggleTargets(true);
- this.mousePressed = true;
- this.state.currentMovingDraggable = this;
- }
- },
-
- mouseUp: function() {
- if (this.mousePressed === true) {
- this.state.currentMovingDraggable = null;
- this.iconEl.attr('aria-grabbed', 'false');
-
- this.checkLandingElement();
- if (this.inContainer === true) {
- window.SR.readText(gettext('dropped in slider'));
- } else {
- window.SR.readText(gettext('dropped on target'));
- }
- this.toggleTargets(false);
- }
- },
-
- mouseMove: function(event) {
- if (this.mousePressed === true) {
- // Because we have also attached a 'mousemove' event to the
- // 'document' (that will do the same thing), let's tell the
- // browser not to bubble up this event. The attached event
- // on the 'document' will only be triggered when the mouse
- // pointer leaves the draggable while it is in the middle
- // of a drag operation (user moves the mouse very quickly).
- event.stopPropagation();
-
- this.iconEl.css({
- left: event.pageX - this.state.baseImageEl.offset().left - this.iconWidth * 0.5 - this.iconElLeftOffset,
- top: event.pageY - this.state.baseImageEl.offset().top - this.iconHeight * 0.5
- });
-
- if (this.labelEl !== null) {
- this.labelEl.css({
- left: event.pageX - this.state.baseImageEl.offset().left - this.labelWidth * 0.5 - 9, // Acoount for padding, border.
- top: event.pageY - this.state.baseImageEl.offset().top + this.iconHeight * 0.5 + 5
- });
- }
- }
- }
- }; // End-of: return {
- }); // End-of: define([], function () {
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
diff --git a/common/static/js/capa/drag_and_drop/draggable_logic.js b/common/static/js/capa/drag_and_drop/draggable_logic.js
deleted file mode 100644
index 5de987fd128c..000000000000
--- a/common/static/js/capa/drag_and_drop/draggable_logic.js
+++ /dev/null
@@ -1,400 +0,0 @@
-(function(requirejs, require, define) {
- define(['js/capa/drag_and_drop/update_input', 'js/capa/drag_and_drop/targets'], function(updateInput, Targets) {
- return {
- moveDraggableTo: function(moveType, target, funcCallback) {
- var self, offset;
-
- if (this.hasLoaded === false) {
- self = this;
-
- setTimeout(function() {
- self.moveDraggableTo(moveType, target, funcCallback);
- }, 50);
-
- return;
- }
-
- if ((this.isReusable === true) && (this.isOriginal === true)) {
- this.makeDraggableCopy(function(draggableCopy) {
- draggableCopy.moveDraggableTo(moveType, target, funcCallback);
- });
-
- return;
- }
-
- offset = 0;
- if (this.state.config.targetOutline === true) {
- offset = 1;
- }
-
- this.inContainer = false;
-
- if (this.isOriginal === true) {
- this.containerEl.hide();
- this.iconEl.detach();
- }
-
- if (this.iconImgEl !== null) {
- this.iconImgEl.css({
- width: this.iconWidth,
- height: this.iconHeight
- });
- }
-
- this.iconEl.css({
- 'background-color': this.iconElBGColor,
- 'padding-left': this.iconElPadding,
- 'padding-right': this.iconElPadding,
- border: this.iconElBorder,
- width: this.iconWidth,
- height: this.iconHeight
- });
- if (moveType === 'target') {
- this.iconEl.css({
- left: target.offset.left + 0.5 * target.w - this.iconWidth * 0.5 + offset - this.iconElLeftOffset,
- top: target.offset.top + 0.5 * target.h - this.iconHeight * 0.5 + offset
- });
- } else {
- this.iconEl.css({
- left: target.x - this.iconWidth * 0.5 + offset - this.iconElLeftOffset,
- top: target.y - this.iconHeight * 0.5 + offset
- });
- }
- this.iconEl.appendTo(this.state.baseImageEl.parent());
-
- if (this.labelEl !== null) {
- if (this.isOriginal === true) {
- this.labelEl.detach();
- }
- this.labelEl.css({
- 'background-color': this.state.config.labelBgColor,
- 'padding-left': 8,
- 'padding-right': 8,
- border: '1px solid black'
- });
- if (moveType === 'target') {
- this.labelEl.css({
- left: target.offset.left + 0.5 * target.w - this.labelWidth * 0.5 + offset - 9, // Account for padding, border.
- top: target.offset.top + 0.5 * target.h + this.iconHeight * 0.5 + 5 + offset
- });
- } else {
- this.labelEl.css({
- left: target.x - this.labelWidth * 0.5 + offset - 9, // Account for padding, border.
- top: target.y - this.iconHeight * 0.5 + this.iconHeight + 5 + offset
- });
- }
- this.labelEl.appendTo(this.state.baseImageEl.parent());
- }
-
- if (moveType === 'target') {
- target.addDraggable(this);
- } else {
- this.x = target.x;
- this.y = target.y;
- }
-
- this.zIndex = 1000;
- this.correctZIndexes();
-
- Targets.initializeTargetField(this);
-
- if (this.isOriginal === true) {
- this.state.numDraggablesInSlider -= 1;
- this.state.updateArrowOpacity();
- }
-
- if ($.isFunction(funcCallback) === true) {
- funcCallback();
- }
- },
-
- // At this point the mouse was realeased, and we need to check
- // where the draggable eneded up. Based on several things, we
- // will either move the draggable back to the slider, or update
- // the input with the user's answer (X-Y position of the draggable,
- // or the ID of the target where it landed.
- checkLandingElement: function() {
- var positionIE;
-
- this.mousePressed = false;
- positionIE = this.iconEl.position();
-
- if (this.state.config.individualTargets === true) {
- if (this.checkIfOnTarget(positionIE) === true) {
- this.correctZIndexes();
-
- Targets.initializeTargetField(this);
- } else {
- if (this.onTarget !== null) {
- this.onTarget.removeDraggable(this);
- }
-
- this.moveBackToSlider();
-
- if (this.isOriginal === true) {
- this.state.numDraggablesInSlider += 1;
- }
- }
- } else {
- if (
- (positionIE.left < 0)
- || (positionIE.left + this.iconWidth > this.state.baseImageEl.width())
- || (positionIE.top < 0)
- || (positionIE.top + this.iconHeight > this.state.baseImageEl.height())
- ) {
- this.moveBackToSlider();
-
- this.x = -1;
- this.y = -1;
-
- if (this.isOriginal === true) {
- this.state.numDraggablesInSlider += 1;
- }
- } else {
- this.correctZIndexes();
-
- this.x = positionIE.left + this.iconWidth * 0.5;
- this.y = positionIE.top + this.iconHeight * 0.5;
-
- Targets.initializeTargetField(this);
- }
- }
-
- if (this.isOriginal === true) {
- this.state.updateArrowOpacity();
- }
- updateInput.update(this.state);
- },
-
- // Determine if a draggable, after it was relased, ends up on a
- // target. We do this by iterating over all of the targets, and
- // for each one we check whether the draggable's center is
- // within the target's dimensions.
- //
- // positionIE is the object as returned by
- //
- // this.iconEl.position()
- checkIfOnTarget: function(positionIE) {
- var c1, target;
-
- for (c1 = 0; c1 < this.state.targets.length; c1 += 1) {
- target = this.state.targets[c1];
-
- // If only one draggable per target is allowed, and
- // the current target already has a draggable on it
- // (with an ID different from the one we are checking
- // against), then go to next target.
- if (
- (this.state.config.onePerTarget === true)
- && (target.draggableList.length === 1)
- && (target.draggableList[0].uniqueId !== this.uniqueId)
- ) {
- // eslint-disable-next-line no-continue
- continue;
- }
-
- // If the target is on a draggable (from target field), we must make sure that
- // this draggable is not the same as "this" one.
- if ((target.type === 'on_drag') && (target.draggableObj.uniqueId === this.uniqueId)) {
- // eslint-disable-next-line no-continue
- continue;
- }
-
- // Check if the draggable's center coordinate is within
- // the target's dimensions. If not, go to next target.
- if (
- (positionIE.top + this.iconHeight * 0.5 < target.offset.top)
- || (positionIE.top + this.iconHeight * 0.5 > target.offset.top + target.h)
- || (positionIE.left + this.iconWidth * 0.5 < target.offset.left)
- || (positionIE.left + this.iconWidth * 0.5 > target.offset.left + target.w)
- ) {
- // eslint-disable-next-line no-continue
- continue;
- }
-
- // If the draggable was moved from one target to
- // another, then we need to remove it from the
- // previous target's draggables list, and add it to the
- // new target's draggables list.
- if ((this.onTarget !== null) && (this.onTarget.uniqueId !== target.uniqueId)) {
- this.onTarget.removeDraggable(this);
- target.addDraggable(this);
- // eslint-disable-next-line brace-style
- }
- // If the draggable was moved from the slider to a
- // target, remember the target, and add ID to the
- // target's draggables list.
- else if (this.onTarget === null) {
- target.addDraggable(this);
- }
-
- // Reposition the draggable so that it's center
- // coincides with the center of the target.
- this.snapToTarget(target);
-
- // Target was found.
- return true;
- }
-
- // Target was not found.
- return false;
- },
-
- toggleTargets: function(isEnabled) {
- var effect = isEnabled ? 'move' : null;
-
- this.state.baseImageEl.attr('aria-dropeffect', effect);
- $.each(this.state.targets, function(index, target) {
- target.targetEl.attr('aria-dropeffect', effect);
- });
- },
-
- snapToTarget: function(target) {
- var offset;
-
- offset = 0;
- if (this.state.config.targetOutline === true) {
- offset = 1;
- }
-
- this.iconEl.css({
- left: target.offset.left + 0.5 * target.w - this.iconWidth * 0.5 + offset - this.iconElLeftOffset,
- top: target.offset.top + 0.5 * target.h - this.iconHeight * 0.5 + offset
- });
-
- if (this.labelEl !== null) {
- this.labelEl.css({
- left: target.offset.left + 0.5 * target.w - this.labelWidth * 0.5 + offset - 9, // Acoount for padding, border.
- top: target.offset.top + 0.5 * target.h + this.iconHeight * 0.5 + 5 + offset
- });
- }
- },
-
- // Go through all of the draggables subtract 1 from the z-index
- // of all whose z-index is higher than the old z-index of the
- // current element. After, set the z-index of the current
- // element to 1 + N (where N is the number of draggables - i.e.
- // the highest z-index possible).
- //
- // This will make sure that after releasing a draggable, it
- // will be on top of all of the other draggables. Also, the
- // ordering of the visibility (z-index) of the other draggables
- // will not change.
- correctZIndexes: function() {
- var c1, highestZIndex;
-
- highestZIndex = -10000;
-
- if (this.state.config.individualTargets === true) {
- if (this.onTarget.draggableList.length > 0) {
- for (c1 = 0; c1 < this.onTarget.draggableList.length; c1 += 1) {
- if (
- (this.onTarget.draggableList[c1].zIndex > highestZIndex)
- && (this.onTarget.draggableList[c1].zIndex !== 1000)
- ) {
- highestZIndex = this.onTarget.draggableList[c1].zIndex;
- }
- }
- } else {
- highestZIndex = 0;
- }
- } else {
- for (c1 = 0; c1 < this.state.draggables.length; c1++) {
- if (this.inContainer === false) {
- if (
- (this.state.draggables[c1].zIndex > highestZIndex)
- && (this.state.draggables[c1].zIndex !== 1000)
- ) {
- highestZIndex = this.state.draggables[c1].zIndex;
- }
- }
- }
- }
-
- if (highestZIndex === -10000) {
- highestZIndex = 0;
- }
-
- this.zIndex = highestZIndex + 1;
-
- this.iconEl.css('z-index', this.zIndex);
- if (this.labelEl !== null) {
- this.labelEl.css('z-index', this.zIndex);
- }
- },
-
- // If a draggable was released in a wrong positione, we will
- // move it back to the slider, placing it in the same position
- // that it was dragged out of.
- moveBackToSlider: function() {
- var c1;
-
- Targets.destroyTargetField(this);
-
- if (this.isOriginal === false) {
- this.iconEl.remove();
- if (this.labelEl !== null) {
- this.labelEl.remove();
- }
-
- this.state.draggables.splice(this.stateDraggablesIndex, 1);
-
- for (c1 = 0; c1 < this.state.draggables.length; c1 += 1) {
- if (this.state.draggables[c1].stateDraggablesIndex > this.stateDraggablesIndex) {
- this.state.draggables[c1].stateDraggablesIndex -= 1;
- }
- }
-
- return;
- }
-
- this.containerEl.show();
- this.zIndex = 1;
-
- this.iconEl.detach();
- if (this.iconImgEl !== null) {
- this.iconImgEl.css({
- width: this.iconWidthSmall,
- height: this.iconHeightSmall
- });
- }
- this.iconEl.css({
- border: 'none',
- 'background-color': 'transparent',
- 'padding-left': 0,
- 'padding-right': 0,
- 'z-index': this.zIndex,
- width: this.iconWidthSmall,
- height: this.iconHeightSmall,
- left: 50 - this.iconWidthSmall * 0.5,
-
- // Before:
- // 'top': ((this.labelEl !== null) ? (100 - this.iconHeightSmall - 25) * 0.5 : 50 - this.iconHeightSmall * 0.5)
- // After:
- top: ((this.labelEl !== null) ? 37.5 : 50.0) - 0.5 * this.iconHeightSmall
- });
- this.iconEl.appendTo(this.containerEl);
-
- if (this.labelEl !== null) {
- this.labelEl.detach();
- this.labelEl.css({
- border: 'none',
- 'background-color': 'transparent',
- 'padding-left': 0,
- 'padding-right': 0,
- 'z-index': this.zIndex,
- left: 50 - this.labelWidth * 0.5,
-
- // Before:
- // 'top': (100 - this.iconHeightSmall - 25) * 0.5 + this.iconHeightSmall + 5
- // After:
- top: 42.5 + 0.5 * this.iconHeightSmall
- });
- this.labelEl.appendTo(this.containerEl);
- }
-
- this.inContainer = true;
- }
- }; // End-of: return {
- }); // End-of: define(['update_input', 'targets'], function (updateInput, Targets) {
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
diff --git a/common/static/js/capa/drag_and_drop/draggables.js b/common/static/js/capa/drag_and_drop/draggables.js
deleted file mode 100644
index 13e26c28de49..000000000000
--- a/common/static/js/capa/drag_and_drop/draggables.js
+++ /dev/null
@@ -1,281 +0,0 @@
-(function(requirejs, require, define) {
- define(['js/capa/drag_and_drop/draggable_events', 'js/capa/drag_and_drop/draggable_logic',
- 'edx-ui-toolkit/js/utils/html-utils'],
- function(draggableEvents, draggableLogic, HtmlUtils) {
- return {
- init: init
- };
-
- function init(state) {
- state.config.draggables.every(function(draggable) {
- processDraggable(state, draggable);
-
- return true;
- });
- }
-
- function makeDraggableCopy(callbackFunc) {
- var draggableObj, property;
-
- // Make a full proper copy of the draggable object, with some modifications.
- draggableObj = {};
- for (property in this) {
- if (this.hasOwnProperty(property) === true) {
- draggableObj[property] = this[property];
- }
- }
- // The modifications to the draggable copy.
- draggableObj.isOriginal = false; // This new draggable is a copy.
- draggableObj.uniqueId = draggableObj.state.getUniqueId(); // Is newly set.
- draggableObj.stateDraggablesIndex = null; // Will be set.
- draggableObj.containerEl = null; // Not needed, since a copy will never return to a container element.
- draggableObj.iconEl = null; // Will be created.
- draggableObj.iconImgEl = null; // Will be created.
- draggableObj.labelEl = null; // Will be created.
- draggableObj.targetField = []; // Will be populated.
-
- // Create DOM elements and attach events.
- if (draggableObj.originalConfigObj.icon.length > 0) {
- draggableObj.iconEl = $('');
- draggableObj.iconImgEl = $('
');
- draggableObj.iconImgEl.attr('src', draggableObj.originalConfigObj.icon);
- draggableObj.iconImgEl.load(function() {
- draggableObj.iconEl.css({
- position: 'absolute',
- width: draggableObj.iconWidthSmall,
- height: draggableObj.iconHeightSmall,
- left: 50 - draggableObj.iconWidthSmall * 0.5,
- top: ((draggableObj.originalConfigObj.label.length > 0) ? 5 : 50 - draggableObj.iconHeightSmall * 0.5)
- });
- draggableObj.iconImgEl.css({
- position: 'absolute',
- width: draggableObj.iconWidthSmall,
- height: draggableObj.iconHeightSmall,
- left: 0,
- top: 0
- });
- draggableObj.iconImgEl.appendTo(draggableObj.iconEl);
-
- if (draggableObj.originalConfigObj.label.length > 0) {
- draggableObj.labelEl = $(HtmlUtils.joinHtml(
- HtmlUtils.HTML(
- ''
- ),
- draggableObj.originalConfigObj.label,
- HtmlUtils.HTML('
')
- ).toString());
- draggableObj.labelEl.css({
- left: 50 - draggableObj.labelWidth * 0.5,
- top: 5 + draggableObj.iconHeightSmall + 5
- });
-
- draggableObj.attachMouseEventsTo('labelEl');
- }
-
- draggableObj.attachMouseEventsTo('iconEl');
-
- draggableObj.stateDraggablesIndex = draggableObj.state.draggables.push(draggableObj) - 1;
-
- setTimeout(function() {
- callbackFunc(draggableObj);
- }, 0);
- });
- } else {
- if (draggableObj.originalConfigObj.label.length > 0) {
- draggableObj.iconEl = $(HtmlUtils.joinHtml(
- HtmlUtils.HTML(''),
- draggableObj.originalConfigObj.label,
- HtmlUtils.HTML('
')
- ).toString());
- draggableObj.iconEl.css({
- left: 50 - draggableObj.iconWidthSmall * 0.5,
- top: 50 - draggableObj.iconHeightSmall * 0.5
- });
-
- draggableObj.attachMouseEventsTo('iconEl');
-
- draggableObj.stateDraggablesIndex = draggableObj.state.draggables.push(draggableObj) - 1;
-
- setTimeout(function() {
- callbackFunc(draggableObj);
- }, 0);
- }
- }
- }
-
- function processDraggable(state, obj) {
- var draggableObj;
-
- draggableObj = {
- uniqueId: state.getUniqueId(),
- originalConfigObj: obj,
- stateDraggablesIndex: null,
- id: obj.id,
- isReusable: obj.can_reuse,
- isOriginal: true,
- x: -1,
- y: -1,
- zIndex: 1,
- containerEl: null,
- iconEl: null,
- iconImgEl: null,
- iconElBGColor: null,
- iconElPadding: null,
- iconElBorder: null,
- iconElLeftOffset: null,
- iconWidth: null,
- iconHeight: null,
- iconWidthSmall: null,
- iconHeightSmall: null,
- labelEl: null,
- labelWidth: null,
- hasLoaded: false,
- inContainer: true,
- mousePressed: false,
- onTarget: null,
- onTargetIndex: null,
- state: state,
-
- mouseDown: draggableEvents.mouseDown,
- mouseUp: draggableEvents.mouseUp,
- mouseMove: draggableEvents.mouseMove,
-
- checkLandingElement: draggableLogic.checkLandingElement,
- checkIfOnTarget: draggableLogic.checkIfOnTarget,
- snapToTarget: draggableLogic.snapToTarget,
- correctZIndexes: draggableLogic.correctZIndexes,
- moveBackToSlider: draggableLogic.moveBackToSlider,
- moveDraggableTo: draggableLogic.moveDraggableTo,
- toggleTargets: draggableLogic.toggleTargets,
-
- makeDraggableCopy: makeDraggableCopy,
-
- attachMouseEventsTo: draggableEvents.attachMouseEventsTo,
-
- targetField: [],
- numDraggablesOnMe: 0
- };
-
- draggableObj.containerEl = $(HtmlUtils.joinHtml(
- HtmlUtils.HTML('')
- ).toString());
-
- draggableObj.containerEl.appendTo(state.sliderEl);
-
- if (obj.icon.length > 0) {
- draggableObj.iconElBGColor = 'transparent';
- draggableObj.iconElPadding = 0;
- draggableObj.iconElBorder = 'none';
- draggableObj.iconElLeftOffset = 0;
-
- draggableObj.iconEl = $('');
-
- draggableObj.iconImgEl = $('
');
- draggableObj.iconImgEl.attr('src', obj.icon);
- draggableObj.iconImgEl.load(function() {
- draggableObj.iconWidth = this.width;
- draggableObj.iconHeight = this.height;
-
- if (draggableObj.iconWidth >= draggableObj.iconHeight) {
- draggableObj.iconWidthSmall = 60;
- draggableObj.iconHeightSmall = draggableObj.iconWidthSmall * (draggableObj.iconHeight / draggableObj.iconWidth);
- } else {
- draggableObj.iconHeightSmall = 60;
- draggableObj.iconWidthSmall = draggableObj.iconHeightSmall * (draggableObj.iconWidth / draggableObj.iconHeight);
- }
-
- draggableObj.iconEl.css({
- position: 'absolute',
- width: draggableObj.iconWidthSmall,
- height: draggableObj.iconHeightSmall,
- left: 50 - draggableObj.iconWidthSmall * 0.5,
-
- // Before:
- // 'top': ((obj.label.length > 0) ? (100 - draggableObj.iconHeightSmall - 25) * 0.5 : 50 - draggableObj.iconHeightSmall * 0.5)
- // After:
- top: ((obj.label.length > 0) ? 37.5 : 50.0) - 0.5 * draggableObj.iconHeightSmall
- });
- draggableObj.iconImgEl.css({
- position: 'absolute',
- width: draggableObj.iconWidthSmall,
- height: draggableObj.iconHeightSmall,
- left: 0,
- top: 0
- });
- draggableObj.iconImgEl.appendTo(draggableObj.iconEl);
- draggableObj.iconEl.appendTo(draggableObj.containerEl);
-
- if (obj.label.length > 0) {
- draggableObj.labelEl = $(HtmlUtils.joinHtml(
- HtmlUtils.HTML(
- ''
- ),
- obj.label,
- HtmlUtils.HTML('
')
- ).toString());
-
- draggableObj.labelEl.appendTo(draggableObj.containerEl);
- draggableObj.labelWidth = draggableObj.labelEl.width();
- draggableObj.labelEl.css({
- left: 50 - draggableObj.labelWidth * 0.5,
-
- // Before:
- // 'top': (100 - this.iconHeightSmall - 25) * 0.5 + this.iconHeightSmall + 5
- // After:
- top: 42.5 + 0.5 * draggableObj.iconHeightSmall
- });
-
- draggableObj.attachMouseEventsTo('labelEl');
- }
-
- draggableObj.hasLoaded = true;
- });
- } else {
- // To make life easier, if there is no icon, but there is a
- // label, we will create a label and store it as if it was an
- // icon. All the existing code will work, and the user will
- // see a label instead of an icon.
- if (obj.label.length > 0) {
- draggableObj.iconElBGColor = state.config.labelBgColor;
- draggableObj.iconElPadding = 8;
- draggableObj.iconElBorder = '1px solid black';
- draggableObj.iconElLeftOffset = 9;
-
- draggableObj.iconEl = $(HtmlUtils.joinHtml(
- HtmlUtils.HTML(
- ''),
- obj.label,
- HtmlUtils.HTML('
')
- ).toString());
-
- draggableObj.iconEl.appendTo(draggableObj.containerEl);
-
- draggableObj.iconWidth = draggableObj.iconEl.width() + 1;
- draggableObj.iconHeight = draggableObj.iconEl.height();
- draggableObj.iconWidthSmall = draggableObj.iconWidth;
- draggableObj.iconHeightSmall = draggableObj.iconHeight;
-
- draggableObj.iconEl.css({
- left: 50 - draggableObj.iconWidthSmall * 0.5,
- top: 50 - draggableObj.iconHeightSmall * 0.5
- });
-
- draggableObj.hasLoaded = true;
- } else {
- // If no icon and no label, don't create a draggable.
- return;
- }
- }
-
- draggableObj.attachMouseEventsTo('iconEl');
- draggableObj.attachMouseEventsTo('containerEl');
-
- state.numDraggablesInSlider += 1;
- draggableObj.stateDraggablesIndex = state.draggables.push(draggableObj) - 1;
- }
- }); // End-of: define(['draggable_events', 'draggable_logic'], function (draggableEvents, draggableLogic) {
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
diff --git a/common/static/js/capa/drag_and_drop/main.js b/common/static/js/capa/drag_and_drop/main.js
deleted file mode 100644
index 3cd15971bfd6..000000000000
--- a/common/static/js/capa/drag_and_drop/main.js
+++ /dev/null
@@ -1,107 +0,0 @@
-(function(requirejs, require, define) {
- define(
- ['js/capa/drag_and_drop/state',
- 'js/capa/drag_and_drop/config_parser', 'js/capa/drag_and_drop/container',
- 'js/capa/drag_and_drop/base_image', 'js/capa/drag_and_drop/scroller',
- 'js/capa/drag_and_drop/draggables', 'js/capa/drag_and_drop/targets',
- 'js/capa/drag_and_drop/update_input'],
- function(State, configParser, Container, BaseImage, Scroller, Draggables, Targets, updateInput) {
- return Main;
-
- function Main() {
- // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/every
- //
- // Array.prototype.every is a recent addition to the ECMA-262 standard; as such it may not be present in
- // other implementations of the standard.
- if (!Array.prototype.every) {
- // eslint-disable-next-line no-extend-native
- Array.prototype.every = function(fun /* , thisp */) {
- var thisp, t, len, i;
-
- if (this == null) {
- throw new TypeError();
- }
-
- t = Object(this);
- // eslint-disable-next-line no-bitwise
- len = t.length >>> 0;
- if (typeof fun !== 'function') {
- throw new TypeError();
- }
-
- thisp = arguments[1];
-
- for (i = 0; i < len; i++) {
- if (i in t && !fun.call(thisp, t[i], i, t)) {
- return false;
- }
- }
-
- return true;
- };
- }
-
- $('.drag_and_drop_problem_div').each(processProblem);
- }
-
- // $(value) - get the element of the entire problem
- function processProblem(index, value) {
- var problemId, config, state;
-
- if ($(value).attr('data-problem-processed') === 'true') {
- // This problem was already processed by us before, so we will
- // skip it.
-
- return;
- }
- $(value).attr('data-problem-processed', 'true');
-
- problemId = $(value).attr('data-plain-id');
- if (typeof problemId !== 'string') {
- console.log('ERROR: Could not find the ID of the problem DOM element.');
-
- return;
- }
-
- try {
- config = JSON.parse($('#drag_and_drop_json_' + problemId).html());
- } catch (err) {
- console.log('ERROR: Could not parse the JSON configuration options.');
- console.log('Error message: "' + err.message + '".');
-
- return;
- }
-
- state = State(problemId);
-
- if (configParser(state, config) !== true) {
- console.log('ERROR: Could not make sense of the JSON configuration options.');
-
- return;
- }
-
- Container(state);
- BaseImage(state);
-
- (function addContent() {
- if (state.baseImageLoaded !== true) {
- setTimeout(addContent, 50);
-
- return;
- }
-
- Targets.initializeBaseTargets(state);
- Scroller(state);
- Draggables.init(state);
-
- state.updateArrowOpacity();
-
- // Update the input element, checking first that it is not filled with
- // an answer from the server.
- if (updateInput.check(state) === false) {
- updateInput.update(state);
- }
- }());
- }
- }); // End-of: define(
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
diff --git a/common/static/js/capa/drag_and_drop/scroller.js b/common/static/js/capa/drag_and_drop/scroller.js
deleted file mode 100644
index eb6646141d3d..000000000000
--- a/common/static/js/capa/drag_and_drop/scroller.js
+++ /dev/null
@@ -1,162 +0,0 @@
-(function(requirejs, require, define) {
- define(['edx-ui-toolkit/js/utils/html-utils'], function(HtmlUtils) {
- return Scroller;
-
- function Scroller(state) {
- var $parentEl, $moveLeftEl, $showEl, $moveRightEl, showElLeftMargin;
-
- $parentEl = $(HtmlUtils.HTML(
- ''
- ).toString());
-
- $moveLeftEl = $(HtmlUtils.joinHtml(
- HtmlUtils.HTML(''),
- HtmlUtils.HTML('
'),
- HtmlUtils.HTML('
'),
- HtmlUtils.HTML('
')
- ).toString());
- $moveLeftEl.appendTo($parentEl);
-
- // The below is necessary to prevent the browser thinking that we want
- // to perform a drag operation, or a highlight operation. If we don't
- // do this, the browser will then highlight with a gray shade the
- // element.
- $moveLeftEl.mousemove(function(event) { event.preventDefault(); });
- $moveLeftEl.mousedown(function(event) { event.preventDefault(); });
-
- // This event will be responsible for moving the scroller left.
- // Hidden draggables will be shown.
- $moveLeftEl.mouseup(function(event) {
- event.preventDefault();
-
- // When there are no more hidden draggables, prevent from
- // scrolling infinitely.
- if (showElLeftMargin > -102) {
- return;
- }
-
- showElLeftMargin += 102;
-
- // We scroll by changing the 'margin-left' CSS property smoothly.
- state.sliderEl.animate({
- 'margin-left': showElLeftMargin + 'px'
- }, 100, function() {
- updateArrowOpacity();
- });
- });
-
- $showEl = $(HtmlUtils.HTML(
- ''
- ).toString());
- $showEl.appendTo($parentEl);
-
- showElLeftMargin = 0;
-
- // Element where the draggables will be contained. It is very long
- // so that any SANE number of draggables will fit in a single row. It
- // will be contained in a parent element whose 'overflow' CSS value
- // will be hidden, preventing the long row from fully being visible.
- // eslint-disable-next-line no-param-reassign
- state.sliderEl = $(HtmlUtils.joinHtml(
- HtmlUtils.HTML('')
- ).toString());
- state.sliderEl.appendTo($showEl);
-
- state.sliderEl.mousedown(function(event) {
- event.preventDefault();
- });
-
- $moveRightEl = $(HtmlUtils.joinHtml(
- HtmlUtils.HTML(''),
- HtmlUtils.HTML('
'),
- HtmlUtils.HTML('
'),
- HtmlUtils.HTML('
')
- ).toString());
- $moveRightEl.appendTo($parentEl);
-
- // The below is necessary to prevent the browser thinking that we want
- // to perform a drag operation, or a highlight operation. If we don't
- // do this, the browser will then highlight with a gray shade the
- // element.
- $moveRightEl.mousemove(function(event) { event.preventDefault(); });
- $moveRightEl.mousedown(function(event) { event.preventDefault(); });
-
- // This event will be responsible for moving the scroller right.
- // Hidden draggables will be shown.
- $moveRightEl.mouseup(function(event) {
- event.preventDefault();
-
- // When there are no more hidden draggables, prevent from
- // scrolling infinitely.
- if (showElLeftMargin < -102 * (state.numDraggablesInSlider - 6)) {
- return;
- }
-
- showElLeftMargin -= 102;
-
- // We scroll by changing the 'margin-left' CSS property smoothly.
- state.sliderEl.animate({
- 'margin-left': showElLeftMargin + 'px'
- }, 100, function() {
- updateArrowOpacity();
- });
- });
-
- $parentEl.appendTo(state.containerEl);
-
- // Make the function available throughout the application. We need to
- // call it in several places:
- //
- // 1.) When initially reading answer from server, if draggables will be
- // positioned on the base image, the scroller's right and left arrows
- // opacity must be updated.
- //
- // 2.) When creating draggable elements, the scroller's right and left
- // arrows opacity must be updated according to the number of
- // draggables.
- state.updateArrowOpacity = updateArrowOpacity;
-
- // eslint-disable-next-line no-useless-return
- return;
-
- function updateArrowOpacity() {
- $moveLeftEl.children('div').css('opacity', '1');
- $moveRightEl.children('div').css('opacity', '1');
-
- if (showElLeftMargin < -102 * (state.numDraggablesInSlider - 6)) {
- $moveRightEl.children('div').css('opacity', '.4');
- }
- if (showElLeftMargin > -102) {
- $moveLeftEl.children('div').css('opacity', '.4');
- }
- }
- } // End-of: function Scroller(state)
- }); // End-of: define([], function () {
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
diff --git a/common/static/js/capa/drag_and_drop/state.js b/common/static/js/capa/drag_and_drop/state.js
deleted file mode 100644
index 6ea9d5b62374..000000000000
--- a/common/static/js/capa/drag_and_drop/state.js
+++ /dev/null
@@ -1,95 +0,0 @@
-(function(requirejs, require, define) {
- define([], function() {
- return State;
-
- function State(problemId) {
- var state;
-
- state = {
- config: null,
-
- baseImageEl: null,
- baseImageLoaded: false,
-
- containerEl: null,
-
- sliderEl: null,
-
- problemId: problemId,
-
- draggables: [],
- numDraggablesInSlider: 0,
- currentMovingDraggable: null,
-
- targets: [],
-
- updateArrowOpacity: null,
-
- uniqueId: 0,
- salt: makeSalt(),
-
- getUniqueId: getUniqueId
- };
-
- $(document).mousemove(function(event) {
- documentMouseMove(state, event);
- });
-
- return state;
- }
-
- function getUniqueId() {
- this.uniqueId += 1;
-
- return this.salt + '_' + this.uniqueId.toFixed(0);
- }
-
- function makeSalt() {
- var text, possible, i;
-
- text = '';
- possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
-
- for (i = 0; i < 5; i += 1) {
- text += possible.charAt(Math.floor(Math.random() * possible.length));
- }
-
- return text;
- }
-
- function documentMouseMove(state, event) {
- if (state.currentMovingDraggable !== null) {
- state.currentMovingDraggable.iconEl.css(
- 'left',
- event.pageX
- - state.baseImageEl.offset().left
- - state.currentMovingDraggable.iconWidth * 0.5
- - state.currentMovingDraggable.iconElLeftOffset
- );
- state.currentMovingDraggable.iconEl.css(
- 'top',
- event.pageY
- - state.baseImageEl.offset().top
- - state.currentMovingDraggable.iconHeight * 0.5
- );
-
- if (state.currentMovingDraggable.labelEl !== null) {
- state.currentMovingDraggable.labelEl.css(
- 'left',
- event.pageX
- - state.baseImageEl.offset().left
- - state.currentMovingDraggable.labelWidth * 0.5
- - 9 // Account for padding, border.
- );
- state.currentMovingDraggable.labelEl.css(
- 'top',
- event.pageY
- - state.baseImageEl.offset().top
- + state.currentMovingDraggable.iconHeight * 0.5
- + 5
- );
- }
- }
- }
- }); // End-of: define([], function () {
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
diff --git a/common/static/js/capa/drag_and_drop/targets.js b/common/static/js/capa/drag_and_drop/targets.js
deleted file mode 100644
index 553053fbc063..000000000000
--- a/common/static/js/capa/drag_and_drop/targets.js
+++ /dev/null
@@ -1,266 +0,0 @@
-(function(requirejs, require, define) {
- define(['edx-ui-toolkit/js/utils/html-utils'], function(HtmlUtils) {
- return {
- initializeBaseTargets: initializeBaseTargets,
- initializeTargetField: initializeTargetField,
- destroyTargetField: destroyTargetField
- };
-
- function initializeBaseTargets(state) {
- (function(c1) {
- while (c1 < state.config.targets.length) {
- processTarget(state, state.config.targets[c1]);
-
- c1 += 1;
- }
- }(0));
- }
-
- function initializeTargetField(draggableObj) {
- var iconElOffset;
-
- if (draggableObj.targetField.length === 0) {
- draggableObj.originalConfigObj.target_fields.every(function(targetObj) {
- processTarget(draggableObj.state, targetObj, true, draggableObj);
-
- return true;
- });
- } else {
- iconElOffset = draggableObj.iconEl.position();
-
- draggableObj.targetField.every(function(targetObj) {
- targetObj.offset.top = iconElOffset.top + targetObj.y;
- targetObj.offset.left = iconElOffset.left + targetObj.x;
-
- return true;
- });
- }
- }
-
- function destroyTargetField(draggableObj) {
- var indexOffset, lowestRemovedIndex;
-
- indexOffset = 0;
- lowestRemovedIndex = draggableObj.state.targets.length + 1;
-
- draggableObj.targetField.every(function(target) {
- target.el.remove();
-
- if (lowestRemovedIndex > target.indexInStateArray) {
- lowestRemovedIndex = target.indexInStateArray;
- }
-
- draggableObj.state.targets.splice(target.indexInStateArray - indexOffset, 1);
- indexOffset += 1;
-
- return true;
- });
-
- draggableObj.state.targets.every(function(target) {
- if (target.indexInStateArray > lowestRemovedIndex) {
- target.indexInStateArray -= indexOffset;
- }
-
- return true;
- });
-
- draggableObj.targetField = [];
- }
-
- function processTarget(state, obj, fromTargetField, draggableObj) {
- var $targetEl, borderCss, $numTextEl, targetObj;
-
- borderCss = '';
- if (state.config.targetOutline === true) {
- borderCss = 'border: 1px dashed gray; ';
- }
-
- $targetEl = $(
- HtmlUtils.joinHtml(
- HtmlUtils.HTML('')
- ).toString()
- );
- if (fromTargetField === true) {
- $targetEl.appendTo(draggableObj.iconEl);
- } else {
- $targetEl.appendTo(state.baseImageEl.parent());
- }
-
- $targetEl.mousedown(function(event) {
- event.preventDefault();
- });
-
- if (state.config.onePerTarget === false) {
- $numTextEl = $(
- HtmlUtils.joinHtml(
- HtmlUtils.HTML('0
')
- ).toString()
- );
- } else {
- $numTextEl = null;
- }
-
- targetObj = {
- uniqueId: state.getUniqueId(),
-
- id: obj.id,
-
- x: obj.x,
- y: obj.y,
-
- w: obj.w,
- h: obj.h,
-
- el: $targetEl,
- offset: $targetEl.position(),
-
- draggableList: [],
-
- state: state,
-
- targetEl: $targetEl,
-
- numTextEl: $numTextEl,
- updateNumTextEl: updateNumTextEl,
-
- removeDraggable: removeDraggable,
- addDraggable: addDraggable,
-
- type: 'base',
- draggableObj: null
- };
-
- if (fromTargetField === true) {
- targetObj.offset = draggableObj.iconEl.position();
- targetObj.offset.top += obj.y;
- targetObj.offset.left += obj.x;
-
- targetObj.type = 'on_drag';
- targetObj.draggableObj = draggableObj;
- }
-
- if (state.config.onePerTarget === false) {
- $numTextEl.appendTo(state.baseImageEl.parent());
- $numTextEl.mousedown(function(event) {
- event.preventDefault();
- });
- $numTextEl.mouseup(function() {
- cycleDraggableOrder.call(targetObj);
- });
- }
-
- targetObj.indexInStateArray = state.targets.push(targetObj) - 1;
-
- if (fromTargetField === true) {
- draggableObj.targetField.push(targetObj);
- }
- }
-
- function removeDraggable(draggable) {
- var c1;
-
- this.draggableList.splice(draggable.onTargetIndex, 1);
-
- // An item from the array was removed. We need to updated all indexes accordingly.
- // Shift all indexes down by one if they are higher than the index of the removed item.
- c1 = 0;
- while (c1 < this.draggableList.length) {
- if (this.draggableList[c1].onTargetIndex > draggable.onTargetIndex) {
- this.draggableList[c1].onTargetIndex -= 1;
- }
-
- c1 += 1;
- }
-
- draggable.onTarget = null;
- draggable.onTargetIndex = null;
-
- if (this.type === 'on_drag') {
- this.draggableObj.numDraggablesOnMe -= 1;
- }
-
- this.updateNumTextEl();
- }
-
- function addDraggable(draggable) {
- draggable.onTarget = this;
- draggable.onTargetIndex = this.draggableList.push(draggable) - 1;
-
- if (this.type === 'on_drag') {
- this.draggableObj.numDraggablesOnMe += 1;
- }
-
- this.updateNumTextEl();
- }
-
- /*
- * function cycleDraggableOrder
- *
- * Parameters:
- * none - This function does not expect any parameters.
- *
- * Returns:
- * undefined - The return value of this function is not used.
- *
- * Description:
- * Go through all draggables that are on the current target, and decrease their
- * z-index by 1, making sure that the bottom-most draggable ends up on the top.
- */
- function cycleDraggableOrder() {
- var c1, lowestZIndex, highestZIndex;
-
- if (this.draggableList.length < 2) {
- return;
- }
-
- highestZIndex = -10000;
- lowestZIndex = 10000;
-
- for (c1 = 0; c1 < this.draggableList.length; c1 += 1) {
- if (this.draggableList[c1].zIndex < lowestZIndex) {
- lowestZIndex = this.draggableList[c1].zIndex;
- }
-
- if (this.draggableList[c1].zIndex > highestZIndex) {
- highestZIndex = this.draggableList[c1].zIndex;
- }
- }
-
- for (c1 = 0; c1 < this.draggableList.length; c1 += 1) {
- if (this.draggableList[c1].zIndex === lowestZIndex) {
- this.draggableList[c1].zIndex = highestZIndex;
- } else {
- this.draggableList[c1].zIndex -= 1;
- }
-
- this.draggableList[c1].iconEl.css('z-index', this.draggableList[c1].zIndex);
- if (this.draggableList[c1].labelEl !== null) {
- this.draggableList[c1].labelEl.css('z-index', this.draggableList[c1].zIndex);
- }
- }
- }
-
- function updateNumTextEl() {
- if (this.numTextEl !== null) {
- this.numTextEl.text(this.draggableList.length);
- }
- }
- }); // End-of: define([], function () {
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
diff --git a/common/static/js/capa/drag_and_drop/update_input.js b/common/static/js/capa/drag_and_drop/update_input.js
deleted file mode 100644
index c7769c4891ec..000000000000
--- a/common/static/js/capa/drag_and_drop/update_input.js
+++ /dev/null
@@ -1,373 +0,0 @@
-(function(requirejs, require, define) {
- define([], function() {
- return {
- check: check,
- update: update
- };
-
- function update(state) {
- var draggables, tempObj;
-
- draggables = [];
-
- if (state.config.individualTargets === false) {
- (function(c1) {
- while (c1 < state.draggables.length) {
- if (state.draggables[c1].x !== -1) {
- tempObj = {};
- tempObj[state.draggables[c1].id] = [
- state.draggables[c1].x,
- state.draggables[c1].y
- ];
- draggables.push(tempObj);
- tempObj = null;
- }
-
- c1 += 1;
- }
- }(0));
- } else {
- (function(c1) {
- while (c1 < state.targets.length) {
- // eslint-disable-next-line no-loop-func
- (function(c2) {
- while (c2 < state.targets[c1].draggableList.length) {
- tempObj = {};
-
- if (state.targets[c1].type === 'base') {
- tempObj[state.targets[c1].draggableList[c2].id] = state.targets[c1].id;
- } else {
- addTargetRecursively(tempObj, state.targets[c1].draggableList[c2], state.targets[c1]);
- }
- draggables.push(tempObj);
- tempObj = null;
-
- c2 += 1;
- }
- }(0));
-
- c1 += 1;
- }
- }(0));
- }
-
- $('#input_' + state.problemId).val(JSON.stringify(draggables));
- }
-
- function addTargetRecursively(tempObj, draggable, target) {
- if (target.type === 'base') {
- tempObj[draggable.id] = target.id;
- } else {
- tempObj[draggable.id] = {};
- tempObj[draggable.id][target.id] = {};
-
- addTargetRecursively(tempObj[draggable.id][target.id], target.draggableObj, target.draggableObj.onTarget);
- }
- }
-
- // Check if input has an answer from server. If yes, then position
- // all draggables according to answer.
- function check(state) {
- var inputElVal;
-
- inputElVal = $('#input_' + state.problemId).val();
-
- if (inputElVal.length === 0) {
- return false;
- }
-
- repositionDraggables(state, JSON.parse(inputElVal));
-
- return true;
- }
-
- function processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i) {
- var baseDraggableId, baseDraggable, baseTargetId, baseTarget,
- layeredDraggableId, layeredDraggable, layeredTargetId, layeredTarget,
- chain;
-
- if (depth === 0) {
- // We are at the lowest depth? The end.
-
- return;
- }
-
- if (answerSortedByDepth.hasOwnProperty(depth) === false) {
- // We have a depth that ts not valid, we decrease the depth by one.
- processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth - 1, 0);
-
- return;
- }
-
- if (answerSortedByDepth[depth].length <= i) {
- // We ran out of answers at this depth, go to the next depth down.
- processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth - 1, 0);
-
- return;
- }
-
- chain = answerSortedByDepth[depth][i];
-
- baseDraggableId = Object.keys(chain)[0];
-
- // This is a hack. For now we will work with depths 1 and 3.
- if (depth === 1) {
- baseTargetId = chain[baseDraggableId];
-
- layeredTargetId = null;
- layeredDraggableId = null;
-
- // createBaseDraggableOnTarget(state, baseDraggableId, baseTargetId);
- } else if (depth === 3) {
- layeredDraggableId = baseDraggableId;
-
- layeredTargetId = Object.keys(chain[layeredDraggableId])[0];
-
- baseDraggableId = Object.keys(chain[layeredDraggableId][layeredTargetId])[0];
-
- baseTargetId = chain[layeredDraggableId][layeredTargetId][baseDraggableId];
- }
-
- checkBaseDraggable();
-
- // eslint-disable-next-line no-useless-return
- return;
-
- function checkBaseDraggable() {
- // eslint-disable-next-line no-cond-assign
- if ((baseDraggable = getById(state, 'draggables', baseDraggableId, null, false, baseTargetId)) === null) {
- createBaseDraggableOnTarget(state, baseDraggableId, baseTargetId, true, function() {
- // eslint-disable-next-line no-cond-assign
- if ((baseDraggable = getById(state, 'draggables', baseDraggableId, null, false, baseTargetId)) === null) {
- console.log('ERROR: Could not successfully create a base draggable on a base target.');
- } else {
- baseTarget = baseDraggable.onTarget;
-
- if ((layeredTargetId === null) || (layeredDraggableId === null)) {
- processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
- } else {
- checklayeredDraggable();
- }
- }
- });
- } else {
- baseTarget = baseDraggable.onTarget;
-
- if ((layeredTargetId === null) || (layeredDraggableId === null)) {
- processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
- } else {
- checklayeredDraggable();
- }
- }
- }
-
- function checklayeredDraggable() {
- // eslint-disable-next-line no-cond-assign
- if ((layeredDraggable = getById(state, 'draggables', layeredDraggableId, null, false, layeredTargetId, baseDraggableId, baseTargetId)) === null) {
- layeredDraggable = getById(state, 'draggables', layeredDraggableId);
- layeredTarget = null;
- baseDraggable.targetField.every(function(target) {
- if (target.id === layeredTargetId) {
- layeredTarget = target;
- }
-
- return true;
- });
-
- if ((layeredDraggable !== null) && (layeredTarget !== null)) {
- layeredDraggable.moveDraggableTo('target', layeredTarget, function() {
- processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
- });
- } else {
- processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
- }
- } else {
- processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, depth, i + 1);
- }
- }
- }
-
- function createBaseDraggableOnTarget(state, draggableId, targetId, reportError, funcCallback) {
- var draggable, target;
-
- // eslint-disable-next-line no-cond-assign
- if ((draggable = getById(state, 'draggables', draggableId)) === null) {
- if (reportError !== false) {
- console.log(
- 'ERROR: In answer there exists a '
- + 'draggable ID "' + draggableId + '". No '
- + 'draggable with this ID could be found.'
- );
- }
-
- return false;
- }
-
- // eslint-disable-next-line no-cond-assign
- if ((target = getById(state, 'targets', targetId)) === null) {
- if (reportError !== false) {
- console.log(
- 'ERROR: In answer there exists a target '
- + 'ID "' + targetId + '". No target with this '
- + 'ID could be found.'
- );
- }
-
- return false;
- }
-
- draggable.moveDraggableTo('target', target, funcCallback);
-
- return true;
- }
-
- function processAnswerPositions(state, answer) {
- var draggableId, draggable;
-
- (function(c1) {
- while (c1 < answer.length) {
- for (draggableId in answer[c1]) {
- if (answer[c1].hasOwnProperty(draggableId) === false) {
- // eslint-disable-next-line no-continue
- continue;
- }
-
- // eslint-disable-next-line no-cond-assign
- if ((draggable = getById(state, 'draggables', draggableId)) === null) {
- console.log(
- 'ERROR: In answer there exists a '
- + 'draggable ID "' + draggableId + '". No '
- + 'draggable with this ID could be found.'
- );
-
- // eslint-disable-next-line no-continue
- continue;
- }
-
- draggable.moveDraggableTo('XY', {
- x: answer[c1][draggableId][0],
- y: answer[c1][draggableId][1]
- });
- }
-
- c1 += 1;
- }
- }(0));
- }
-
- function repositionDraggables(state, answer) {
- var answerSortedByDepth, minDepth, maxDepth;
-
- answerSortedByDepth = {};
- minDepth = 1000;
- maxDepth = 0;
-
- answer.every(function(chain) {
- var depth;
-
- depth = findDepth(chain, 0);
-
- if (depth < minDepth) {
- minDepth = depth;
- }
- if (depth > maxDepth) {
- maxDepth = depth;
- }
-
- if (answerSortedByDepth.hasOwnProperty(depth) === false) {
- answerSortedByDepth[depth] = [];
- }
-
- answerSortedByDepth[depth].push(chain);
-
- return true;
- });
-
- if (answer.length === 0) {
- return;
- }
-
- // For now we support only one case.
- if ((minDepth < 1) || (maxDepth > 3)) {
- return;
- }
-
- if (state.config.individualTargets === true) {
- processAnswerTargets(state, answerSortedByDepth, minDepth, maxDepth, maxDepth, 0);
- } else if (state.config.individualTargets === false) {
- processAnswerPositions(state, answer);
- }
- }
-
- function findDepth(tempObj, depth) {
- var i;
-
- if ($.isPlainObject(tempObj) === false) {
- return depth;
- }
-
- depth += 1;
-
- for (i in tempObj) {
- if (tempObj.hasOwnProperty(i) === true) {
- depth = findDepth(tempObj[i], depth);
- }
- }
-
- return depth;
- }
-
- function getById(state, type, id, fromTargetField, inContainer, targetId, baseDraggableId, baseTargetId) {
- return (function(c1) {
- while (c1 < state[type].length) {
- if (type === 'draggables') {
- if ((targetId !== undefined) && (inContainer === false) && (baseDraggableId !== undefined) && (baseTargetId !== undefined)) {
- if (
- (state[type][c1].id === id)
- && (state[type][c1].inContainer === false)
- && (state[type][c1].onTarget.id === targetId)
- && (state[type][c1].onTarget.type === 'on_drag')
- && (state[type][c1].onTarget.draggableObj.id === baseDraggableId)
- && (state[type][c1].onTarget.draggableObj.onTarget.id === baseTargetId)
- ) {
- return state[type][c1];
- }
- } else if ((targetId !== undefined) && (inContainer === false)) {
- if (
- (state[type][c1].id === id)
- && (state[type][c1].inContainer === false)
- && (state[type][c1].onTarget.id === targetId)
- ) {
- return state[type][c1];
- }
- } else {
- if (inContainer === false) {
- if ((state[type][c1].id === id) && (state[type][c1].inContainer === false)) {
- return state[type][c1];
- }
- } else {
- if ((state[type][c1].id === id) && (state[type][c1].inContainer === true)) {
- return state[type][c1];
- }
- }
- }
- } else { // 'targets'
- if (fromTargetField === true) {
- if ((state[type][c1].id === id) && (state[type][c1].type === 'on_drag')) {
- return state[type][c1];
- }
- } else {
- if ((state[type][c1].id === id) && (state[type][c1].type === 'base')) {
- return state[type][c1];
- }
- }
- }
-
- c1 += 1;
- }
-
- return null;
- }(0));
- }
- }); // End-of: define([], function () {
-}(RequireJS.requirejs, RequireJS.require, RequireJS.define)); // End-of: (function (requirejs, require, define) {
diff --git a/common/static/js/capa/edit-a-gene.js b/common/static/js/capa/edit-a-gene.js
deleted file mode 100644
index 0ef55a06fb12..000000000000
--- a/common/static/js/capa/edit-a-gene.js
+++ /dev/null
@@ -1,71 +0,0 @@
-(function() {
- var timeout = 1000;
-
- waitForGenex();
-
- function waitForGenex() {
- if (typeof genex !== 'undefined' && genex) {
- genex.onInjectionDone('genex');
- } else {
- setTimeout(function() { waitForGenex(); }, timeout);
- }
- }
-
- // NOTE:
- // Genex uses 8 global functions, all prefixed with genex:
- // 6 are exported from GWT:
- // genexSetDefaultDNASequence
- // genexSetDNASequence
- // genexGetDNASequence
- // genexSetClickEvent
- // genexSetKeyEvent
- // genexSetProblemNumber
- //
- // It calls genexIsReady with a deferred command when it has finished
- // initialization and has drawn itself
- // genexStoreAnswer(answer) is called each time the DNA sequence changes
- // through user interaction
-
- // Genex does not call the following function
- genexGetInputField = function() {
- var problem = $('#genex_container').parents('.problem');
- return problem.find('input[type="hidden"][name!="genex_dna_sequence"][name!="genex_problem_number"]');
- };
-
- genexIsReady = function() {
- var input_field = genexGetInputField();
- var genex_saved_state = input_field.val();
- var genex_default_dna_sequence;
- var genex_dna_sequence;
-
- // Get the DNA sequence from xml file
- genex_default_dna_sequence = $('#genex_dna_sequence').val();
- // Set the default DNA
- genexSetDefaultDNASequence(genex_default_dna_sequence);
-
- // Now load problem
- var genex_problem_number = $('#genex_problem_number').val();
- genexSetProblemNumber(genex_problem_number);
-
- // Set the DNA sequence that is displayed
- if (genex_saved_state === '') {
- // Load DNA sequence from xml file
- genex_dna_sequence = genex_default_dna_sequence;
- } else {
- // Load DNA sequence from saved value
- genex_saved_state = JSON.parse(genex_saved_state);
- genex_dna_sequence = genex_saved_state.genex_dna_sequence;
- }
- genexSetDNASequence(genex_dna_sequence);
-
- // Now load mouse and keyboard handlers
- genexSetClickEvent();
- genexSetKeyEvent();
- };
-
- genexStoreAnswer = function(answer) {
- var input_field = genexGetInputField();
- var value = {genex_dna_sequence: genexGetDNASequence(), genex_answer: answer};
- input_field.val(JSON.stringify(value));
- };
-}).call(this);
diff --git a/common/static/js/capa/fixtures/jsinput.html b/common/static/js/capa/fixtures/jsinput.html
deleted file mode 100644
index 039fe3d8d1df..000000000000
--- a/common/static/js/capa/fixtures/jsinput.html
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
diff --git a/common/static/js/capa/genex/21B31BA00E7CE7B6BD63DD13A8586A45.cache.html b/common/static/js/capa/genex/21B31BA00E7CE7B6BD63DD13A8586A45.cache.html
deleted file mode 100644
index ec8170eb4793..000000000000
--- a/common/static/js/capa/genex/21B31BA00E7CE7B6BD63DD13A8586A45.cache.html
+++ /dev/null
@@ -1,652 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/common/static/js/capa/genex/63308EE54E8033A708B414CAC05B0C32.cache.html b/common/static/js/capa/genex/63308EE54E8033A708B414CAC05B0C32.cache.html
deleted file mode 100644
index 952e3b5f37dc..000000000000
--- a/common/static/js/capa/genex/63308EE54E8033A708B414CAC05B0C32.cache.html
+++ /dev/null
@@ -1,642 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/common/static/js/capa/genex/7AC57DC6EC8C1D8672DDF6E6D4EF57CC.cache.html b/common/static/js/capa/genex/7AC57DC6EC8C1D8672DDF6E6D4EF57CC.cache.html
deleted file mode 100644
index 95cb962805c7..000000000000
--- a/common/static/js/capa/genex/7AC57DC6EC8C1D8672DDF6E6D4EF57CC.cache.html
+++ /dev/null
@@ -1,628 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/common/static/js/capa/genex/9B4F4D4EFA24CDE2E4287CC07897F249.cache.html b/common/static/js/capa/genex/9B4F4D4EFA24CDE2E4287CC07897F249.cache.html
deleted file mode 100644
index 5c828c120943..000000000000
--- a/common/static/js/capa/genex/9B4F4D4EFA24CDE2E4287CC07897F249.cache.html
+++ /dev/null
@@ -1,654 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/common/static/js/capa/genex/A069AC107D79C29D6237614AC340F0C0.cache.html b/common/static/js/capa/genex/A069AC107D79C29D6237614AC340F0C0.cache.html
deleted file mode 100644
index bcf15330d988..000000000000
--- a/common/static/js/capa/genex/A069AC107D79C29D6237614AC340F0C0.cache.html
+++ /dev/null
@@ -1,652 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/common/static/js/capa/genex/C6220FCC8B9234FEAD8D826A73C6D2A4.cache.html b/common/static/js/capa/genex/C6220FCC8B9234FEAD8D826A73C6D2A4.cache.html
deleted file mode 100644
index 5ab12af71887..000000000000
--- a/common/static/js/capa/genex/C6220FCC8B9234FEAD8D826A73C6D2A4.cache.html
+++ /dev/null
@@ -1,642 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/common/static/js/capa/genex/clear.cache.gif b/common/static/js/capa/genex/clear.cache.gif
deleted file mode 100644
index e565824aafaf..000000000000
Binary files a/common/static/js/capa/genex/clear.cache.gif and /dev/null differ
diff --git a/common/static/js/capa/genex/genex.css b/common/static/js/capa/genex/genex.css
deleted file mode 100644
index 459c854f92e4..000000000000
--- a/common/static/js/capa/genex/genex.css
+++ /dev/null
@@ -1,122 +0,0 @@
-.genex-button {
- margin-right: -8px;
- height: 40px !important;
-}
-
-.genex-label {
- /*font: normal normal normal 10pt/normal 'Open Sans', Verdana, Geneva, sans-serif !important;*/
- /*padding: 4px 0px 0px 10px !important;*/
- font-family: sans-serif !important;
- font-size: 13px !important;
- font-style: normal !important;
- font-variant: normal !important;
- font-weight: bold !important;
- padding-top: 6px !important;
- margin-left: 18px;
-}
-
-.gwt-HTML {
- cursor: default;
- overflow-x: auto !important;
- overflow-y: auto !important;
- background-color: rgb(248, 248, 248) !important;
-}
-
-.genex-scrollpanel {
- word-wrap: normal !important;
- white-space: pre !important;
-}
-
-pre, #dna-strand {
- font-family: 'courier new', courier !important;
- font-size: 13px !important;
- font-style: normal !important;
- font-variant: normal !important;
- font-weight: normal !important;
- border-style: none !important;
- background-color: rgb(248, 248, 248) !important;
- word-wrap: normal !important;
- white-space: pre !important;
- overflow-x: visible !important;
- overflow-y: visible !important;
-}
-
-.gwt-DialogBox .Caption {
- background: #F1F1F1;
- padding: 4px 8px 4px 4px;
- cursor: default;
- font-family: Arial Unicode MS, Arial, sans-serif;
- font-weight: bold;
- border-bottom: 1px solid #bbbbbb;
- border-top: 1px solid #D2D2D2;
-}
-.gwt-DialogBox .dialogContent {
-}
-.gwt-DialogBox .dialogMiddleCenter {
- padding: 3px;
- background: white;
-}
-.gwt-DialogBox .dialogBottomCenter {
- background: url(images/hborder.png) repeat-x 0px -2945px;
- -background: url(images/hborder_ie6.png) repeat-x 0px -2144px;
-}
-.gwt-DialogBox .dialogMiddleLeft {
- background: url(images/vborder.png) repeat-y -31px 0px;
-}
-.gwt-DialogBox .dialogMiddleRight {
- background: url(images/vborder.png) repeat-y -32px 0px;
- -background: url(images/vborder_ie6.png) repeat-y -32px 0px;
-}
-.gwt-DialogBox .dialogTopLeftInner {
- width: 10px;
- height: 8px;
- zoom: 1;
-}
-.gwt-DialogBox .dialogTopRightInner {
- width: 12px;
- zoom: 1;
-}
-.gwt-DialogBox .dialogBottomLeftInner {
- width: 10px;
- height: 12px;
- zoom: 1;
-}
-.gwt-DialogBox .dialogBottomRightInner {
- width: 12px;
- height: 12px;
- zoom: 1;
-}
-.gwt-DialogBox .dialogTopLeft {
- background: url(images/circles.png) no-repeat -20px 0px;
- -background: url(images/circles_ie6.png) no-repeat -20px 0px;
-}
-.gwt-DialogBox .dialogTopRight {
- background: url(images/circles.png) no-repeat -28px 0px;
- -background: url(images/circles_ie6.png) no-repeat -28px 0px;
-}
-.gwt-DialogBox .dialogBottomLeft {
- background: url(images/circles.png) no-repeat 0px -36px;
- -background: url(images/circles_ie6.png) no-repeat 0px -36px;
-}
-.gwt-DialogBox .dialogBottomRight {
- background: url(images/circles.png) no-repeat -8px -36px;
- -background: url(images/circles_ie6.png) no-repeat -8px -36px;
-}
-* html .gwt-DialogBox .dialogTopLeftInner {
- width: 10px;
- overflow: hidden;
-}
-* html .gwt-DialogBox .dialogTopRightInner {
- width: 12px;
- overflow: hidden;
-}
-* html .gwt-DialogBox .dialogBottomLeftInner {
- width: 10px;
- height: 12px;
- overflow: hidden;
-}
-* html .gwt-DialogBox .dialogBottomRightInner {
- width: 12px;
- height: 12px;
- overflow: hidden;
-}
\ No newline at end of file
diff --git a/common/static/js/capa/genex/genex.nocache.js b/common/static/js/capa/genex/genex.nocache.js
deleted file mode 100644
index 11f9714afbe1..000000000000
--- a/common/static/js/capa/genex/genex.nocache.js
+++ /dev/null
@@ -1,18 +0,0 @@
-function genex(){var P='',xb='" for "gwt:onLoadErrorFn"',vb='" for "gwt:onPropertyErrorFn"',ib='"><\/script>',Z='#',Xb='.cache.html',_='/',lb='//',Qb='21B31BA00E7CE7B6BD63DD13A8586A45',Rb='63308EE54E8033A708B414CAC05B0C32',Sb='7AC57DC6EC8C1D8672DDF6E6D4EF57CC',Tb='9B4F4D4EFA24CDE2E4287CC07897F249',Wb=':',pb='::',dc='
-
-This html file is for Development Mode support.
-