The badge support for DiscoverDesign benefitted greatly from Drupal Console's facility to generate a completely functioning module with a custom entity type.
DiscoverDesign's digital badge features cover these tasks:
- Users can find information about digital badges they can be awarded for work on DiscoverDesign.org
- Students can apply for badges, submit their work on project as evidence and offer a narrative reflection on why that work fulfills the requirements of the badge.
- Teachers can review badge applications to approve or reject them.
- Awarded badges are displayed on the student's public profile.
- Optionally, awarded badges are sent to the Chicago City of Learning API so a student's achievements across all participating organizations can be collected in a common system.
We wanted to avoid implementing a complete digital badging platform in Drupal when viable options already existed as open source projects. At first, we considered BadgeKit, which was usually the first such platform mentioned in any discussion of digital badges.
BadgeKit is a full implementation of the OpenBadges specification. While superficially, digital badges are simple images that represent some sort of academic or vocational achievement, the specification includes some perhaps surprising features that ensure their durability. When a learner is awarded a badge, the issuers can produce an Assertion that is cryptographically signed and baked into the image representing the badge. This digital signature allows the badge to be verified independently of the issuer organization, which means the badge can retain its value even if the organization who issued it disappears from the internet.
However, BadgeKit had some important negatives. It is a node.js application, which would have imposed additional server and maintenance requirements on the project when it was in production. The project on Github is not maintained: there have been no commits for over a year and over a dozen open pull requests and many more open issues. (As a test, we opened a simple pull request to test the engagement of the maintainers, and in five months it has not been reviewed or even reacted to.) While the UI and API are comprehensive and sophisticated, they appear to lack some important features like actually filtering badge assessment applications by the reviewer's user ID. Finally, the project depends on Mozilla Persona for authentication, but this service will shut down in November 2016, and no concrete actions have been taken to update BadgeKit with a replacement authentication mechanism.
In the end, we worked with the Chicago City of Learning to use their documented API to provide the data about badges that students can win and also to store awarded badges for students. The other tasks in our badge system -- applying for badges and reviewing those applications -- are handled entirely within the Drupal 8 site.
The "digital badge" idea has some important players behind it --- from Mozilla, Girl Scouts, Purdue University, MacArthur Foundation and educational institutions in China and Australia --- so this concept will probably continue to evolve and expand into more learning projects. Digital badges, of course, are an innovation in a volatile education system in the United States where privatization, austerity and online networks are major drivers of change for the institutions that educate children and adults.
Although the final work Caxy did to support digital badges on DiscoverDesign is open source, this tool will only be useful for other users of the City of Learning API. The work we started to support BadgeKit includes a generic PHP API client and a very basic Drupal 8 module to integrate that client. We would be eager to see this work continue and to be more involved in digital badge support on open source platforms.
School data
Near the beginning of our work on this project, we stumbled upon data published by the U.S. Department of Education listing every public school along with demographic and economic data about the students served by the school. As we played with the data, we created a simple Silex-based application that provides a very basic REST API for the data from the government.
Initially, we only used this data to simplify registration of new users. As new students register, the U.S. state they select is used to filter a query that populates an autocomplete input field on the registration form. Using values from other parts of the form to modify an autocomplete element's query is not core Drupal behavior, but it was not hard to accomplish and did not require a lot of custom code.
We effectively extend the core Drupal.autocomplete
object and replace the source parameter of the jQuery UI Autocomplete call in the custom autocomplete behavior for this particular input element. While some parts of this function are duplicated from Drupal's autocomplete.js
file (the private functions showSuggestions
), the code duplication is relatively small. Other modifications were necessary to expand the cache keys for the autocomplete behavior's internal cache of already searched values.
(function ($, Drupal) {
'use strict';
var autocomplete = Drupal.autocomplete;
function sourceData(request, response) {
var elementId = this.element.attr('id');
if (!(elementId in autocomplete.cache)) {
autocomplete.cache[elementId] = {};
}
/**
* Filter through the suggestions removing all terms already tagged and
* display the available terms to the user.
*
* @param {object} suggestions
* Suggestions returned by the server.
*/
function showSuggestions(suggestions) {
var tagged = autocomplete.splitValues(request.term);
var il = tagged.length;
for (var i = 0; i < il; i++) {
var index = suggestions.indexOf(tagged[i]);
if (index >= 0) {
suggestions.splice(index, 1);
}
}
response(suggestions);
}
/**
* Transforms the data object into an array and update autocomplete results.
*
* @param {object} data
* The data sent back from the server.
*/
function sourceCallbackHandler(data) {
autocomplete.cache[elementId][cacheKey] = data;
// Send the new string array of terms to the jQuery UI list.
showSuggestions(data);
}
// Get the desired term and construct the autocomplete URL for it.
var term = autocomplete.extractLastTerm(request.term);
var state;
// Use the state indicated elsewhere in the form
$('[data-drupal-selector="edit-field-address-0"]').each(function () {
state = $('[data-drupal-selector="edit-field-address-0-administrative-area"] :selected', this).attr('value');
});
// Check if the term is already cached and use the state value as part of the cache key.
var cacheKey = term;
if (state) {
cacheKey = state + ':' + term;
}
if (autocomplete.cache[elementId].hasOwnProperty(cacheKey)) {
showSuggestions(autocomplete.cache[elementId][cacheKey]);
}
else {
// Modify the request to the autocomplete endpoint to include the state.
var target = {success: sourceCallbackHandler, data: {q: term}};
if (state) {
target.data.state = state;
}
var options = $.extend(target, autocomplete.ajax);
$.ajax(this.element.attr('data-autocomplete-path'), options);
}
}
Drupal.behaviors.schoolAutocomplete = {
attach: function (context, settings) {
$(context).find('[data-drupal-selector="edit-field-school-0-target-id"]').each(function () {
$(this).autocomplete('option', 'source', sourceData);
});
},
detach: function (context, settings, trigger) {
}
};
})(jQuery, Drupal);
Caxy Interactive can help your next Drupal development project be just as successful as the Chicago Architecture Foundation's DiscoverDesign.org initiative. Contact us today to learn more.