diff --git a/lms/djangoapps/badges/api/serializers.py b/lms/djangoapps/badges/api/serializers.py
index bd3739be31a7..54e669e9ec27 100644
--- a/lms/djangoapps/badges/api/serializers.py
+++ b/lms/djangoapps/badges/api/serializers.py
@@ -1,5 +1,5 @@
"""
-Serializers for badging
+Serializers for Badges
"""
from rest_framework import serializers
diff --git a/lms/djangoapps/student_profile/views.py b/lms/djangoapps/student_profile/views.py
index 0ee58e68966e..751a683a4d95 100644
--- a/lms/djangoapps/student_profile/views.py
+++ b/lms/djangoapps/student_profile/views.py
@@ -7,6 +7,7 @@
from django.http import Http404
from django.views.decorators.http import require_http_methods
from django_countries import countries
+from django.contrib.staticfiles.storage import staticfiles_storage
from edxmako.shortcuts import render_to_response, marketing_link
from microsite_configuration import microsite
@@ -87,6 +88,9 @@ def learner_profile_context(request, profile_username, user_is_staff):
'country_options': list(countries),
'find_courses_url': marketing_link('COURSES'),
'language_options': settings.ALL_LANGUAGES,
+ 'badges_logo': staticfiles_storage.url('certificates/images/backpack-logo.png'),
+ 'badges_icon': staticfiles_storage.url('certificates/images/ico-mozillaopenbadges.png'),
+ 'backpack_ui_img': staticfiles_storage.url('certificates/images/backpack-ui.png'),
'platform_name': microsite.get_value('platform_name', settings.PLATFORM_NAME),
},
'disable_courseware_js': True,
diff --git a/lms/static/js/student_profile/views/badge_list_container.js b/lms/static/js/student_profile/views/badge_list_container.js
index e53bce12c8c1..7426e2cea379 100644
--- a/lms/static/js/student_profile/views/badge_list_container.js
+++ b/lms/static/js/student_profile/views/badge_list_container.js
@@ -9,6 +9,8 @@
initialize: function (options) {
BadgeListContainer.__super__.initialize.call(this, options);
this.listView.find_courses_url = options.find_courses_url;
+ this.listView.badgeMeta = options.badgeMeta;
+ this.listView.ownProfile = options.ownProfile;
},
type: 'badge',
itemViewClass: BadgeView,
diff --git a/lms/static/js/student_profile/views/badge_list_view.js b/lms/static/js/student_profile/views/badge_list_view.js
index 182af7c1c2f6..a5c3ef5ec246 100644
--- a/lms/static/js/student_profile/views/badge_list_view.js
+++ b/lms/static/js/student_profile/views/badge_list_view.js
@@ -15,7 +15,11 @@
row = $('
');
this.$el.append(row);
}
- var item = new BadgeView({model: badge}).render().el;
+ var item = new BadgeView({
+ model: badge,
+ badgeMeta: this.badgeMeta,
+ ownProfile: this.ownProfile
+ }).render().el;
row.append(item);
this.itemViews.push(item);
}, this);
diff --git a/lms/static/js/student_profile/views/badge_view.js b/lms/static/js/student_profile/views/badge_view.js
index 559c560e5391..5eba42e5421f 100644
--- a/lms/static/js/student_profile/views/badge_view.js
+++ b/lms/static/js/student_profile/views/badge_view.js
@@ -1,18 +1,37 @@
;(function (define, undefined) {
'use strict';
- define([
- 'gettext', 'jquery', 'underscore', 'backbone', 'moment', 'text!templates/student_profile/badge.underscore'],
- function (gettext, $, _, Backbone, Moment, badgeTemplate) {
+ define(['gettext', 'jquery', 'underscore', 'backbone', 'moment',
+ 'text!templates/student_profile/badge.underscore',
+ 'js/student_profile/views/share_modal_view'],
+ function (gettext, $, _, Backbone, Moment, badgeTemplate, ShareModalView) {
var BadgeView = Backbone.View.extend({
+ initialize: function(options) {
+ this.context = _.extend(this.options.model.toJSON(), {
+ 'created': new Moment(this.options.model.toJSON().created),
+ 'ownProfile': options.ownProfile,
+ 'badgeMeta': options.badgeMeta
+ });
+ },
attributes: {
'class': 'badge-display'
},
- render: function () {
- var context = _.extend(this.options.model.toJSON(), {
- 'created': new Moment(this.options.model.toJSON().created)
+ events: {
+ 'click .share-button': 'createModal'
+ },
+ createModal: function() {
+ var modal = new ShareModalView({
+ model: new Backbone.Model(this.context),
+ shareButton: this.shareButton
});
- this.$el.html(_.template(badgeTemplate, context));
+ modal.$el.hide();
+ modal.render();
+ $('body').append(modal.$el);
+ modal.$el.fadeIn('short', 'swing', _.bind(modal.ready, modal));
+ },
+ render: function () {
+ this.$el.html(_.template(badgeTemplate, this.context));
+ this.shareButton = this.$el.find('.share-button');
return this;
}
});
diff --git a/lms/static/js/student_profile/views/learner_profile_factory.js b/lms/static/js/student_profile/views/learner_profile_factory.js
index 4ac76bc1e44c..720fbf4cd793 100644
--- a/lms/static/js/student_profile/views/learner_profile_factory.js
+++ b/lms/static/js/student_profile/views/learner_profile_factory.js
@@ -131,7 +131,13 @@
var badgeListContainer = new BadgeListContainer({
'attributes': {'class': 'badge-set-display'},
'collection': badgeCollection,
- 'find_courses_url': options.find_courses_url
+ 'find_courses_url': options.find_courses_url,
+ 'ownProfile': options.own_profile,
+ 'badgeMeta': {
+ 'badges_logo': options.badges_logo,
+ 'backpack_ui_img': options.backpack_ui_img,
+ 'badges_icon': options.badges_icon
+ }
});
var learnerProfileView = new LearnerProfileView({
diff --git a/lms/static/js/student_profile/views/share_modal_view.js b/lms/static/js/student_profile/views/share_modal_view.js
new file mode 100644
index 000000000000..21744ed79314
--- /dev/null
+++ b/lms/static/js/student_profile/views/share_modal_view.js
@@ -0,0 +1,48 @@
+;(function (define, undefined) {
+ 'use strict';
+ define(['gettext', 'jquery', 'underscore', 'backbone', 'moment',
+ 'text!templates/student_profile/share_modal.underscore'],
+ function (gettext, $, _, Backbone, Moment, badgeModalTemplate) {
+
+ var ShareModalView = Backbone.View.extend({
+ attributes: {
+ 'class': 'badges-overlay'
+ },
+ events: {
+ 'click .badges-modal': function (event) {event.stopPropagation();},
+ 'click .badges-modal .close': 'close',
+ 'click .badges-overlay': 'close',
+ 'keydown': 'keyAction',
+ 'focus .focusguard-start': 'focusGuardStart',
+ 'focus .focusguard-end': 'focusGuardEnd'
+ },
+ focusGuardStart: function () {
+ // Should only be selected directly if shift-tabbing from the start, so grab last item.
+ this.$el.find("a").last().focus();
+ },
+ focusGuardEnd: function() {
+ this.$el.find(".badges-modal").focus();
+ },
+ close: function () {
+ this.$el.fadeOut('short', 'swing', _.bind(this.remove, this));
+ this.options.shareButton.focus();
+ },
+ keyAction: function (event) {
+ if (event.keyCode === $.ui.keyCode.ESCAPE) {
+ this.close();
+ }
+ },
+ ready: function() {
+ // Focusing on the modal background directly doesn't work, probably due
+ // to its positioning.
+ this.$el.find('.badges-modal').focus();
+ },
+ render: function () {
+ this.$el.html(_.template(badgeModalTemplate, this.model.toJSON()));
+ return this;
+ }
+ });
+
+ return ShareModalView;
+ });
+}).call(this, define || RequireJS.define);
diff --git a/lms/static/sass/views/_learner-profile.scss b/lms/static/sass/views/_learner-profile.scss
index d1aacf96a722..d0ee5ce6d633 100644
--- a/lms/static/sass/views/_learner-profile.scss
+++ b/lms/static/sass/views/_learner-profile.scss
@@ -372,6 +372,37 @@
font-weight: bold;
color: $blue-s3;
}
+ .share-button {
+ @extend %t-action3;
+ @extend %button-reset;
+ background: $gray-l6;
+ color: $gray-d1;
+ padding: ($baseline / 4) ($baseline / 2);
+ margin-bottom: ($baseline / 2);
+ display: inline-block;
+ border-radius: 5px;
+ border: 2px solid $gray-d1;
+ cursor: pointer;
+ transition: background .5s;
+ .share-prefix {
+ display: inline-block;
+ vertical-align: middle;
+ }
+ .share-icon-container {
+ display: inline-block;
+ img.icon-mozillaopenbadges {
+ max-width: 1.5em;
+ margin-right: .25em;
+ }
+ }
+ &:hover {
+ background: $gray-l4;
+ }
+ &:active {
+ box-shadow: inset 0 4px 15px 0 $black-t2;
+ transition: none;
+ }
+ }
}
}
.badge-placeholder {
@@ -379,4 +410,90 @@
box-shadow: inset 0 0 4px 0 $gray-l4;
}
}
+
+ // ------------------------------
+ // #BADGES MODAL
+ // ------------------------------
+ .badges-overlay {
+ @extend %ui-depth1;
+ position: fixed;
+ top: 0;
+ left: 0;
+ background-color: $dark-trans-bg; /* dim the background */
+ width: 100%;
+ height: 100%;
+ vertical-align: middle;
+
+ .badges-modal {
+ @extend %t-copy-lead1;
+ @extend %ui-depth2;
+ color: $lighter-base-font-color;
+ box-sizing: content-box;
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 80%;
+ max-width: 700px;
+ max-height: calc(100% - 100px);
+ margin-right: auto;
+ margin-left: auto;
+ border-top: rem(10) solid $blue-l2;
+ background: $light-gray3;
+ padding-right: ($baseline * 2);
+ padding-left: ($baseline * 2);
+ padding-bottom: ($baseline);
+ overflow-x: hidden;
+
+ .modal-header {
+ margin-top: ($baseline / 2);
+ margin-bottom: ($baseline / 2);
+ }
+
+ .close {
+ @extend %button-reset;
+ @extend %t-strong;
+ color: $lighter-base-font-color;
+ position: absolute;
+ right: ($baseline);
+ top: $baseline;
+ cursor: pointer;
+ padding: ($baseline / 4) ($baseline / 2);
+ @include transition(all $tmg-f2 ease-in-out 0s);
+ &:focus, &:hover {
+ background-color: $blue-d2;
+ border-radius: 3px;
+ color: $white;
+ }
+ }
+
+ .badges-steps {
+ display: table;
+ }
+
+ .image-container{
+ // Lines the image up with the content of the above list.
+ @include ltr {
+ @include padding-left(2em);
+ }
+ @include rtl {
+ @include padding-right(1em);
+ float: right;
+ }
+ }
+
+ .backpack-logo {
+ @include float(right);
+ @include margin-left($baseline);
+ }
+ }
+ }
+
+ .modal-hr {
+ display: block;
+ border: none;
+ background-color: $light-gray;
+ height: rem(2);
+ width: 100%;
+ }
}
diff --git a/lms/templates/student_profile/badge.underscore b/lms/templates/student_profile/badge.underscore
index 00b7f3313f7d..10901497270d 100644
--- a/lms/templates/student_profile/badge.underscore
+++ b/lms/templates/student_profile/badge.underscore
@@ -4,6 +4,20 @@
<%- badge_class.display_name %>
<%- badge_class.description %>
+ <% if (ownProfile) { %>
+
+
+
">
+
+ <%- gettext("Share") %>
+
+ <% } %>
<%-
interpolate(
diff --git a/lms/templates/student_profile/share_modal.underscore b/lms/templates/student_profile/share_modal.underscore
new file mode 100644
index 000000000000..402756bb2659
--- /dev/null
+++ b/lms/templates/student_profile/share_modal.underscore
@@ -0,0 +1,30 @@
+
+
+
<%- gettext("Close") %>
+
+
<%- gettext("To share your certificate on Mozilla Backpack, you must first have a Backpack account. Complete the following steps to add your certificate to Backpack.") %>
+
+
+
+
+ <%=
+ interpolate(
+ gettext("Create a %(link_start)sMozilla Backpack%(link_end)s account, or log in to your existing account"),
+ {link_start: '', link_end: ' '},
+ true
+ )%>
+
+ <%=
+ interpolate(
+ gettext("%(download_link_start)sDownload this image (right-click or option-click, save as)%(link_end)s and then %(upload_link_start)supload%(link_end)s it to your backpack. "), {
+ download_link_start: '',
+ link_end: ' ', upload_link_start: ''
+ },
+ true
+ )%>
+
+
+
+
+
+
\ No newline at end of file