Drag-and-Drop-v2 XBlock

Devstack development process

  1. Clone the repo to your devstack/src directory. This directory is generally mounted to be shared with the devstack VM
  2. `vagrant ssh` to SSH on to the Devstack
  3. `sudo su edxapp` to log in at the edxapp user
  4. cd to the src/xblock-drag-and-drop-v2/ directory
  5. run `pip uninstall xblock-drag-and-drop-v2` to remove the installed version
  6. run `python setup.py develop`

Feature Overview

Drag and drop v2 XBlock implements a friendly drag-and-drop style problem, where the learner has to drag items to zones on a target image.

Detailed feature overview is available in README.

SOL-1803 epic tracks progress of bringing the DnDv2 XBlock to satisfy edX quality standards. DnDv2 has now replaced DnDv1 as a default block for drag and drop problem.

Key features:

  • Mouse and keyboard friendly
  • Accessible ( SOL-2157 - Getting issue details... STATUS SOL-2158 - Getting issue details... STATUS , SOL-2158 - Getting issue details... STATUS )
  • Rich custom studio editor (no XML knowledge required from author)
  • Two operational modes: 
    • Standard - students have an unlimited amount of attempts and get feedback for each item placement + overall feedback
    • Assessment - students have a limited amount of attempts and do not receive feedback until correct solution is submitted or all attempts were used
  • Custom theming
  • Responsive and mobile-friendly



DnDv2 xblock comes as a single monolithic XBlock, i.e. there are no "child" or "companion" XBlocks or XBlock Asides. It communicates with LMS via standard XBlock APIs:

  • XBlock Services: Settings Service and Translation Service
  • Using XBlock views: 
    • student_view - used in LMS to render problem to the student 
    • studio_view - used in Studio to render problem editor for course author.
  • Using XBlock handlers
    • studio_submit - handles submitting DnDv2 configuration from Studio editor
    • drop_item - handles dropping item into a dropzone: updates user state and (potentially) grade,
    • do_attempt - handles submitting an attempt in assessment mode
    • publish_event - allows publishing XBlock events from frontend code
    • reset - resets problem state
    • show_answer - returns correct solution to the problem (only in assessment mode and when no more attempts left)
    • expand_static_url - allows resolving URLs to static files from frontend code
    • get_user_state - returns student's answer to the problem
  • Runtime events:
  • XBlock fields - at high level, there are two groups of fields used: one for XBlock content and settings (Scope.settings and Scope.content), and another to store student answers and grade (Scope.user_state)

From implementation point of view, major part of functionality is collected in DragAndDropBlock class (~900 lines of code). Most is pretty much standard XBlock code: LMS and Studio views, fields declarations and so on.

Non-trivial features are:

  • Extensive communication with frontend - 7 json handlers
  • Keeps track of highest achieved grade and does not decrease the grade - allows further experimentation with the block without the risk of worsening the result.
  • User state migrations on the fly - since there are no (external to XBlock itself) mechanism for migrating XBlock field data, DnDv2 keeps track of backward-incompatible changes and migrates old user state and dropzone data on the fly


DnDv2 comes with two JS files:

  • drag_and_drop.js - used in LMS to render the problem to student and handle student interactions. Uses jQuery, jQuery UI and VirtualDom.
  • drag_and_drop_edit.js - used in Studio to animate custom DnDv2 editor. Uses jQuery, jQueryUI and Handlebars.

All JS dependencies (jQuery, Handlebars, etc.) are shipped with DnDv2 and injected into page by DnDv2 itself. Only external dependencies that DnDv2 just assumes to be available on the page are "gettext" and "ngettext" - although a fallback mechanism is set up so that in lieu of those two  DnDv2 degrades gracefully and will only miss frontend messages translation.

Studio interface (drag_and_drop_edit.js) contains single function/class DragAndDropEditBlock(runtime, element, params) that follows JS XBlock signature.

LMS interface (drag_and_drop.js) contains two functions/classes:

  • DragAndDropBlock - main entry point - follows JS XBlock signature. Contains event handlers, and interaction logic, keeps track of problem state, emits events and handles communication with backend.
  • DragAndDropTemplates - contains methods to render various parts of DnDv2 interface

As LMS interface is build around VirtualDom, most of the interactions are revolving around problem "state" and problem "configuration". Majority of actions performed by DragAndDropBlock methods are either reading state/configuration, modifying state as a result of user actions or fetching/submitting state from/to backend. 

One key method of DragAndDropBlock is "applyState" - this method is always called at the end of any call chain handling user interactions as it updates problem DOM to reflect new problem state.

Enabling DnDv2

Standard procedure for a XBlock:

  1. Make sure an XBlock is installed in virtualenv running LMS/Studio (should be handled by LMS/Studio itself - DnDv2 is listed as a dependency)
  2. Add DnDv2 entrypoint to a list of Advanced Modules. Instructions are available in the README


Test instructions can be found in README

Although neither local config nor CI build collect coverage, it would be straightforward to enable it by installing coverage python package and running the test suite with --with-coverage flag.

Coverage report at the time of writing

Future direction and technical debt

Most of future prospects are related to refactoring the code to become modular and more maintainable:

  • Extracting standard and assessment modes into dedicated XBlocks.
  • Extract parts of monolithic DragAndDropBlock python class into separate classes/objects.
  • Make better use of JS features in frontend code (e.g. prototype inheritance, modern libraries, reactive interface, etc).

Technical debt:

  • DnDv2 test suite heavily relies on integration tests - might be good to replace at least some of those with unit tests (python and JS)
    • Take very long time to run entire suite
    • No JS unit tests
    • JS code coverage is never collected (there are tools for instrumenting selenium to do so, but no one actually investigated this).
    • Some tests are fragile (but not flaky) - under certain conditions element to receive a click is not visible in the selenium viewport, which results in an error. All of such tests have `scroll_down` parameter somewhere in the call chain - adjusting the value might be needed when DnDv2 layout changes.
    • Code coverage result is probably an over-estimation as integration tests tend to hit a lot of lines, while actually testing a few. Branch coverage might be quite poor.
  • Complete lack of logging
  • No load tests, but most likely there shouldn't be any problem.
  • Trivial tech debt:
    • 2 handlers do not use XBlock.json_handler decorator, but still return "application/json"
    • Keeping highest available grade is not documented in any student-facing part of the system, so students only can discover it by trial and error; also, this is not in line with CAPA problems
    • Significant vertical separation - methods in DragAndDropBlock are not always semantically grouped together.
    • Very long and complicated methods (i.e. get_feedback)
  • DragAndDropBlock class resembles a God Object a bit - might make sense to start pulling it apart (this is considered and certain options are evaluated now)
  • Some methods and properties have to be invoked in certain order (and that order is not explicitly visible) - potential source of bugs:
  • Complex frontend code + different libs are used for editor and for student view (VirtualDom vs Handlebars).
  • (Arguable) Student view does not use templates at all - as a result everything is constructed via VirtualDom calls - complex and non-intuitive (~500 lines of code building DOM elements)

Student interaction diagrams

Standard ModeAssessment Mode