Make editing courses on Coursera fun!

31 March 2015

Quiz editing for courses

We recently launched the next generation of authoring tools for instructors, instructional designers and teaching staff at our Partners Conference. To accomplish this, we made use of several open-source projects including React.js as the UI library, Flux as the application architecture and Scribe for the rich editing interface.

In the same spirit, we are also open-sourcing a few of our scribe plugins to contribute back to the community, and we hope to continue to grow this list in the future. This blog post will talk about the guiding principles behind building a new set of authoring tools and how we tackled some of the front-end design and engineering challenges.

We want to provide the maximal value to our learners, and towards that goal, we’ve partnered with amazing university partners to get the best content onto our platform. In the early days of Coursera, we bootstrapped this process of content onboarding through manual effort - and over time built tools to give our instructors the capability to independently iterate on their content. This authoring tool was packed with functionality ranging from the ability to edit course structure to uploading new videos and assessments.

In mid 2014, we introduced the notion of on demand classes. This was an opportunity for us to revisit our authoring tools and build a new experience based on the lessons learned from our first iteration. We quickly identified three important goals for our authoring tools:

  • Ease of data-driven iteration - A noticeable pattern in the first version of the authoring tools was instructors making edits to their content based on analytical insights from our dashboard - so bringing the two products closer together would be useful. More about this coming soon in another blog.

  • Consistency in output - Coursera offers a rich set of “learning units” to build up a course - for example, assessments, reading material and videos. We want our learners to have a consistent learning experience across all these units, while being able to take their course across multiple platforms.

  • Consistency in authoring tools - Given the variety of learning units that exist on our platform, we wanted to create a consistent and intuitive interface to allow instructors to edit their courses.

Here we will talk about how we achieved the latter two goals.

Consistency in output

Our goal was to create a consistent cross-platform experience for our learners. Our first version of the authoring tool stored and represented content as restricted HTML, resulting in a sub-optimal user experience, with inconsistent layout on non-web platforms. In addition, we weren’t able to leverage native functionality present in the platform to render content.

This prompted us to build a platform agnostic markup language (we call it Coursera Markup Language - CML), with libraries that would render it natively on web, iOS and Android platform. The CML language definition, based on XML specification, itself consists of predefined “blocks” - for example, table, list, image, code, etc.

The WYSIWYG Editor

WYSIWYG editor using Scribe

To allow instructors to create CML content on our platform, we wanted a rich editing experience, which meant building a WYSIWYG editor. With this editor, we faced the following challenges:

  • Ability to transform the HTML generated by the editor into CML. So, the more semantic and consistent the markup generated by the editor, the better it was.

  • Flexibility in modifying the low-level editing behaviors of the editor: CML had several restrictions, for example, a list could not have images. So it was imperative that our choice of editor allowed defining these low level bounded conditions.

  • Ability to add/modify support for different “CML blocks” to the editor, including images, tables, lists, code, etc.

  • Ability to change styling of the editor.

  • Ability to reuse the same editor in different feature contexts with support for different blocks (one feature might support images, the other may not)

  • Work well with React and Flux, which were the UI library and application architecture we were using.

We began researching existing WYSIWYG editors in the landscape, and narrowed it down to the following: wysiHTML5, Quill, Scribe, Medium.js and Sir Trevor.

After trying out the different editors, we settled on Scribe. The “everything is a plugin” approach was a fantastic fit for our use case. It afforded a lot of flexibility in modifying different parts of the editor. It also had the notion of blocks which mapped well to “CML blocks”. The HTMLJanitor project helped in sanitizing the HTML to include a strict set of tags.

The Scribe community has been thriving and it has done a great job in taking the editor forward. It has moved from version 0.1.x (when we started using it) to 1.3.x in a matter of a few months!

Consistency in authoring tools

Review & Publish flow for authoring tools

In addition to solving the consistency in output, we wanted uniformity in the authoring tools for different learning units. This meant identifying and building common behaviors. Our usage of React allowed us to build these up as simple components that could be easily dropped in with different parameters for different contexts. Some examples are:

  • Auto-save content changes: Using Actions from Flux made it possible to execute all the API requests on a single thread, which in turn helped build a common debouncing solution for all requests and avoid any conflicts during editing for the same user (see below).

  • Concurrent editing: We intended not to support concurrent editing at a learning unit level i.e. prompt a user to retry later if another user was editing the same learning unit concurrently. This approach was reasonable as we had learned from our first version of authoring tools that multiple instructors working on the same learning unit concurrently was rare. The single thread architecture for API requests made this easy to achieve; each request contained the timestamp of the last successful request and user as the payload. If the timestamp was outdated, it meant there was a conflict.

  • DTD Validation for content: In order to prevent bad data from being stored on our systems, we required all CML generated on the frontend to go through a predefined strict DTD. The HTML generated by our editor needed to be well-defined so that it could be converted into valid CML that conformed to the specification We had to handle a number of edge cases that could lead to unpredictable HTML. A couple of examples include:

    • Copy/paste: The user can paste in any HTML into the editor. This HTML is sanitized by Scribe, but it doesn’t sanitize against any CML restrictions. So, we strip out the formatting and paste in raw text. In the future, we want to preserve the formatting by building another layer of sanitization for CML.

    • Drag and drop: Users can also drag and drop images into a list, so we have cancelled all drop events until we build a case-by-case handling.

The Future

We are starting to use the editor in other contexts on the site, including discussion forums. For CML, we want to add support for more blocks over time, including perhaps videos, audio and layout.

The next big problem we are now looking to tackle is adding support for course creation. There is also a lot more we need to do to make editing easier and fun for instructors and instructional designers, including bridging the gap between authoring and the learner’s perspective of content, reducing the gap between data analysis and content editing (towards the goal of data-driven editing), and recommending best practices to instructors for generating great course content.

Product Engineering
Want to work with us? Join Us!