Merge pull request #8175 from edx/will/footer-api-redux
ECOM-1339 Branding API footer
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -78,14 +78,13 @@ lms/static/sass/lms-main.scss
|
||||
lms/static/sass/lms-main-rtl.scss
|
||||
lms/static/sass/lms-course.scss
|
||||
lms/static/sass/lms-course-rtl.scss
|
||||
lms/static/sass/lms-footer-edx.scss
|
||||
lms/static/sass/lms-footer-edx-rtl.scss
|
||||
lms/static/sass/lms-footer.scss
|
||||
lms/static/sass/lms-footer-rtl.scss
|
||||
cms/static/css/
|
||||
cms/static/sass/*.css
|
||||
cms/static/sass/*.css.map
|
||||
|
||||
|
||||
|
||||
### Logging artifacts
|
||||
log/
|
||||
logs
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
/**
|
||||
* Adds rwd classes and click handlers.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
var rwd = (function() {
|
||||
|
||||
var _fn = {
|
||||
header: 'header.global-new',
|
||||
|
||||
footer: '.edx-footer-new',
|
||||
|
||||
resultsUrl: 'course-search',
|
||||
|
||||
init: function() {
|
||||
_fn.$header = $( _fn.header );
|
||||
_fn.$footer = $( _fn.footer );
|
||||
_fn.$nav = _fn.$header.find('nav');
|
||||
_fn.$globalNav = _fn.$nav.find('.nav-global');
|
||||
|
||||
_fn.add.elements();
|
||||
_fn.add.classes();
|
||||
_fn.eventHandlers.init();
|
||||
},
|
||||
|
||||
add: {
|
||||
classes: function() {
|
||||
// Add any RWD-specific classes
|
||||
_fn.$header.addClass('rwd');
|
||||
_fn.$footer.addClass('rwd');
|
||||
},
|
||||
|
||||
elements: function() {
|
||||
_fn.add.burger();
|
||||
_fn.add.registerLink();
|
||||
},
|
||||
|
||||
burger: function() {
|
||||
_fn.$nav.prepend([
|
||||
'<a href="#" class="mobile-menu-button" aria-label="menu">',
|
||||
'<i class="icon fa fa-reorder" aria-hidden="true"></i>',
|
||||
'</a>'
|
||||
].join(''));
|
||||
},
|
||||
|
||||
registerLink: function() {
|
||||
var $register = _fn.$nav.find('.cta-register'),
|
||||
$li = {},
|
||||
$a = {},
|
||||
count = 0;
|
||||
|
||||
// Add if register link is shown
|
||||
if ( $register.length > 0 ) {
|
||||
count = _fn.$globalNav.find('li').length + 1;
|
||||
|
||||
// Create new li
|
||||
$li = $('<li/>');
|
||||
$li.addClass('desktop-hide nav-global-0' + count);
|
||||
|
||||
// Clone register link and remove classes
|
||||
$a = $register.clone();
|
||||
$a.removeClass();
|
||||
|
||||
// append to DOM
|
||||
$a.appendTo( $li );
|
||||
_fn.$globalNav.append( $li );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
eventHandlers: {
|
||||
init: function() {
|
||||
_fn.eventHandlers.click();
|
||||
},
|
||||
|
||||
click: function() {
|
||||
// Toggle menu
|
||||
_fn.$nav.on( 'click', '.mobile-menu-button', _fn.toggleMenu );
|
||||
}
|
||||
},
|
||||
|
||||
toggleMenu: function( event ) {
|
||||
event.preventDefault();
|
||||
|
||||
_fn.$globalNav.toggleClass('show');
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
init: _fn.init
|
||||
};
|
||||
})();
|
||||
|
||||
setTimeout( function() {
|
||||
rwd.init();
|
||||
}, 100);
|
||||
})(jQuery);
|
||||
@@ -10,6 +10,7 @@
|
||||
var _fn = {
|
||||
header: 'header.global-new',
|
||||
|
||||
// TODO (ECOM-1339): Remove this once the V3 footer is enabled permanently
|
||||
footer: '.edx-footer-new',
|
||||
|
||||
resultsUrl: 'course-search',
|
||||
@@ -29,7 +30,7 @@
|
||||
classes: function() {
|
||||
// Add any RWD-specific classes
|
||||
_fn.$header.addClass('rwd');
|
||||
_fn.$footer.addClass('rwd');
|
||||
_fn.$footer.addClass('rwd'); // TODO (ECOM-1339): remove once the V3 footer is enabled permanently
|
||||
},
|
||||
|
||||
elements: function() {
|
||||
Binary file not shown.
@@ -37,8 +37,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.1a\n"
|
||||
"Report-Msgid-Bugs-To: openedx-translation@googlegroups.com\n"
|
||||
"POT-Creation-Date: 2015-05-26 15:42+0000\n"
|
||||
"PO-Revision-Date: 2015-05-26 15:42:32.205037\n"
|
||||
"POT-Creation-Date: 2015-05-26 18:33+0000\n"
|
||||
"PO-Revision-Date: 2015-05-26 18:33:10.093000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: openedx-translation <openedx-translation@googlegroups.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -179,7 +179,7 @@ msgstr ""
|
||||
"Ýöü'ré énrölléd äs än hönör çödé stüdént Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, "
|
||||
"¢σηѕє¢тєтυя#"
|
||||
|
||||
#: common/djangoapps/course_modes/models.py
|
||||
#: common/djangoapps/course_modes/models.py lms/djangoapps/branding/api.py
|
||||
#: openedx/core/djangoapps/user_api/views.py
|
||||
#: lms/templates/static_templates/honor.html
|
||||
msgid "Honor Code"
|
||||
@@ -3184,9 +3184,9 @@ msgstr ""
|
||||
msgid "Both"
|
||||
msgstr "Böth Ⱡ'σяєм ι#"
|
||||
|
||||
#: common/lib/xmodule/xmodule/course_module.py
|
||||
#: lms/templates/footer-edx-v2.html lms/templates/footer-edx-v3.html
|
||||
#: lms/templates/footer.html lms/templates/static_templates/about.html
|
||||
#: common/lib/xmodule/xmodule/course_module.py lms/djangoapps/branding/api.py
|
||||
#: lms/templates/footer-edx-v2.html lms/templates/footer.html
|
||||
#: lms/templates/static_templates/about.html
|
||||
msgid "About"
|
||||
msgstr "Àßöüt Ⱡ'σяєм ιρѕ#"
|
||||
|
||||
@@ -5141,6 +5141,80 @@ msgstr "Séärçh Ⱡ'σяєм ιρѕυ#"
|
||||
msgid "Copyright"
|
||||
msgstr "Çöpýrïght Ⱡ'σяєм ιρѕυм ∂σł#"
|
||||
|
||||
#: lms/djangoapps/branding/api.py
|
||||
msgid ""
|
||||
"© {org_name}. All rights reserved except where noted. EdX, Open edX and "
|
||||
"the edX and Open EdX logos are registered trademarks or trademarks of edX "
|
||||
"Inc."
|
||||
msgstr ""
|
||||
"© {org_name}. Àll rïghts résérvéd éxçépt whéré nötéd. ÉdX, Öpén édX änd "
|
||||
"thé édX änd Öpén ÉdX lögös äré régïstéréd trädémärks ör trädémärks öf édX "
|
||||
"Ìnç. Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ "
|
||||
"єιυѕмσ∂ тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм"
|
||||
" νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα "
|
||||
"¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє νєłιт"
|
||||
" єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт "
|
||||
"¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂#"
|
||||
|
||||
#. #-#-#-#-# django-partial.po (0.1a) #-#-#-#-#
|
||||
#. Translators: 'Open edX' is a brand, please keep this untranslated.
|
||||
#. See http://openedx.org for more information.
|
||||
#: lms/djangoapps/branding/api.py cms/templates/widgets/footer.html
|
||||
#: lms/templates/footer-edx-v2.html
|
||||
msgid "Powered by Open edX"
|
||||
msgstr "Pöwéréd ßý Öpén édX Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#"
|
||||
|
||||
#: lms/djangoapps/branding/api.py lms/templates/static_templates/blog.html
|
||||
msgid "Blog"
|
||||
msgstr "Blög Ⱡ'σяєм ι#"
|
||||
|
||||
#: lms/djangoapps/branding/api.py lms/templates/footer-edx-v2.html
|
||||
msgid "News"
|
||||
msgstr "Néws Ⱡ'σяєм ι#"
|
||||
|
||||
#: lms/djangoapps/branding/api.py
|
||||
msgid "FAQs"
|
||||
msgstr "FÀQs Ⱡ'σяєм ι#"
|
||||
|
||||
#: lms/djangoapps/branding/api.py lms/templates/footer-edx-v2.html
|
||||
#: lms/templates/static_templates/contact.html
|
||||
msgid "Contact"
|
||||
msgstr "Çöntäçt Ⱡ'σяєм ιρѕυм #"
|
||||
|
||||
#: lms/djangoapps/branding/api.py lms/templates/static_templates/jobs.html
|
||||
msgid "Jobs"
|
||||
msgstr "Jößs Ⱡ'σяєм ι#"
|
||||
|
||||
#: lms/djangoapps/branding/api.py lms/templates/static_templates/donate.html
|
||||
msgid "Donate"
|
||||
msgstr "Dönäté Ⱡ'σяєм ιρѕυ#"
|
||||
|
||||
#: lms/djangoapps/branding/api.py
|
||||
msgid "Sitemap"
|
||||
msgstr "Sïtémäp Ⱡ'σяєм ιρѕυм #"
|
||||
|
||||
#. #-#-#-#-# django-partial.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is a legal document users must agree to
|
||||
#. in order to register a new account.
|
||||
#: lms/djangoapps/branding/api.py openedx/core/djangoapps/user_api/views.py
|
||||
#: cms/templates/widgets/footer.html lms/templates/static_templates/tos.html
|
||||
msgid "Terms of Service"
|
||||
msgstr "Térms öf Sérvïçé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#"
|
||||
|
||||
#: lms/djangoapps/branding/api.py
|
||||
msgid "Terms of Service & Honor Code"
|
||||
msgstr "Térms öf Sérvïçé & Hönör Çödé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#"
|
||||
|
||||
#: lms/djangoapps/branding/api.py lms/djangoapps/certificates/views.py
|
||||
#: cms/templates/widgets/footer.html lms/templates/footer-edx-v2.html
|
||||
#: lms/templates/static_templates/privacy.html
|
||||
msgid "Privacy Policy"
|
||||
msgstr "Prïväçý Pölïçý Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#"
|
||||
|
||||
#: lms/djangoapps/branding/api.py
|
||||
msgid "Accessibility Policy"
|
||||
msgstr "Àççéssïßïlïtý Pölïçý Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
|
||||
|
||||
#: lms/djangoapps/ccx/views.py
|
||||
msgid "You must be a CCX Coach to access this view."
|
||||
msgstr ""
|
||||
@@ -5363,13 +5437,7 @@ msgstr "Wörk ät {platform_name} Ⱡ'σяєм ιρѕυм ∂σłσя #"
|
||||
msgid "Contact {platform_name}"
|
||||
msgstr "Çöntäçt {platform_name} Ⱡ'σяєм ιρѕυм ∂σłσя #"
|
||||
|
||||
#: lms/djangoapps/certificates/views.py cms/templates/widgets/footer.html
|
||||
#: lms/templates/footer-edx-v2.html lms/templates/footer-edx-v3.html
|
||||
#: lms/templates/footer.html lms/templates/static_templates/privacy.html
|
||||
msgid "Privacy Policy"
|
||||
msgstr "Prïväçý Pölïçý Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#"
|
||||
|
||||
#: lms/djangoapps/certificates/views.py lms/templates/footer-edx-v3.html
|
||||
#: lms/djangoapps/certificates/views.py
|
||||
msgid "Terms of Service & Honor Code"
|
||||
msgstr ""
|
||||
"Térms öf Sérvïçé & Hönör Çödé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#"
|
||||
@@ -8427,42 +8495,26 @@ msgstr "Çöüld nöt süßmït phötös Ⱡ'σяєм ιρѕυм ∂σłσя ѕ
|
||||
#. #-#-#-#-# django-partial.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is the website name of www.facebook.com. Please
|
||||
#. translate this the way that Facebook advertises in your language.
|
||||
#. #-#-#-#-# mako.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is the website name of www.facebook.com. Please
|
||||
#. translate this the way that Facebook advertises in your language.
|
||||
#: lms/envs/common.py lms/templates/footer-edx-v3.html
|
||||
#: lms/templates/dashboard/_dashboard_course_listing.html
|
||||
#: lms/envs/common.py lms/templates/dashboard/_dashboard_course_listing.html
|
||||
msgid "Facebook"
|
||||
msgstr "Fäçéßöök Ⱡ'σяєм ιρѕυм ∂#"
|
||||
|
||||
#. #-#-#-#-# django-partial.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is the website name of www.twitter.com. Please
|
||||
#. translate this the way that Twitter advertises in your language.
|
||||
#. #-#-#-#-# mako.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is the website name of www.twitter.com. Please
|
||||
#. translate this the way that Twitter advertises in your language.
|
||||
#: lms/envs/common.py lms/templates/footer-edx-v3.html
|
||||
#: lms/templates/dashboard/_dashboard_course_listing.html
|
||||
#: lms/envs/common.py lms/templates/dashboard/_dashboard_course_listing.html
|
||||
msgid "Twitter"
|
||||
msgstr "Twïttér Ⱡ'σяєм ιρѕυм #"
|
||||
|
||||
#. #-#-#-#-# django-partial.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is the website name of www.linkedin.com. Please
|
||||
#. translate this the way that LinkedIn advertises in your language.
|
||||
#. #-#-#-#-# mako.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is the website name of www.linked.com. Please
|
||||
#. translate this the way that LinkedIn advertises in your language.
|
||||
#: lms/envs/common.py lms/templates/footer-edx-v3.html
|
||||
#: lms/envs/common.py
|
||||
msgid "LinkedIn"
|
||||
msgstr "LïnkédÌn Ⱡ'σяєм ιρѕυм ∂#"
|
||||
|
||||
#. #-#-#-#-# django-partial.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is the website name of plus.google.com. Please
|
||||
#. translate this the way that Google+ advertises in your language.
|
||||
#. #-#-#-#-# mako.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is the website name of plus.google.com. Please
|
||||
#. translate this the way that Google+ advertises in your language.
|
||||
#: lms/envs/common.py lms/templates/footer-edx-v3.html
|
||||
#: lms/envs/common.py
|
||||
msgid "Google+"
|
||||
msgstr "Gööglé+ Ⱡ'σяєм ιρѕυм #"
|
||||
|
||||
@@ -8472,13 +8524,9 @@ msgstr "Gööglé+ Ⱡ'σяєм ιρѕυм #"
|
||||
msgid "Tumblr"
|
||||
msgstr "Tümßlr Ⱡ'σяєм ιρѕυ#"
|
||||
|
||||
#. #-#-#-#-# django-partial.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is the website name of www.meetup.com. Please
|
||||
#. translate this the way that MeetUp advertises in your language.
|
||||
#. #-#-#-#-# mako.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is the website name of www.meetup.com. Please
|
||||
#. translate this the way that Meetup advertises in your language.
|
||||
#: lms/envs/common.py lms/templates/footer-edx-v3.html
|
||||
#: lms/envs/common.py
|
||||
msgid "Meetup"
|
||||
msgstr "Méétüp Ⱡ'σяєм ιρѕυ#"
|
||||
|
||||
@@ -9397,14 +9445,6 @@ msgstr ""
|
||||
"Ýöü müst ägréé tö thé {platform_name} {terms_of_service}. Ⱡ'σяєм ιρѕυм ∂σłσя"
|
||||
" ѕιт αмєт, ¢σηѕє¢т#"
|
||||
|
||||
#. #-#-#-#-# django-partial.po (0.1a) #-#-#-#-#
|
||||
#. Translators: This is a legal document users must agree to
|
||||
#. in order to register a new account.
|
||||
#: openedx/core/djangoapps/user_api/views.py cms/templates/widgets/footer.html
|
||||
#: lms/templates/footer.html lms/templates/static_templates/tos.html
|
||||
msgid "Terms of Service"
|
||||
msgstr "Térms öf Sérvïçé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αм#"
|
||||
|
||||
#: openedx/core/djangoapps/user_api/accounts/api.py
|
||||
msgid "The '{field_name}' field cannot be edited."
|
||||
msgstr ""
|
||||
@@ -10081,13 +10121,6 @@ msgstr ""
|
||||
"Vïsït ýöür {link_start}däshßöärd{link_end} tö séé ýöür çöürsés. Ⱡ'σяєм ιρѕυм"
|
||||
" ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
|
||||
|
||||
#. Translators: 'Open edX' is a brand, please keep this untranslated. See
|
||||
#. http://openedx.org for more information.
|
||||
#: cms/templates/widgets/footer.html lms/templates/footer-edx-v2.html
|
||||
#: lms/templates/footer-edx-v3.html lms/templates/footer.html
|
||||
msgid "Powered by Open edX"
|
||||
msgstr "Pöwéréd ßý Öpén édX Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт,#"
|
||||
|
||||
#: cms/templates/widgets/header.html lms/templates/courseware/courseware.html
|
||||
msgid "Course Navigation"
|
||||
msgstr "Çöürsé Nävïgätïön Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмє#"
|
||||
@@ -10499,7 +10532,7 @@ msgstr ""
|
||||
|
||||
#. Translators: 'EdX', 'edX', and 'Open edX' are trademarks of 'edX Inc.'.
|
||||
#. Please do not translate any of these trademarks and company names.
|
||||
#: lms/templates/footer-edx-v2.html lms/templates/footer.html
|
||||
#: lms/templates/footer-edx-v2.html
|
||||
msgid ""
|
||||
"EdX, Open edX, and the edX and Open edX logos are registered trademarks or "
|
||||
"trademarks of {link_start}edX Inc.{link_end}"
|
||||
@@ -10521,18 +10554,7 @@ msgstr "(Révïséd {date}) Ⱡ'σяєм ιρѕυм ∂σłσя ѕι#"
|
||||
msgid "10/22/2014"
|
||||
msgstr "10/22/2014 Ⱡ'σяєм ιρѕυм ∂σłσ#"
|
||||
|
||||
#: lms/templates/footer-edx-v2.html lms/templates/footer-edx-v3.html
|
||||
#: lms/templates/footer.html
|
||||
msgid "News"
|
||||
msgstr "Néws Ⱡ'σяєм ι#"
|
||||
|
||||
#: lms/templates/footer-edx-v2.html lms/templates/footer-edx-v3.html
|
||||
#: lms/templates/footer.html lms/templates/static_templates/contact.html
|
||||
msgid "Contact"
|
||||
msgstr "Çöntäçt Ⱡ'σяєм ιρѕυм #"
|
||||
|
||||
#: lms/templates/footer-edx-v2.html lms/templates/footer.html
|
||||
#: lms/templates/static_templates/faq.html
|
||||
#: lms/templates/footer-edx-v2.html lms/templates/static_templates/faq.html
|
||||
msgid "FAQ"
|
||||
msgstr "FÀQ Ⱡ'σяєм#"
|
||||
|
||||
@@ -10556,11 +10578,11 @@ msgstr "Föllöw Ûs Ⱡ'σяєм ιρѕυм ∂σł#"
|
||||
msgid "Mobile Apps"
|
||||
msgstr "Mößïlé Àpps Ⱡ'σяєм ιρѕυм ∂σłσя #"
|
||||
|
||||
#: lms/templates/footer-edx-v2.html lms/templates/footer-edx-v3.html
|
||||
#: lms/templates/footer-edx-v2.html
|
||||
msgid "Apple app on Apple Store"
|
||||
msgstr "Àpplé äpp ön Àpplé Störé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢ση#"
|
||||
|
||||
#: lms/templates/footer-edx-v2.html lms/templates/footer-edx-v3.html
|
||||
#: lms/templates/footer-edx-v2.html
|
||||
msgid "Android app on Google Play"
|
||||
msgstr "Àndröïd äpp ön Gööglé Pläý Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕ#"
|
||||
|
||||
@@ -10568,43 +10590,10 @@ msgstr "Àndröïd äpp ön Gööglé Pläý Ⱡ'σяєм ιρѕυм ∂σłσя
|
||||
msgid "Page Footer"
|
||||
msgstr "Pägé Föötér Ⱡ'σяєм ιρѕυм ∂σłσя #"
|
||||
|
||||
#: lms/templates/footer-edx-v3.html lms/templates/static_templates/blog.html
|
||||
msgid "Blog"
|
||||
msgstr "Blög Ⱡ'σяєм ι#"
|
||||
|
||||
#: lms/templates/footer-edx-v3.html
|
||||
msgid "FAQs"
|
||||
msgstr "FÀQs Ⱡ'σяєм ι#"
|
||||
|
||||
#: lms/templates/footer-edx-v3.html lms/templates/footer.html
|
||||
#: lms/templates/static_templates/jobs.html
|
||||
msgid "Jobs"
|
||||
msgstr "Jößs Ⱡ'σяєм ι#"
|
||||
|
||||
#: lms/templates/footer-edx-v3.html lms/templates/static_templates/donate.html
|
||||
msgid "Donate"
|
||||
msgstr "Dönäté Ⱡ'σяєм ιρѕυ#"
|
||||
|
||||
#: lms/templates/footer-edx-v3.html
|
||||
msgid "Sitemap"
|
||||
msgstr "Sïtémäp Ⱡ'σяєм ιρѕυм #"
|
||||
|
||||
#: lms/templates/footer-edx-v3.html lms/templates/footer.html
|
||||
msgid "Legal"
|
||||
msgstr "Légäl Ⱡ'σяєм ιρѕ#"
|
||||
|
||||
#: lms/templates/footer-edx-v3.html
|
||||
msgid "Website Accessibility Policy"
|
||||
msgstr "Wéßsïté Àççéssïßïlïtý Pölïçý Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢#"
|
||||
|
||||
#: lms/templates/footer.html
|
||||
msgid ""
|
||||
"{tos_link_start}Terms of Service{tos_link_end} and {honor_link_start}Honor "
|
||||
"Code{honor_link_end}"
|
||||
msgstr ""
|
||||
"{tos_link_start}Térms öf Sérvïçé{tos_link_end} änd {honor_link_start}Hönör "
|
||||
"Çödé{honor_link_end} Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #"
|
||||
|
||||
#: lms/templates/forgot_password_modal.html
|
||||
msgid "Password Reset"
|
||||
msgstr "Pässwörd Rését Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт#"
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
'''
|
||||
Django admin pages for Video Branding Configuration.
|
||||
'''
|
||||
"""Django admin pages for branding configuration. """
|
||||
from django.contrib import admin
|
||||
from config_models.admin import ConfigurationModelAdmin
|
||||
|
||||
from .models import BrandingInfoConfig
|
||||
from .models import BrandingInfoConfig, BrandingApiConfig
|
||||
|
||||
admin.site.register(BrandingInfoConfig, ConfigurationModelAdmin)
|
||||
admin.site.register(BrandingApiConfig, ConfigurationModelAdmin)
|
||||
|
||||
291
lms/djangoapps/branding/api.py
Normal file
291
lms/djangoapps/branding/api.py
Normal file
@@ -0,0 +1,291 @@
|
||||
"""EdX Branding API
|
||||
|
||||
Provides a way to retrieve "branded" parts of the site,
|
||||
such as the site footer.
|
||||
|
||||
This information exposed to:
|
||||
1) Templates in the LMS.
|
||||
2) Consumers of the branding API.
|
||||
|
||||
This ensures that branded UI elements such as the footer
|
||||
are consistent across the LMS and other sites (such as
|
||||
the marketing site and blog).
|
||||
|
||||
"""
|
||||
import logging
|
||||
import urlparse
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from staticfiles.storage import staticfiles_storage
|
||||
|
||||
from microsite_configuration import microsite
|
||||
from edxmako.shortcuts import marketing_link
|
||||
from branding.models import BrandingApiConfig
|
||||
|
||||
|
||||
log = logging.getLogger("edx.footer")
|
||||
|
||||
|
||||
def is_enabled():
|
||||
"""Check whether the branding API is enabled. """
|
||||
# TODO (ECOM-1339): Remove this comment
|
||||
# Currently, the branding API configuration controls two things:
|
||||
# 1) whether we're using the new version of the footer
|
||||
# 2) whether we're exposing footer information through the API.
|
||||
#
|
||||
# Once we've enabled the new footer, the feature flag will control
|
||||
# only (2), but not (1).
|
||||
return BrandingApiConfig.current().enabled
|
||||
|
||||
|
||||
def get_footer(is_secure=True):
|
||||
"""Retrieve information used to render the footer.
|
||||
|
||||
This will handle both the OpenEdX and EdX.org versions
|
||||
of the footer. All user-facing text is internationalized.
|
||||
|
||||
Currently, this does NOT support theming.
|
||||
|
||||
Keyword Arguments:
|
||||
is_secure (bool): If True, use https:// in URLs.
|
||||
|
||||
Returns: dict
|
||||
|
||||
Example:
|
||||
>>> get_footer()
|
||||
{
|
||||
"copyright": "(c) 2015 EdX Inc",
|
||||
"logo_image": "http://www.example.com/logo.png",
|
||||
"social_links": [
|
||||
{
|
||||
"name": "facebook",
|
||||
"title": "Facebook",
|
||||
"url": "http://www.facebook.com/example",
|
||||
"icon-class": "fa-facebook-square"
|
||||
},
|
||||
...
|
||||
],
|
||||
"navigation_links": [
|
||||
{
|
||||
"name": "about",
|
||||
"title": "About",
|
||||
"url": "http://www.example.com/about.html"
|
||||
},
|
||||
...
|
||||
],
|
||||
"mobile_links": [
|
||||
{
|
||||
"name": "apple",
|
||||
"title": "Apple",
|
||||
"url": "http://store.apple.com/example_app"
|
||||
"image": "http://example.com/static/apple_logo.png"
|
||||
},
|
||||
...
|
||||
],
|
||||
"legal_links": [
|
||||
{
|
||||
"url": "http://example.com/terms-of-service.html",
|
||||
"name": "terms_of_service",
|
||||
"title': "Terms of Service"
|
||||
},
|
||||
# ...
|
||||
],
|
||||
"openedx_link": {
|
||||
"url": "http://open.edx.org",
|
||||
"title": "Powered by Open edX",
|
||||
"image": "http://example.com/openedx.png"
|
||||
}
|
||||
}
|
||||
|
||||
"""
|
||||
return {
|
||||
"copyright": _footer_copyright(),
|
||||
"logo_image": _footer_logo_img(is_secure),
|
||||
"social_links": _footer_social_links(),
|
||||
"navigation_links": _footer_navigation_links(),
|
||||
"mobile_links": _footer_mobile_links(is_secure),
|
||||
"legal_links": _footer_legal_links(),
|
||||
"openedx_link": _footer_openedx_link(),
|
||||
}
|
||||
|
||||
|
||||
def _footer_copyright():
|
||||
"""Return the copyright to display in the footer.
|
||||
|
||||
Returns: unicode
|
||||
|
||||
"""
|
||||
org_name = (
|
||||
"edX Inc" if settings.FEATURES.get('IS_EDX_DOMAIN', False)
|
||||
else microsite.get_value('PLATFORM_NAME', settings.PLATFORM_NAME)
|
||||
)
|
||||
|
||||
# Translators: 'EdX', 'edX', and 'Open edX' are trademarks of 'edX Inc.'.
|
||||
# Please do not translate any of these trademarks and company names.
|
||||
return _(
|
||||
u"\u00A9 {org_name}. All rights reserved except where noted. "
|
||||
u"EdX, Open edX and the edX and Open EdX logos are registered trademarks "
|
||||
u"or trademarks of edX Inc."
|
||||
).format(org_name=org_name)
|
||||
|
||||
|
||||
def _footer_openedx_link():
|
||||
"""Return the image link for "powered by OpenEdX".
|
||||
|
||||
Args:
|
||||
is_secure (bool): Whether the request is using TLS.
|
||||
|
||||
Returns: dict
|
||||
|
||||
"""
|
||||
# Translators: 'Open edX' is a brand, please keep this untranslated.
|
||||
# See http://openedx.org for more information.
|
||||
title = _("Powered by Open edX")
|
||||
return {
|
||||
"url": settings.FOOTER_OPENEDX_URL,
|
||||
"title": title,
|
||||
"image": settings.FOOTER_OPENEDX_LOGO_IMAGE,
|
||||
}
|
||||
|
||||
|
||||
def _footer_social_links():
|
||||
"""Return the social media links to display in the footer.
|
||||
|
||||
Returns: list
|
||||
|
||||
"""
|
||||
links = []
|
||||
for social_name in settings.SOCIAL_MEDIA_FOOTER_NAMES:
|
||||
links.append(
|
||||
{
|
||||
"name": social_name,
|
||||
"title": unicode(settings.SOCIAL_MEDIA_FOOTER_DISPLAY.get(social_name, {}).get("title", "")),
|
||||
"url": settings.SOCIAL_MEDIA_FOOTER_URLS.get(social_name, "#"),
|
||||
"icon-class": settings.SOCIAL_MEDIA_FOOTER_DISPLAY.get(social_name, {}).get("icon", ""),
|
||||
}
|
||||
)
|
||||
return links
|
||||
|
||||
|
||||
def _footer_navigation_links():
|
||||
"""Return the navigation links to display in the footer. """
|
||||
return [
|
||||
{
|
||||
"name": link_name,
|
||||
"title": link_title,
|
||||
"url": link_url,
|
||||
}
|
||||
for link_name, link_url, link_title in [
|
||||
("about", marketing_link("ABOUT"), _("About")),
|
||||
("blog", marketing_link("BLOG"), _("Blog")),
|
||||
("news", marketing_link("NEWS"), _("News")),
|
||||
("faq", marketing_link("FAQ"), _("FAQs")),
|
||||
("contact", marketing_link("CONTACT"), _("Contact")),
|
||||
("jobs", marketing_link("JOBS"), _("Jobs")),
|
||||
("donate", marketing_link("DONATE"), _("Donate")),
|
||||
("sitemap", marketing_link("SITE_MAP"), _("Sitemap")),
|
||||
]
|
||||
if link_url and link_url != "#"
|
||||
]
|
||||
|
||||
|
||||
def _footer_legal_links():
|
||||
"""Return the legal footer links (e.g. terms of service). """
|
||||
|
||||
links = [
|
||||
("terms_of_service_and_honor_code", marketing_link("TOS_AND_HONOR"), _("Terms of Service & Honor Code")),
|
||||
("privacy_policy", marketing_link("PRIVACY"), _("Privacy Policy")),
|
||||
("accessibility_policy", marketing_link("ACCESSIBILITY"), _("Accessibility Policy")),
|
||||
]
|
||||
|
||||
# Backwards compatibility: If a combined "terms of service and honor code"
|
||||
# link isn't provided, add separate TOS and honor code links.
|
||||
tos_and_honor_link = marketing_link("TOS_AND_HONOR")
|
||||
if not (tos_and_honor_link and tos_and_honor_link != "#"):
|
||||
links.extend([
|
||||
("terms_of_service", marketing_link("TOS"), _("Terms of Service")),
|
||||
("honor_code", marketing_link("HONOR"), _("Honor Code")),
|
||||
])
|
||||
|
||||
return [
|
||||
{
|
||||
"name": link_name,
|
||||
"title": link_title,
|
||||
"url": link_url,
|
||||
}
|
||||
for link_name, link_url, link_title in links
|
||||
if link_url and link_url != "#"
|
||||
]
|
||||
|
||||
|
||||
def _footer_mobile_links(is_secure):
|
||||
"""Return the mobile app store links.
|
||||
|
||||
Args:
|
||||
is_secure (bool): Whether the request is using TLS.
|
||||
|
||||
Returns: list
|
||||
|
||||
"""
|
||||
mobile_links = []
|
||||
if settings.FEATURES.get('ENABLE_FOOTER_MOBILE_APP_LINKS'):
|
||||
mobile_links = [
|
||||
{
|
||||
"name": "apple",
|
||||
"title": "Apple",
|
||||
"url": settings.MOBILE_STORE_URLS.get('apple', '#'),
|
||||
"image": _absolute_url_staticfile(is_secure, 'images/app/app_store_badge_135x40.svg')
|
||||
},
|
||||
{
|
||||
"name": "google",
|
||||
"title": "Google",
|
||||
"url": settings.MOBILE_STORE_URLS.get('google', '#'),
|
||||
"image": _absolute_url_staticfile(is_secure, 'images/app/google_play_badge_45.png')
|
||||
}
|
||||
]
|
||||
return mobile_links
|
||||
|
||||
|
||||
def _footer_logo_img(is_secure):
|
||||
"""Return the logo used for footer about link
|
||||
|
||||
Args:
|
||||
is_secure (bool): Whether the request is using TLS.
|
||||
|
||||
Returns:
|
||||
Absolute url to logo
|
||||
"""
|
||||
logo_name = microsite.get_value('FOOTER_ORGANIZATION_IMAGE', settings.FOOTER_ORGANIZATION_IMAGE)
|
||||
return _absolute_url_staticfile(is_secure, logo_name)
|
||||
|
||||
|
||||
def _absolute_url(is_secure, url_path):
|
||||
"""Construct an absolute URL back to the site.
|
||||
|
||||
Arguments:
|
||||
is_secure (bool): If true, use HTTPS as the protocol.
|
||||
url_path (unicode): The path of the URL.
|
||||
|
||||
Returns:
|
||||
unicode
|
||||
|
||||
"""
|
||||
site_name = microsite.get_value('SITE_NAME', settings.SITE_NAME)
|
||||
parts = ("https" if is_secure else "http", site_name, url_path, '', '', '')
|
||||
return urlparse.urlunparse(parts)
|
||||
|
||||
|
||||
def _absolute_url_staticfile(is_secure, name):
|
||||
"""Construct an absolute URL back to a static resource on the site.
|
||||
|
||||
Arguments:
|
||||
is_secure (bool): If true, use HTTPS as the protocol.
|
||||
name (unicode): The name of the static resource to retrieve.
|
||||
|
||||
Returns:
|
||||
unicode
|
||||
|
||||
"""
|
||||
url_path = staticfiles_storage.url(name)
|
||||
return _absolute_url(is_secure, url_path)
|
||||
15
lms/djangoapps/branding/api_urls.py
Normal file
15
lms/djangoapps/branding/api_urls.py
Normal file
@@ -0,0 +1,15 @@
|
||||
"""
|
||||
Branding API endpoint urls.
|
||||
"""
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
urlpatterns = patterns(
|
||||
"",
|
||||
|
||||
url(
|
||||
r"^footer$",
|
||||
"branding.views.footer",
|
||||
name="branding_footer",
|
||||
),
|
||||
)
|
||||
10
lms/djangoapps/branding/context_processors.py
Normal file
10
lms/djangoapps/branding/context_processors.py
Normal file
@@ -0,0 +1,10 @@
|
||||
"""Context processors for Django templates. """
|
||||
from branding import api as branding_api
|
||||
|
||||
|
||||
# TODO (ECOM-1339): Remove this module once we permanently enable the V3 footer.
|
||||
def branding_context_processor(request): # pylint: disable=unused-argument
|
||||
"""Add the feature flag to Django template context. """
|
||||
return {
|
||||
"ENABLE_BRANDING_API": branding_api.is_enabled()
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding model 'BrandingApiConfig'
|
||||
db.create_table('branding_brandingapiconfig', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('change_date', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||
('changed_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, on_delete=models.PROTECT)),
|
||||
('enabled', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||
))
|
||||
db.send_create_signal('branding', ['BrandingApiConfig'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting model 'BrandingApiConfig'
|
||||
db.delete_table('branding_brandingapiconfig')
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'branding.brandingapiconfig': {
|
||||
'Meta': {'object_name': 'BrandingApiConfig'},
|
||||
'change_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'changed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'on_delete': 'models.PROTECT'}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'branding.brandinginfoconfig': {
|
||||
'Meta': {'object_name': 'BrandingInfoConfig'},
|
||||
'change_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'changed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'on_delete': 'models.PROTECT'}),
|
||||
'configuration': ('django.db.models.fields.TextField', [], {}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['branding']
|
||||
@@ -44,3 +44,14 @@ class BrandingInfoConfig(ConfigurationModel):
|
||||
"""
|
||||
info = cls.current()
|
||||
return json.loads(info.configuration) if info.enabled else {}
|
||||
|
||||
|
||||
class BrandingApiConfig(ConfigurationModel):
|
||||
"""Configure Branding api's
|
||||
|
||||
Enable or disable api's functionality.
|
||||
When this flag is disabled, the api will return 404.
|
||||
|
||||
When the flag is enabled, the api will returns the valid reponse.
|
||||
"""
|
||||
pass
|
||||
|
||||
214
lms/djangoapps/branding/tests/test_views.py
Normal file
214
lms/djangoapps/branding/tests/test_views.py
Normal file
@@ -0,0 +1,214 @@
|
||||
# encoding: utf-8
|
||||
"""Tests of Branding API views. """
|
||||
import contextlib
|
||||
import json
|
||||
import urllib
|
||||
from django.test import TestCase
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
|
||||
import mock
|
||||
import ddt
|
||||
from config_models.models import cache
|
||||
from branding.models import BrandingApiConfig
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestFooter(TestCase):
|
||||
"""Test API end-point for retrieving the footer. """
|
||||
|
||||
def setUp(self):
|
||||
"""Clear the configuration cache. """
|
||||
super(TestFooter, self).setUp()
|
||||
cache.clear()
|
||||
|
||||
@ddt.data("*/*", "text/html", "application/json")
|
||||
def test_feature_flag(self, accepts):
|
||||
self._set_feature_flag(False)
|
||||
resp = self._get_footer(accepts=accepts)
|
||||
self.assertEqual(resp.status_code, 404)
|
||||
|
||||
@ddt.data(
|
||||
# Open source version
|
||||
(False, "application/json", "application/json; charset=utf-8", "Open edX"),
|
||||
(False, "text/html", "text/html; charset=utf-8", "lms-footer.css"),
|
||||
(False, "text/html", "text/html; charset=utf-8", "Open edX"),
|
||||
|
||||
# EdX.org version
|
||||
(True, "application/json", "application/json; charset=utf-8", "edX Inc"),
|
||||
(True, "text/html", "text/html; charset=utf-8", "lms-footer-edx.css"),
|
||||
(True, "text/html", "text/html; charset=utf-8", "edX Inc"),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_footer_content_types(self, is_edx_domain, accepts, content_type, content):
|
||||
self._set_feature_flag(True)
|
||||
with self._set_is_edx_domain(is_edx_domain):
|
||||
resp = self._get_footer(accepts=accepts)
|
||||
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(resp["Content-Type"], content_type)
|
||||
self.assertIn(content, resp.content)
|
||||
|
||||
@mock.patch.dict(settings.FEATURES, {'ENABLE_FOOTER_MOBILE_APP_LINKS': True})
|
||||
@ddt.data(True, False)
|
||||
def test_footer_json(self, is_edx_domain):
|
||||
self._set_feature_flag(True)
|
||||
with self._set_is_edx_domain(is_edx_domain):
|
||||
resp = self._get_footer()
|
||||
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
json_data = json.loads(resp.content)
|
||||
self.assertTrue(isinstance(json_data, dict))
|
||||
|
||||
# Logo
|
||||
self.assertIn("logo_image", json_data)
|
||||
|
||||
# Links
|
||||
self.assertIn("navigation_links", json_data)
|
||||
for link in json_data["navigation_links"]:
|
||||
self.assertIn("name", link)
|
||||
self.assertIn("title", link)
|
||||
self.assertIn("url", link)
|
||||
|
||||
# Social links
|
||||
self.assertIn("social_links", json_data)
|
||||
for link in json_data["social_links"]:
|
||||
self.assertIn("name", link)
|
||||
self.assertIn("title", link)
|
||||
self.assertIn("url", link)
|
||||
self.assertIn("icon-class", link)
|
||||
|
||||
# Mobile links
|
||||
self.assertIn("mobile_links", json_data)
|
||||
for link in json_data["mobile_links"]:
|
||||
self.assertIn("name", link)
|
||||
self.assertIn("title", link)
|
||||
self.assertIn("url", link)
|
||||
self.assertIn("image", link)
|
||||
|
||||
# Legal links
|
||||
self.assertIn("legal_links", json_data)
|
||||
for link in json_data["legal_links"]:
|
||||
self.assertIn("name", link)
|
||||
self.assertIn("title", link)
|
||||
self.assertIn("url", link)
|
||||
|
||||
# OpenEdX
|
||||
self.assertIn("openedx_link", json_data)
|
||||
self.assertIn("url", json_data["openedx_link"])
|
||||
self.assertIn("title", json_data["openedx_link"])
|
||||
self.assertIn("image", json_data["openedx_link"])
|
||||
|
||||
# Copyright
|
||||
self.assertIn("copyright", json_data)
|
||||
|
||||
@ddt.data(
|
||||
("en", "registered trademarks"),
|
||||
("eo", u"régïstéréd trädémärks"), # Dummy language string
|
||||
("unknown", "registered trademarks"), # default to English
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_language_override_translation(self, language, expected_copyright):
|
||||
self._set_feature_flag(True)
|
||||
|
||||
# Load the footer with the specified language
|
||||
resp = self._get_footer(params={'language': language})
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
json_data = json.loads(resp.content)
|
||||
|
||||
# Verify that the translation occurred
|
||||
self.assertIn(expected_copyright, json_data['copyright'])
|
||||
|
||||
@ddt.data(
|
||||
# OpenEdX
|
||||
(False, "en", "lms-footer.css"),
|
||||
(False, "ar", "lms-footer-rtl.css"),
|
||||
|
||||
# EdX.org
|
||||
(True, "en", "lms-footer-edx.css"),
|
||||
(True, "ar", "lms-footer-edx-rtl.css"),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_language_rtl(self, is_edx_domain, language, static_path):
|
||||
self._set_feature_flag(True)
|
||||
|
||||
with self._set_is_edx_domain(is_edx_domain):
|
||||
resp = self._get_footer(accepts="text/html", params={'language': language})
|
||||
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertIn(static_path, resp.content)
|
||||
|
||||
@ddt.data(
|
||||
# OpenEdX
|
||||
(False, True),
|
||||
(False, False),
|
||||
|
||||
# EdX.org
|
||||
(True, True),
|
||||
(True, False),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_show_openedx_logo(self, is_edx_domain, show_logo):
|
||||
self._set_feature_flag(True)
|
||||
|
||||
with self._set_is_edx_domain(is_edx_domain):
|
||||
params = {'show-openedx-logo': 1} if show_logo else {}
|
||||
resp = self._get_footer(accepts="text/html", params=params)
|
||||
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
if show_logo:
|
||||
self.assertIn(settings.FOOTER_OPENEDX_URL, resp.content)
|
||||
else:
|
||||
self.assertNotIn(settings.FOOTER_OPENEDX_URL, resp.content)
|
||||
|
||||
@ddt.data(
|
||||
# OpenEdX
|
||||
(False, False),
|
||||
(False, True),
|
||||
|
||||
# EdX.org
|
||||
(True, False),
|
||||
(True, True),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_include_dependencies(self, is_edx_domain, include_dependencies):
|
||||
self._set_feature_flag(True)
|
||||
with self._set_is_edx_domain(is_edx_domain):
|
||||
params = {'include-dependencies': 1} if include_dependencies else {}
|
||||
resp = self._get_footer(accepts="text/html", params=params)
|
||||
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
if include_dependencies:
|
||||
self.assertIn("vendor", resp.content)
|
||||
else:
|
||||
self.assertNotIn("vendor", resp.content)
|
||||
|
||||
def test_no_supported_accept_type(self):
|
||||
self._set_feature_flag(True)
|
||||
resp = self._get_footer(accepts="application/x-shockwave-flash")
|
||||
self.assertEqual(resp.status_code, 406)
|
||||
|
||||
def _set_feature_flag(self, enabled):
|
||||
"""Enable or disable the feature flag for the branding API end-points. """
|
||||
config = BrandingApiConfig(enabled=enabled)
|
||||
config.save()
|
||||
|
||||
def _get_footer(self, accepts="application/json", params=None):
|
||||
"""Retrieve the footer. """
|
||||
url = reverse("branding_footer")
|
||||
|
||||
if params is not None:
|
||||
url = u"{url}?{params}".format(
|
||||
url=url,
|
||||
params=urllib.urlencode(params)
|
||||
)
|
||||
|
||||
return self.client.get(url, HTTP_ACCEPT=accepts)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _set_is_edx_domain(self, is_edx_domain):
|
||||
"""Configure whether this an EdX-controlled domain. """
|
||||
with mock.patch.dict(settings.FEATURES, {'IS_EDX_DOMAIN': is_edx_domain}):
|
||||
yield
|
||||
@@ -1,17 +1,29 @@
|
||||
"""Views for the branding app. """
|
||||
import logging
|
||||
import urllib
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import Http404
|
||||
from django.core.cache import cache
|
||||
from django.views.decorators.cache import cache_control
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.utils import translation
|
||||
from django.shortcuts import redirect
|
||||
from django_future.csrf import ensure_csrf_cookie
|
||||
from staticfiles.storage import staticfiles_storage
|
||||
|
||||
from edxmako.shortcuts import render_to_response
|
||||
import student.views
|
||||
from student.models import CourseEnrollment
|
||||
|
||||
import courseware.views
|
||||
|
||||
from microsite_configuration import microsite
|
||||
from edxmako.shortcuts import marketing_link
|
||||
from util.cache import cache_if_anonymous
|
||||
from util.json_request import JsonResponse
|
||||
import branding.api as branding_api
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_course_enrollments(user):
|
||||
@@ -102,3 +114,198 @@ def courses(request):
|
||||
# we do not expect this case to be reached in cases where
|
||||
# marketing is enabled or the courses are not browsable
|
||||
return courseware.views.courses(request)
|
||||
|
||||
|
||||
def _footer_static_url(request, name):
|
||||
"""Construct an absolute URL to a static asset. """
|
||||
return request.build_absolute_uri(staticfiles_storage.url(name))
|
||||
|
||||
|
||||
def _footer_css_urls(request, package_name):
|
||||
"""Construct absolute URLs to CSS assets in a package. """
|
||||
# We need this to work both in local development and in production.
|
||||
# Unfortunately, in local development we don't run the full asset pipeline,
|
||||
# so fully processed output files may not exist.
|
||||
# For this reason, we use the *css package* name(s), rather than the static file name
|
||||
# to identify the CSS file name(s) to include in the footer.
|
||||
# We then construct an absolute URI so that external sites (such as the marketing site)
|
||||
# can locate the assets.
|
||||
package = settings.PIPELINE_CSS.get(package_name, {})
|
||||
paths = [package['output_filename']] if not settings.DEBUG else package['source_filenames']
|
||||
return [
|
||||
_footer_static_url(request, path)
|
||||
for path in paths
|
||||
]
|
||||
|
||||
|
||||
def _render_footer_html(request, show_openedx_logo, include_dependencies):
|
||||
"""Render the footer as HTML.
|
||||
|
||||
Arguments:
|
||||
show_openedx_logo (bool): If True, include the OpenEdX logo in the rendered HTML.
|
||||
include_dependencies (bool): If True, include JavaScript and CSS dependencies.
|
||||
|
||||
Returns: unicode
|
||||
|
||||
"""
|
||||
bidi = 'rtl' if translation.get_language_bidi() else 'ltr'
|
||||
version = 'edx' if settings.FEATURES.get('IS_EDX_DOMAIN') else 'openedx'
|
||||
css_name = settings.FOOTER_CSS[version][bidi]
|
||||
|
||||
context = {
|
||||
'hide_openedx_link': not show_openedx_logo,
|
||||
'footer_js_url': _footer_static_url(request, 'js/footer-edx.js'),
|
||||
'footer_css_urls': _footer_css_urls(request, css_name),
|
||||
'bidi': bidi,
|
||||
'include_dependencies': include_dependencies,
|
||||
}
|
||||
|
||||
return (
|
||||
render_to_response("footer-edx-v3.html", context)
|
||||
if settings.FEATURES.get("IS_EDX_DOMAIN", False)
|
||||
else render_to_response("footer.html", context)
|
||||
)
|
||||
|
||||
|
||||
@cache_control(must_revalidate=True, max_age=settings.FOOTER_BROWSER_CACHE_MAX_AGE)
|
||||
def footer(request):
|
||||
"""Retrieve the branded footer.
|
||||
|
||||
This end-point provides information about the site footer,
|
||||
allowing for consistent display of the footer across other sites
|
||||
(for example, on the marketing site and blog).
|
||||
|
||||
It can be used in one of two ways:
|
||||
1) A client renders the footer from a JSON description.
|
||||
2) A browser loads an HTML representation of the footer
|
||||
and injects it into the DOM. The HTML includes
|
||||
CSS and JavaScript links.
|
||||
|
||||
In case (2), we assume that the following dependencies
|
||||
are included on the page:
|
||||
a) JQuery (same version as used in edx-platform)
|
||||
b) font-awesome (same version as used in edx-platform)
|
||||
c) Open Sans web fonts
|
||||
|
||||
Example: Retrieving the footer as JSON
|
||||
|
||||
GET /api/branding/v1/footer
|
||||
Accepts: application/json
|
||||
|
||||
{
|
||||
"navigation_links": [
|
||||
{
|
||||
"url": "http://example.com/about",
|
||||
"name": "about",
|
||||
"title": "About"
|
||||
},
|
||||
# ...
|
||||
],
|
||||
"social_links": [
|
||||
{
|
||||
"url": "http://example.com/social",
|
||||
"name": "facebook",
|
||||
"icon-class": "fa-facebook-square",
|
||||
"title": "Facebook"
|
||||
},
|
||||
# ...
|
||||
],
|
||||
"mobile_links": [
|
||||
{
|
||||
"url": "http://example.com/android",
|
||||
"name": "google",
|
||||
"image": "http://example.com/google.png",
|
||||
"title": "Google"
|
||||
},
|
||||
# ...
|
||||
],
|
||||
"legal_links": [
|
||||
{
|
||||
"url": "http://example.com/terms-of-service.html",
|
||||
"name": "terms_of_service",
|
||||
"title': "Terms of Service"
|
||||
},
|
||||
# ...
|
||||
],
|
||||
"openedx_link": {
|
||||
"url": "http://open.edx.org",
|
||||
"title": "Powered by Open edX",
|
||||
"image": "http://example.com/openedx.png"
|
||||
},
|
||||
"logo_image": "http://example.com/static/images/default-theme/logo.png",
|
||||
"copyright": "EdX, Open edX, and the edX and Open edX logos are \
|
||||
registered trademarks or trademarks of edX Inc."
|
||||
}
|
||||
|
||||
|
||||
Example: Retrieving the footer as HTML
|
||||
|
||||
GET /api/branding/v1/footer
|
||||
Accepts: text/html
|
||||
|
||||
|
||||
Example: Including the footer with the "Powered by OpenEdX" logo
|
||||
|
||||
GET /api/branding/v1/footer?show-openedx-logo=1
|
||||
Accepts: text/html
|
||||
|
||||
|
||||
Example: Retrieving the footer in a particular language
|
||||
|
||||
GET /api/branding/v1/footer?language=en
|
||||
Accepts: text/html
|
||||
|
||||
Example: Retrieving the footer with all JS and CSS dependencies (for testing)
|
||||
|
||||
GET /api/branding/v1/footer?include-dependencies=1
|
||||
Accepts: text/html
|
||||
|
||||
"""
|
||||
if not branding_api.is_enabled():
|
||||
raise Http404
|
||||
|
||||
# Use the content type to decide what representation to serve
|
||||
accepts = request.META.get('HTTP_ACCEPT', '*/*')
|
||||
|
||||
# Show the OpenEdX logo in the footer
|
||||
show_openedx_logo = bool(request.GET.get('show-openedx-logo', False))
|
||||
|
||||
# Include JS and CSS dependencies
|
||||
# This is useful for testing the end-point directly.
|
||||
include_dependencies = bool(request.GET.get('include-dependencies', False))
|
||||
|
||||
# Override the language if necessary
|
||||
language = request.GET.get('language', translation.get_language())
|
||||
|
||||
# Render the footer information based on the extension
|
||||
if 'text/html' in accepts or '*/*' in accepts:
|
||||
cache_key = u"branding.footer.{params}.html".format(
|
||||
params=urllib.urlencode({
|
||||
'language': language,
|
||||
'show_openedx_logo': show_openedx_logo,
|
||||
'include_dependencies': include_dependencies,
|
||||
})
|
||||
)
|
||||
content = cache.get(cache_key)
|
||||
if content is None:
|
||||
with translation.override(language):
|
||||
content = _render_footer_html(request, show_openedx_logo, include_dependencies)
|
||||
cache.set(cache_key, content, settings.FOOTER_CACHE_TIMEOUT)
|
||||
return HttpResponse(content, status=200, content_type="text/html; charset=utf-8")
|
||||
|
||||
elif 'application/json' in accepts:
|
||||
cache_key = u"branding.footer.{params}.json".format(
|
||||
params=urllib.urlencode({
|
||||
'language': language,
|
||||
'is_secure': request.is_secure(),
|
||||
})
|
||||
)
|
||||
footer_dict = cache.get(cache_key)
|
||||
if footer_dict is None:
|
||||
with translation.override(language):
|
||||
footer_dict = branding_api.get_footer(is_secure=request.is_secure())
|
||||
cache.set(cache_key, footer_dict, settings.FOOTER_CACHE_TIMEOUT)
|
||||
return JsonResponse(footer_dict, 200, content_type="application/json; charset=utf-8")
|
||||
|
||||
else:
|
||||
return HttpResponse(status=406)
|
||||
|
||||
@@ -18,6 +18,6 @@ Feature: LMS.Homepage for web users
|
||||
| id | Link |
|
||||
| about | About |
|
||||
| jobs | Jobs |
|
||||
| faq | FAQ |
|
||||
| faq | FAQs |
|
||||
| contact | Contact|
|
||||
| news | News |
|
||||
|
||||
@@ -306,7 +306,7 @@ class AboutWithInvitationOnly(ModuleStoreTestCase):
|
||||
url = reverse('about_course', args=[self.course.id.to_deprecated_string()])
|
||||
resp = self.client.get(url)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertIn(u"Register for {}".format(self.course.id.course), resp.content)
|
||||
self.assertIn(u"Register for {}".format(self.course.id.course), resp.content.decode('utf-8'))
|
||||
|
||||
# Check that registration button is present
|
||||
self.assertIn(REG_STR, resp.content)
|
||||
@@ -336,7 +336,7 @@ class AboutTestCaseShibCourse(LoginEnrollmentTestCase, ModuleStoreTestCase):
|
||||
resp = self.client.get(url)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertIn("OOGIE BLOOGIE", resp.content)
|
||||
self.assertIn(u"Register for {}".format(self.course.id.course), resp.content)
|
||||
self.assertIn(u"Register for {}".format(self.course.id.course), resp.content.decode('utf-8'))
|
||||
self.assertIn(SHIB_ERROR_STR, resp.content)
|
||||
self.assertIn(REG_STR, resp.content)
|
||||
|
||||
@@ -348,7 +348,7 @@ class AboutTestCaseShibCourse(LoginEnrollmentTestCase, ModuleStoreTestCase):
|
||||
resp = self.client.get(url)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertIn("OOGIE BLOOGIE", resp.content)
|
||||
self.assertIn(u"Register for {}".format(self.course.id.course), resp.content)
|
||||
self.assertIn(u"Register for {}".format(self.course.id.course), resp.content.decode('utf-8'))
|
||||
self.assertIn(SHIB_ERROR_STR, resp.content)
|
||||
self.assertIn(REG_STR, resp.content)
|
||||
|
||||
|
||||
@@ -14,6 +14,17 @@ from django.test.utils import override_settings
|
||||
@attr('shard_1')
|
||||
class TestFooter(TestCase):
|
||||
|
||||
SOCIAL_MEDIA_NAMES = [
|
||||
"facebook",
|
||||
"google_plus",
|
||||
"twitter",
|
||||
"linkedin",
|
||||
"tumblr",
|
||||
"meetup",
|
||||
"reddit",
|
||||
"youtube",
|
||||
]
|
||||
|
||||
SOCIAL_MEDIA_URLS = {
|
||||
"facebook": "http://www.facebook.com/",
|
||||
"google_plus": "https://plus.google.com/",
|
||||
@@ -51,7 +62,10 @@ class TestFooter(TestCase):
|
||||
self.assertContains(resp, 'wrapper-footer')
|
||||
|
||||
@patch.dict(settings.FEATURES, {'IS_EDX_DOMAIN': True})
|
||||
@override_settings(SOCIAL_MEDIA_FOOTER_URLS=SOCIAL_MEDIA_URLS)
|
||||
@override_settings(
|
||||
SOCIAL_MEDIA_FOOTER_NAMES=SOCIAL_MEDIA_NAMES,
|
||||
SOCIAL_MEDIA_FOOTER_URLS=SOCIAL_MEDIA_URLS
|
||||
)
|
||||
def test_edx_footer_social_links(self):
|
||||
resp = self.client.get('/')
|
||||
for name, url in self.SOCIAL_MEDIA_URLS.iteritems():
|
||||
|
||||
@@ -309,6 +309,13 @@ if FEATURES.get('AUTH_USE_CAS'):
|
||||
# Example: {'CN': 'http://api.xuetangx.com/edx/video?s3_url='}
|
||||
VIDEO_CDN_URL = ENV_TOKENS.get('VIDEO_CDN_URL', {})
|
||||
|
||||
# Branded footer
|
||||
FOOTER_OPENEDX_URL = ENV_TOKENS.get('FOOTER_OPENEDX_URL', FOOTER_OPENEDX_URL)
|
||||
FOOTER_OPENEDX_LOGO_IMAGE = ENV_TOKENS.get('FOOTER_OPENEDX_LOGO_IMAGE', FOOTER_OPENEDX_LOGO_IMAGE)
|
||||
FOOTER_ORGANIZATION_IMAGE = ENV_TOKENS.get('FOOTER_ORGANIZATION_IMAGE', FOOTER_ORGANIZATION_IMAGE)
|
||||
FOOTER_CACHE_TIMEOUT = ENV_TOKENS.get('FOOTER_CACHE_TIMEOUT', FOOTER_CACHE_TIMEOUT)
|
||||
FOOTER_BROWSER_CACHE_MAX_AGE = ENV_TOKENS.get('FOOTER_BROWSER_CACHE_MAX_AGE', FOOTER_BROWSER_CACHE_MAX_AGE)
|
||||
|
||||
############# CORS headers for cross-domain requests #################
|
||||
|
||||
if FEATURES.get('ENABLE_CORS_HEADERS') or FEATURES.get('ENABLE_CROSS_DOMAIN_CSRF_COOKIE'):
|
||||
|
||||
@@ -342,9 +342,6 @@ FEATURES = {
|
||||
# Show the mobile app links in the footer
|
||||
'ENABLE_FOOTER_MOBILE_APP_LINKS': False,
|
||||
|
||||
# Use version 3 of the footer (added May 2015)
|
||||
'ENABLE_FOOTER_V3': False,
|
||||
|
||||
# Let students save and manage their annotations
|
||||
'ENABLE_EDXNOTES': False,
|
||||
|
||||
@@ -507,6 +504,11 @@ TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
# Allows the open edX footer to be leveraged in Django Templates.
|
||||
'edxmako.shortcuts.open_source_footer_context_processor',
|
||||
|
||||
# TODO (ECOM-1339): Remove once the V3 version of the footer is enabled permanently
|
||||
# This allows us to pass the appropriate feature flag to the main Django template
|
||||
# that contains the footer.
|
||||
'branding.context_processors.branding_context_processor',
|
||||
|
||||
# Shoppingcart processor (detects if request.user has a cart)
|
||||
'shoppingcart.context_processor.user_has_cart_context_processor',
|
||||
|
||||
@@ -1039,6 +1041,48 @@ PARENTAL_CONSENT_AGE_LIMIT = 13
|
||||
################################# Jasmine ##################################
|
||||
JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/static/coffee'
|
||||
|
||||
|
||||
######################### Branded Footer ###################################
|
||||
# Constants for the footer used on the site and shared with other sites
|
||||
# (such as marketing and the blog) via the branding API.
|
||||
|
||||
# URL for OpenEdX displayed in the footer
|
||||
FOOTER_OPENEDX_URL = "http://open.edx.org"
|
||||
|
||||
# URL for the OpenEdX logo image
|
||||
# We use logo images served from files.edx.org so we can (roughly) track
|
||||
# how many OpenEdX installations are running.
|
||||
# Site operators can choose from these logo options:
|
||||
# * https://files.edx.org/openedx-logos/edx-openedx-logo-tag.png
|
||||
# * https://files.edx.org/openedx-logos/edx-openedx-logo-tag-light.png"
|
||||
# * https://files.edx.org/openedx-logos/edx-openedx-logo-tag-dark.png
|
||||
FOOTER_OPENEDX_LOGO_IMAGE = "https://files.edx.org/openedx-logos/edx-openedx-logo-tag.png"
|
||||
|
||||
# This is just a placeholder image.
|
||||
# Site operators can customize this with their organization's image.
|
||||
FOOTER_ORGANIZATION_IMAGE = "images/default-theme/logo.png"
|
||||
|
||||
# These are referred to both by the Django asset pipeline
|
||||
# AND by the branding footer API, which needs to decide which
|
||||
# version of the CSS to serve.
|
||||
FOOTER_CSS = {
|
||||
"openedx": {
|
||||
"ltr": "style-lms-footer",
|
||||
"rtl": "style-lms-footer-rtl",
|
||||
},
|
||||
"edx": {
|
||||
"ltr": "style-lms-footer-edx",
|
||||
"rtl": "style-lms-footer-edx-rtl",
|
||||
},
|
||||
}
|
||||
|
||||
# Cache expiration for the version of the footer served
|
||||
# by the branding API.
|
||||
FOOTER_CACHE_TIMEOUT = 30 * 60
|
||||
|
||||
# Max age cache control header for the footer (controls browser caching).
|
||||
FOOTER_BROWSER_CACHE_MAX_AGE = 5 * 60
|
||||
|
||||
################################# Deprecation warnings #####################
|
||||
|
||||
# Ignore deprecation warnings (so we don't clutter Jenkins builds/production)
|
||||
@@ -1182,8 +1226,7 @@ dashboard_js = (
|
||||
['js/search/dashboard/main.js']
|
||||
)
|
||||
discussion_js = sorted(rooted_glob(COMMON_ROOT / 'static', 'coffee/src/discussion/**/*.js'))
|
||||
rwd_header_footer_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/common_helpers/rwd_header_footer.js'))
|
||||
footer_edx_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/footer-edx.js'))
|
||||
rwd_header_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/utils/rwd_header.js'))
|
||||
staff_grading_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/staff_grading/**/*.js'))
|
||||
open_ended_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/open_ended/**/*.js'))
|
||||
notes_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/notes/**/*.js'))
|
||||
@@ -1196,7 +1239,7 @@ instructor_dash_js = (
|
||||
# These are not courseware, so they do not need many of the courseware-specific
|
||||
# JavaScript modules.
|
||||
student_account_js = [
|
||||
'js/utils/rwd_header_footer.js',
|
||||
'js/utils/rwd_header.js',
|
||||
'js/utils/edx.utils.validate.js',
|
||||
'js/form.ext.js',
|
||||
'js/my_courses_dropdown.js',
|
||||
@@ -1342,17 +1385,29 @@ PIPELINE_CSS = {
|
||||
],
|
||||
'output_filename': 'css/lms-style-xmodule-annotations.css',
|
||||
},
|
||||
'style-edx-footer': {
|
||||
FOOTER_CSS['openedx']['ltr']: {
|
||||
'source_filenames': [
|
||||
'sass/footer-v3.css',
|
||||
'sass/lms-footer.css',
|
||||
],
|
||||
'output_filename': 'css/lms-footer-edx.css',
|
||||
'output_filename': 'css/lms-footer.css',
|
||||
},
|
||||
'style-edx-footer-rtl': {
|
||||
FOOTER_CSS['openedx']['rtl']: {
|
||||
'source_filenames': [
|
||||
'sass/footer-v3-rtl.css',
|
||||
'sass/lms-footer-rtl.css',
|
||||
],
|
||||
'output_filename': 'css/lms-footer-edx-rtl.css',
|
||||
'output_filename': 'css/lms-footer-rtl.css'
|
||||
},
|
||||
FOOTER_CSS['edx']['ltr']: {
|
||||
'source_filenames': [
|
||||
'sass/lms-footer-edx.css',
|
||||
],
|
||||
'output_filename': 'css/lms-footer-edx.css'
|
||||
},
|
||||
FOOTER_CSS['edx']['rtl']: {
|
||||
'source_filenames': [
|
||||
'sass/lms-footer-edx-rtl.css',
|
||||
],
|
||||
'output_filename': 'css/lms-footer-edx-rtl.css'
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1423,9 +1478,9 @@ PIPELINE_JS = {
|
||||
'source_filenames': dashboard_js,
|
||||
'output_filename': 'js/dashboard.js'
|
||||
},
|
||||
'rwd_header_footer': {
|
||||
'source_filenames': rwd_header_footer_js,
|
||||
'output_filename': 'js/rwd_header_footer.js'
|
||||
'rwd_header': {
|
||||
'source_filenames': rwd_header_js,
|
||||
'output_filename': 'js/rwd_header.js'
|
||||
},
|
||||
'student_account': {
|
||||
'source_filenames': student_account_js,
|
||||
@@ -1448,8 +1503,8 @@ PIPELINE_JS = {
|
||||
'output_filename': 'js/ccx.js'
|
||||
},
|
||||
'footer_edx': {
|
||||
'source_filenames': footer_edx_js,
|
||||
'output_filename': 'js/footer_edx.js'
|
||||
'source_filenames': ['js/footer-edx.js'],
|
||||
'output_filename': 'js/footer-edx.js',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1492,6 +1547,7 @@ PIPELINE_UGLIFYJS_BINARY = 'node_modules/.bin/uglifyjs'
|
||||
# Setting that will only affect the edX version of django-pipeline until our changes are merged upstream
|
||||
PIPELINE_COMPILE_INPLACE = True
|
||||
|
||||
|
||||
################################# CELERY ######################################
|
||||
|
||||
# Message configuration
|
||||
@@ -1797,25 +1853,14 @@ MKTG_URL_LINK_MAP = {
|
||||
################# Social Media Footer Links #######################
|
||||
# The names list controls the order of social media
|
||||
# links in the footer.
|
||||
if FEATURES.get('ENABLE_FOOTER_V3'):
|
||||
SOCIAL_MEDIA_FOOTER_NAMES = [
|
||||
"facebook",
|
||||
"twitter",
|
||||
"linkedin",
|
||||
"weibo",
|
||||
"vk",
|
||||
]
|
||||
else:
|
||||
SOCIAL_MEDIA_FOOTER_NAMES = [
|
||||
"facebook",
|
||||
"twitter",
|
||||
"linkedin",
|
||||
"google_plus",
|
||||
"tumblr",
|
||||
"meetup",
|
||||
"reddit",
|
||||
"youtube",
|
||||
]
|
||||
SOCIAL_MEDIA_FOOTER_NAMES = [
|
||||
"facebook",
|
||||
"twitter",
|
||||
"youtube",
|
||||
"linkedin",
|
||||
"google_plus",
|
||||
"reddit",
|
||||
]
|
||||
|
||||
# The footer URLs dictionary maps social footer names
|
||||
# to URLs defined in configuration.
|
||||
@@ -1852,7 +1897,7 @@ SOCIAL_MEDIA_FOOTER_DISPLAY = {
|
||||
# Translators: This is the website name of www.tumblr.com. Please
|
||||
# translate this the way that Tumblr advertises in your language.
|
||||
"title": _("Tumblr"),
|
||||
"icon": "fa-tumblr-square"
|
||||
"icon": "fa-tumblr"
|
||||
},
|
||||
"meetup": {
|
||||
# Translators: This is the website name of www.meetup.com. Please
|
||||
@@ -1864,7 +1909,7 @@ SOCIAL_MEDIA_FOOTER_DISPLAY = {
|
||||
# Translators: This is the website name of www.reddit.com. Please
|
||||
# translate this the way that Reddit advertises in your language.
|
||||
"title": _("Reddit"),
|
||||
"icon": "fa-reddit-square"
|
||||
"icon": "fa-reddit"
|
||||
},
|
||||
"vk": {
|
||||
# Translators: This is the website name of https://vk.com. Please
|
||||
@@ -1882,7 +1927,7 @@ SOCIAL_MEDIA_FOOTER_DISPLAY = {
|
||||
# Translators: This is the website name of www.youtube.com. Please
|
||||
# translate this the way that YouTube advertises in your language.
|
||||
"title": _("Youtube"),
|
||||
"icon": "fa-youtube-square"
|
||||
"icon": "fa-youtube"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,18 +7,6 @@ var edx = edx || {};
|
||||
var _fn = {
|
||||
el: '#footer-edx-v3',
|
||||
|
||||
init: function() {
|
||||
_fn.$el = _fn.$el || $( _fn.el );
|
||||
|
||||
/**
|
||||
* Only continue if the expected element
|
||||
* to add footer to is in the DOM
|
||||
*/
|
||||
if ( _fn.$el.length > -1 ) {
|
||||
_fn.footer.get();
|
||||
}
|
||||
},
|
||||
|
||||
analytics: {
|
||||
init: function() {
|
||||
_fn.$el = _fn.$el || $( _fn.el );
|
||||
@@ -27,7 +15,7 @@ var edx = edx || {};
|
||||
* Only continue if the expected element
|
||||
* to add footer to is in the DOM
|
||||
*/
|
||||
if ( _fn.$el.length > -1 ) {
|
||||
if ( _fn.$el.length ) {
|
||||
_fn.analytics.eventListener();
|
||||
}
|
||||
},
|
||||
@@ -50,31 +38,12 @@ var edx = edx || {};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
footer: {
|
||||
get: function() {
|
||||
$.ajax({
|
||||
url: 'https://courses.edx.org/api/v1/branding/footer',
|
||||
type: 'GET',
|
||||
dataType: 'html',
|
||||
success: function( data ) {
|
||||
_fn.footer.render( data );
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render: function( html ) {
|
||||
_fn.$el.html( html );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
load: _fn.init,
|
||||
analytics: _fn.analytics.init
|
||||
};
|
||||
})();
|
||||
|
||||
// Initialize the analytics events
|
||||
edx.footer.analytics();
|
||||
})(jQuery);
|
||||
|
||||
19
lms/static/sass/_build-footer-edx.scss
Normal file
19
lms/static/sass/_build-footer-edx.scss
Normal file
@@ -0,0 +1,19 @@
|
||||
// ----------------------------------------
|
||||
// LMS edx.org Footer: Shared Build Compile
|
||||
|
||||
// base - utilities
|
||||
@import 'base/variables';
|
||||
@import 'base/mixins';
|
||||
|
||||
footer#footer-edx-v3 {
|
||||
@import 'base/extends';
|
||||
|
||||
// base - starter
|
||||
@import 'base/base';
|
||||
}
|
||||
|
||||
// base - elements
|
||||
@import 'elements/typography';
|
||||
|
||||
// shared - platform
|
||||
@import 'shared/footer-edx';
|
||||
@@ -21,7 +21,7 @@
|
||||
@import 'shared/fields';
|
||||
@import 'shared/forms';
|
||||
@import 'shared/footer';
|
||||
@import 'shared/footer-edx'; // Replaces most of the footer partial. Will update footer to remove edx specific styles once feature flag removed.
|
||||
@import 'shared/footer-edx';
|
||||
@import 'shared/header';
|
||||
@import 'shared/course_object';
|
||||
@import 'shared/course_filter';
|
||||
|
||||
7
lms/static/sass/base/_variables-ltr.scss
Normal file
7
lms/static/sass/base/_variables-ltr.scss
Normal file
@@ -0,0 +1,7 @@
|
||||
// Variables for LMS (left-to-right)
|
||||
// ==================================
|
||||
|
||||
// Neat
|
||||
// ==================================
|
||||
// Sets the default layout direction of the grid.
|
||||
$default-layout-direction: LTR !global;
|
||||
7
lms/static/sass/base/_variables-rtl.scss
Normal file
7
lms/static/sass/base/_variables-rtl.scss
Normal file
@@ -0,0 +1,7 @@
|
||||
// Variables for LMS (right-to-left)
|
||||
// ==================================
|
||||
|
||||
// Neat
|
||||
// ==================================
|
||||
// Sets the default layout direction of the grid.
|
||||
$default-layout-direction: RTL !global;
|
||||
10
lms/static/sass/lms-footer-edx-rtl.scss
Normal file
10
lms/static/sass/lms-footer-edx-rtl.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
// Footer for edx.org (right-to-left)
|
||||
// ==================================
|
||||
|
||||
// libs and resets *do not edit*
|
||||
@import 'bourbon/bourbon'; // lib - bourbon
|
||||
@import 'vendor/bi-app/bi-app-rtl'; // set the layout for right to left languages
|
||||
@import 'base/variables-rtl';
|
||||
|
||||
// Import shared build for the edx.org footer
|
||||
@import 'build-footer-edx'
|
||||
10
lms/static/sass/lms-footer-edx.scss
Normal file
10
lms/static/sass/lms-footer-edx.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
// Footer for edx.org (left-to-right)
|
||||
// ==================================
|
||||
|
||||
// libs and resets *do not edit*
|
||||
@import 'bourbon/bourbon'; // lib - bourbon
|
||||
@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages
|
||||
@import 'base/variables-ltr';
|
||||
|
||||
// Import shared build for the edx.org footer
|
||||
@import 'build-footer-edx'
|
||||
@@ -1,14 +1,9 @@
|
||||
## Note: This Sass infrastructure is repeated in application-extend1 and application-extend2, but needed in order to address an IE9 rule limit within CSS - http://blogs.msdn.com/b/ieinternals/archive/2011/05/14/10164546.aspx
|
||||
|
||||
// lms - css application architecture
|
||||
// ====================
|
||||
// Footer for OpenEdX (right-to-left)
|
||||
// ==================================
|
||||
|
||||
// libs and resets *do not edit*
|
||||
@import 'bourbon/bourbon'; // lib - bourbon
|
||||
@import 'vendor/bi-app/bi-app-rtl'; // set the layout for left to right languages
|
||||
|
||||
// BASE *default edX offerings*
|
||||
// ====================
|
||||
@import 'vendor/bi-app/bi-app-rtl'; // set the layout for right to left languages
|
||||
|
||||
// base - utilities
|
||||
@import 'base/variables';
|
||||
@@ -27,19 +22,14 @@
|
||||
@import '${env.get('THEME_NAME')}';
|
||||
% endif
|
||||
|
||||
// base - assets
|
||||
@import 'base/font_face';
|
||||
|
||||
footer#footer-edx-v3 {
|
||||
footer#footer-openedx {
|
||||
@import 'base/reset';
|
||||
@import 'base/extends';
|
||||
|
||||
// base - starter
|
||||
@import 'base/base';
|
||||
|
||||
}
|
||||
|
||||
// base - elements
|
||||
@import 'elements/typography';
|
||||
|
||||
// shared - platform
|
||||
@import 'shared/footer-edx';
|
||||
@import 'shared/footer';
|
||||
@@ -1,15 +1,10 @@
|
||||
## Note: This Sass infrastructure is repeated in application-extend1 and application-extend2, but needed in order to address an IE9 rule limit within CSS - http://blogs.msdn.com/b/ieinternals/archive/2011/05/14/10164546.aspx
|
||||
|
||||
// lms - css application architecture
|
||||
// ====================
|
||||
// Footer for OpenEdX (left-to-right)
|
||||
// ==================================
|
||||
|
||||
// libs and resets *do not edit*
|
||||
@import 'bourbon/bourbon'; // lib - bourbon
|
||||
@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages
|
||||
|
||||
// BASE *default edX offerings*
|
||||
// ====================
|
||||
|
||||
// base - utilities
|
||||
@import 'base/variables';
|
||||
@import 'base/mixins';
|
||||
@@ -27,19 +22,14 @@
|
||||
@import '${env.get('THEME_NAME')}';
|
||||
% endif
|
||||
|
||||
// base - assets
|
||||
@import 'base/font_face';
|
||||
|
||||
footer#footer-edx-v3 {
|
||||
footer#footer-openedx {
|
||||
@import 'base/reset';
|
||||
@import 'base/extends';
|
||||
|
||||
// base - starter
|
||||
@import 'base/base';
|
||||
|
||||
}
|
||||
|
||||
// base - elements
|
||||
@import 'elements/typography';
|
||||
|
||||
// shared - platform
|
||||
@import 'shared/footer-edx';
|
||||
@import 'shared/footer';
|
||||
@@ -4,6 +4,7 @@
|
||||
// libs and resets *do not edit*
|
||||
@import 'bourbon/bourbon'; // lib - bourbon
|
||||
@import 'vendor/bi-app/bi-app-rtl'; // set the layout for right to left languages
|
||||
@import 'base/variables-rtl';
|
||||
|
||||
// BASE *default edX offerings*
|
||||
// ====================
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
// libs and resets *do not edit*
|
||||
@import 'bourbon/bourbon'; // lib - bourbon
|
||||
@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages
|
||||
@import 'base/variables-ltr';
|
||||
|
||||
// BASE *default edX offerings*
|
||||
// ====================
|
||||
|
||||
@@ -80,7 +80,7 @@ footer#footer-edx-v3 {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.sm-link {
|
||||
a.sm-link {
|
||||
@include float(left);
|
||||
@include margin(0, 0, 10px, 12px);
|
||||
@include font-size(28);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
background: $footer-bg;
|
||||
clear: both;
|
||||
|
||||
footer {
|
||||
footer#footer-openedx {
|
||||
@include clearfix();
|
||||
@include box-sizing(border-box);
|
||||
max-width: grid-width(12);
|
||||
@@ -286,6 +286,8 @@ $edx-footer-bg-color: rgb(252,252,252);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO (ECOM-1339): Remove the "new" (v2) footer once the v3 footer
|
||||
// is permanently enabled.
|
||||
.edx-footer-new {
|
||||
background: $edx-footer-bg-color;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ ${_("Receipt")}
|
||||
|
||||
</%block>
|
||||
<%block name="js_extra">
|
||||
<%static:js group='rwd_header_footer'/>
|
||||
<%static:js group='rwd_header'/>
|
||||
<script src="${static.url('js/vendor/jquery.ajax-retry.js')}"></script>
|
||||
<script src="${static.url('js/vendor/underscore-min.js')}"></script>
|
||||
<script src="${static.url('js/vendor/underscore.string.min.js')}"></script>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
## mako
|
||||
## TODO (ECOM-1339): Delete this template once the V3 footer is enabled
|
||||
<%! from django.core.urlresolvers import reverse %>
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%namespace name='static' file='static_content.html'/>
|
||||
@@ -50,7 +51,7 @@
|
||||
</div>
|
||||
|
||||
<div class="footer-about-links">
|
||||
<a href="${marketing_link('TOS')}"><span class="copy">${_("Terms of Service and Honor Code")}</span></a>
|
||||
<a href="${marketing_link('TOS_AND_HONOR')}"><span class="copy">${_("Terms of Service and Honor Code")}</span></a>
|
||||
<a href="${marketing_link('PRIVACY')}"><span class="copy">${_("Privacy Policy")}</span>
|
||||
<span class="note">
|
||||
## Translators: {date} will be an abbreviated date, indicating when the privacy policy was most recently revised.
|
||||
|
||||
@@ -1,90 +1,80 @@
|
||||
## mako
|
||||
<%! from django.core.urlresolvers import reverse %>
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%!
|
||||
from django.utils.translation import ugettext as _
|
||||
from branding.api import get_footer
|
||||
%>
|
||||
<% footer = get_footer(is_secure=is_secure) %>
|
||||
<%namespace name='static' file='static_content.html'/>
|
||||
|
||||
## WARNING: These files are specific to edx.org and are not used in installations outside of that domain. Open edX users will want to use the file "footer.html" for any changes or overrides.
|
||||
<footer id="footer-edx-v3" role="contentinfo" aria-label="${_("Page Footer")}">
|
||||
<footer id="footer-edx-v3" role="contentinfo" aria-label="${_("Page Footer")}"
|
||||
## When rendering the footer through the branding API,
|
||||
## the direction may not be set on the parent element,
|
||||
## so we set it here.
|
||||
% if bidi:
|
||||
dir=${bidi}
|
||||
% endif
|
||||
>
|
||||
<h2 class="sr footer-about-title">${_("About edX")}</h2>
|
||||
|
||||
<div class="footer-logo">
|
||||
<img alt="edX logo" src="${static.url('images/edx-theme/edx-header-logo.png')}">
|
||||
<img alt="edX logo" src="${footer['logo_image']}">
|
||||
</div>
|
||||
|
||||
<div class="site-details">
|
||||
<nav class="site-nav" aria-label="${_("About edX")}">
|
||||
<a href="${marketing_link('ABOUT')}">${_("About")}</a>
|
||||
<a href="${marketing_link('BLOG')}">${_("Blog")}</a>
|
||||
<a href="${marketing_link('NEWS')}">${_("News")}</a>
|
||||
<a href="${marketing_link('FAQ')}">${_("FAQs")}</a>
|
||||
<a href="${marketing_link('CONTACT')}">${_("Contact")}</a>
|
||||
<a href="${marketing_link('JOBS')}">${_("Jobs")}</a>
|
||||
<a href="${marketing_link('DONATE')}">${_("Donate")}</a>
|
||||
<a href="${marketing_link('DONATE')}">${_("Sitemap")}</a>
|
||||
% for link in footer["navigation_links"]:
|
||||
<a href="${link['url']}">${link['title']}</a>
|
||||
% endfor
|
||||
</nav>
|
||||
<nav class="legal-notices" aria-label="${_("Legal")}">
|
||||
<a href="${marketing_link('TOS')}">${_("Terms of Service & Honor Code")}</a>
|
||||
<a href="${marketing_link('PRIVACY')}">${_("Privacy Policy")}</a>
|
||||
<a href="${marketing_link('PRIVACY')}">${_("Website Accessibility Policy")}</a>
|
||||
% for link in footer["legal_links"]:
|
||||
<a href="${link['url']}">${link['title']}</a>
|
||||
% endfor
|
||||
</nav>
|
||||
<p class="copyright">
|
||||
## Using "edX Inc." explicitly here for copyright purposes (settings.PLATFORM_NAME is just "edX", and this footer is only used on edx.org)
|
||||
## Site operators: Please do not remove this paragraph! This attributes back to edX and makes your acknowledgement of edX's trademarks clear.
|
||||
<p>© ${settings.COPYRIGHT_YEAR} edX Inc. All rights reserved except where noted. EdX, Open edX and the edX and Open edX logos are registered trademarks of trademarks of edX Inc.</p>
|
||||
</p>
|
||||
<p class="copyright">${footer['copyright']}</p>
|
||||
|
||||
## The OpenEdX link may be hidden when this view is served
|
||||
## through an API to partner sites (such as marketing sites or blogs),
|
||||
## which are not technically powered by OpenEdX.
|
||||
% if not hide_openedx_link:
|
||||
<div class="openedx-link">
|
||||
<a href="http://open.edx.org" title="${_("Powered by Open edX")}">
|
||||
<img alt="${_("Powered by Open edX")}" src="https://files.edx.org/openedx-logos/edx-openedx-logo-tag.png">
|
||||
<a href="${footer['openedx_link']['url']}" title="${footer['openedx_link']['title']}">
|
||||
<img alt="${footer['openedx_link']['title']}" src="${footer['openedx_link']['image']}" width="140">
|
||||
</a>
|
||||
</div>
|
||||
% endif
|
||||
</div>
|
||||
|
||||
<div class="external-links">
|
||||
<div class="social-media-links">
|
||||
## Translators: This is the website name of www.facebook.com. Please
|
||||
## translate this the way that Facebook advertises in your language.
|
||||
<a href="${settings.SOCIAL_MEDIA_FOOTER_URLS.get('facebook', '#')}" class="sm-link external" title="${_("Facebook")}" rel="noreferrer">
|
||||
<span class="icon fa fa-facebook-square element-invisible"></span>
|
||||
</a>
|
||||
<div class="social-media-links">
|
||||
% for link in footer['social_links']:
|
||||
<a href="${link['url']}" class="sm-link external" title="${link['title']}" rel="noreferrer">
|
||||
<span class="icon fa ${link['icon-class']}" aria-hidden="true"></span>
|
||||
</a>
|
||||
% endfor
|
||||
</div>
|
||||
|
||||
## Translators: This is the website name of www.twitter.com. Please
|
||||
## translate this the way that Twitter advertises in your language.
|
||||
<a href="${settings.SOCIAL_MEDIA_FOOTER_URLS.get('twitter', '#')}" class="sm-link external" title="${_("Twitter")}" rel="noreferrer">
|
||||
<span class="icon fa fa-twitter element-invisible"></span>
|
||||
</a>
|
||||
|
||||
## Translators: This is the website name of www.linked.com. Please
|
||||
## translate this the way that LinkedIn advertises in your language.
|
||||
<a href="${settings.SOCIAL_MEDIA_FOOTER_URLS.get('linkedin', '#')}" class="sm-link external" title="${_("LinkedIn")}" rel="noreferrer">
|
||||
<span class="icon fa fa-linkedin-square element-invisible"></span>
|
||||
</a>
|
||||
|
||||
## Translators: This is the website name of plus.google.com. Please
|
||||
## translate this the way that Google+ advertises in your language.
|
||||
<a href="${settings.SOCIAL_MEDIA_FOOTER_URLS.get('facebook', '#')}" class="sm-link external" title="${_("Google+")}" rel="noreferrer">
|
||||
<span class="icon fa fa-weibo element-invisible"></span>
|
||||
</a>
|
||||
|
||||
## Translators: This is the website name of www.meetup.com. Please
|
||||
## translate this the way that Meetup advertises in your language.
|
||||
<a href="${settings.SOCIAL_MEDIA_FOOTER_URLS.get('facebook', '#')}" class="sm-link external" title="${_("Meetup")}" rel="noreferrer">
|
||||
<span class="icon fa fa-vk element-invisible"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
## % if settings.FEATURES.get('ENABLE_FOOTER_MOBILE_APP_LINKS'):
|
||||
<div class="mobile-app-links">
|
||||
<a href="${settings.MOBILE_STORE_URLS.get('apple', '#')}" class="app-link external">
|
||||
<img class="app-store" alt="${_("Apple app on Apple Store")}" src="${static.url('images/app/app_store_badge_135x40.svg')}">
|
||||
</a>
|
||||
<a href="${settings.MOBILE_STORE_URLS.get('google', '#')}" class="app-link external">
|
||||
<img class="google-play" alt="${_("Android app on Google Play")}" src="${static.url('images/app/google_play_badge_45.png')}">
|
||||
</a>
|
||||
</div>
|
||||
## % endif
|
||||
<div class="mobile-app-links">
|
||||
% for link in footer['mobile_links']:
|
||||
<a href="${link['url']}" class="app-link external">
|
||||
<img alt="${link['title']}" src="${link['image']}">
|
||||
</a>
|
||||
% endfor
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
% if include_dependencies:
|
||||
<%static:js group='base_vendor'/>
|
||||
<%static:css group='style-vendor'/>
|
||||
<%include file="widgets/segment-io.html" />
|
||||
% endif
|
||||
% if footer_css_urls:
|
||||
% for url in footer_css_urls:
|
||||
<link rel="stylesheet" type="text/css" href="${url}"></link>
|
||||
% endfor
|
||||
% endif
|
||||
% if footer_js_url:
|
||||
<script type="text/javascript" src="${footer_js_url}"></script>
|
||||
% endif
|
||||
|
||||
<script type="text/javascript" src="/static/js/vendor/noreferrer.js" charset="utf-8"></script>
|
||||
<%block name="js_extra">
|
||||
<%static:js group='footer_edx'/>
|
||||
</%block>
|
||||
|
||||
@@ -1,108 +1,83 @@
|
||||
## mako
|
||||
<%! from django.core.urlresolvers import reverse %>
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%!
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from branding.api import get_footer
|
||||
%>
|
||||
<% footer = get_footer(is_secure=is_secure) %>
|
||||
<%namespace name='static' file='static_content.html'/>
|
||||
<%! from microsite_configuration.templatetags.microsite import platform_name %>
|
||||
|
||||
<div class="wrapper wrapper-footer">
|
||||
<footer>
|
||||
<footer id="footer-openedx"
|
||||
## When rendering the footer through the branding API,
|
||||
## the direction may not be set on the parent element,
|
||||
## so we set it here.
|
||||
% if bidi:
|
||||
dir=${bidi}
|
||||
% endif
|
||||
>
|
||||
<div class="colophon">
|
||||
<nav class="nav-colophon" aria-label="${_('About')}">
|
||||
<ol>
|
||||
<li class="nav-colophon-01">
|
||||
<a id="about" href="${marketing_link('ABOUT')}">
|
||||
${_("About")}
|
||||
</a>
|
||||
</li>
|
||||
%if marketing_link('JOBS') and marketing_link('JOBS') != '#':
|
||||
<li class="nav-colophon-02">
|
||||
<a id="jobs" href="${marketing_link('JOBS')}">
|
||||
${_("Jobs")}
|
||||
</a>
|
||||
<ol>
|
||||
% for item_num, link in enumerate(footer['navigation_links'], start=1):
|
||||
<li class="nav-colophon-0${item_num}">
|
||||
<a id="${link['name']}" href="${link['url']}">${link['title']}</a>
|
||||
</li>
|
||||
%endif
|
||||
%if marketing_link('NEWS') and marketing_link('NEWS') != '#':
|
||||
<li class="nav-colophon-03">
|
||||
<a id="news" href="${marketing_link('NEWS')}">
|
||||
${_("News")}
|
||||
</a>
|
||||
</li>
|
||||
%endif
|
||||
<li class="nav-colophon-04">
|
||||
<a id="faq" href="${marketing_link('FAQ')}">
|
||||
${_("FAQ")}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-colophon-05">
|
||||
<a id="contact" href="${marketing_link('CONTACT')}">
|
||||
${_("Contact")}
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
% endfor
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="wrapper-logo">
|
||||
<p>
|
||||
<a href="/">
|
||||
## this is just a placeholder logo
|
||||
## feel free to change this logo to your own by replacing "logo.png" with your own logo
|
||||
<img alt="organization logo placeholder" src="/static/images/default-theme/logo.png">
|
||||
## The default logo is a placeholder.
|
||||
## You can either replace this link entirely or update
|
||||
## the FOOTER_ORGANIZATION_IMAGE in Django settings.
|
||||
## If you customize FOOTER_ORGANIZATION_IMAGE, then the image
|
||||
## can be included in the footer on other sites
|
||||
## (e.g. a blog or marketing front-end) to provide a consistent
|
||||
## user experience. See the branding app for details.
|
||||
<img alt="organization logo" src="${footer['logo_image']}">
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="copyright">© ${settings.COPYRIGHT_YEAR} ${settings.PLATFORM_NAME}.</p>
|
||||
|
||||
## Site operators: Please do not remove this paragraph! This attributes back to edX and makes your acknowledgement of edX's trademarks clear.
|
||||
<p class="copyright">
|
||||
## Translators: 'EdX', 'edX', and 'Open edX' are trademarks of 'edX Inc.'. Please do not translate any of these trademarks and company names.
|
||||
${_("EdX, Open edX, and the edX and Open edX logos are registered trademarks or trademarks of {link_start}edX Inc.{link_end}").format(
|
||||
link_start=u"<a href='https://www.edx.org/'>",
|
||||
link_end=u"</a>"
|
||||
)}
|
||||
</p>
|
||||
<p class="copyright">${footer['copyright']}</p>
|
||||
|
||||
<nav class="nav-legal" aria-label="${_('Legal')}">
|
||||
<ul>
|
||||
% if marketing_link('HONOR') and marketing_link('HONOR') != '#':
|
||||
<li class="nav-legal-01">
|
||||
<%
|
||||
tos_link = u"<a href='{}'>".format(marketing_link('TOS'))
|
||||
honor_link = u"<a href='{}'>".format(marketing_link('HONOR'))
|
||||
%>
|
||||
${
|
||||
_("{tos_link_start}Terms of Service{tos_link_end} and {honor_link_start}Honor Code{honor_link_end}").format(
|
||||
tos_link_start=tos_link,
|
||||
tos_link_end="</a>",
|
||||
honor_link_start=honor_link,
|
||||
honor_link_end="</a>",
|
||||
)
|
||||
}
|
||||
</li>
|
||||
% else:
|
||||
<li class="nav-legal-01">
|
||||
<a href="${marketing_link('TOS')}">${_("Terms of Service")}</a>
|
||||
</li>
|
||||
% endif
|
||||
<li class="nav-legal-02">
|
||||
<a href="${marketing_link('PRIVACY')}">${_("Privacy Policy")}</a>
|
||||
</li>
|
||||
% for item_num, link in enumerate(footer['legal_links'], start=1):
|
||||
<li class="nav-legal-0${item_num}">
|
||||
<a href="${link['url']}">${link['title']}</a>
|
||||
</li>
|
||||
% endfor
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
## please leave this link and use one of the logos provided
|
||||
## Please leave this link and use one of the logos provided
|
||||
## The OpenEdX link may be hidden when this view is served
|
||||
## through an API to partner sites (such as marketing sites or blogs),
|
||||
## which are not technically powered by OpenEdX.
|
||||
% if not hide_openedx_link:
|
||||
<div class="footer-about-openedx">
|
||||
<p>
|
||||
<a href="http://openedx.org/">
|
||||
## standard powered-by logo
|
||||
## Translators: 'Open edX' is a brand, please keep this untranslated. See http://openedx.org for more information.
|
||||
<img src="https://files.edx.org/openedx-logos/edx-openedx-logo-tag.png" alt="${_('Powered by Open edX')}" width="140" />
|
||||
## greyscale logo for dark background
|
||||
## <img src="https://files.edx.org/openedx-logos/edx-openedx-logo-tag-light.png" alt="${_('Powered by Open edX')}" width="140" />
|
||||
## greyscale logo for light background
|
||||
## <img src="https://files.edx.org/openedx-logos/edx-openedx-logo-tag-dark.png" alt="${_('Powered by Open edX')}" width="140" />
|
||||
<a href="${footer['openedx_link']['url']}">
|
||||
<img src="${footer['openedx_link']['image']}" alt="${footer['openedx_link']['title']}" width="140" />
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
% endif
|
||||
</footer>
|
||||
</div>
|
||||
% if include_dependencies:
|
||||
<%static:js group='base_vendor'/>
|
||||
<%static:css group='style-vendor'/>
|
||||
<%include file="widgets/segment-io.html" />
|
||||
% endif
|
||||
% if footer_css_urls:
|
||||
% for url in footer_css_urls:
|
||||
<link rel="stylesheet" type="text/css" href="${url}"></link>
|
||||
% endfor
|
||||
% endif
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
## coding=utf-8
|
||||
<%namespace name='static' file='static_content.html'/>
|
||||
<%!
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.http import urlquote_plus
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import get_language_bidi
|
||||
from microsite_configuration import microsite
|
||||
from microsite_configuration import page_title_breadcrumbs
|
||||
from branding import api as branding_api
|
||||
|
||||
dir_rtl = 'rtl' if get_language_bidi() else 'ltr'
|
||||
%>
|
||||
@@ -145,17 +147,18 @@ dir_rtl = 'rtl' if get_language_bidi() else 'ltr'
|
||||
% if not disable_footer:
|
||||
<%block name="footer">
|
||||
## Can be overridden by child templates wanting to hide the footer.
|
||||
<%
|
||||
if theme_enabled() and not is_microsite():
|
||||
footer_file = 'theme-footer.html'
|
||||
elif settings.FEATURES.get('IS_EDX_DOMAIN', False) and settings.FEATURES.get('ENABLE_FOOTER_V3', True) and not is_microsite():
|
||||
footer_file = microsite.get_template_path('footer-edx-v3.html')
|
||||
elif settings.FEATURES.get('IS_EDX_DOMAIN', False) and not is_microsite():
|
||||
footer_file = microsite.get_template_path('footer-edx-v2.html')
|
||||
else:
|
||||
footer_file = microsite.get_template_path('footer.html')
|
||||
%>
|
||||
<%include file="${footer_file}" />
|
||||
% if theme_enabled() and not is_microsite():
|
||||
<%include file="theme-footer.html" />
|
||||
% elif settings.FEATURES.get('IS_EDX_DOMAIN', False) and not is_microsite():
|
||||
## TODO (ECOM-1339): Remove this check to permanently enable the V3 footer.
|
||||
% if branding_api.is_enabled():
|
||||
<%include file="footer-edx-v3.html" />
|
||||
% else:
|
||||
<%include file="footer-edx-v2.html" />
|
||||
% endif
|
||||
% else:
|
||||
<%include file="${microsite.get_template_path('footer.html')}" />
|
||||
% endif
|
||||
</%block>
|
||||
% endif
|
||||
|
||||
@@ -167,6 +170,7 @@ dir_rtl = 'rtl' if get_language_bidi() else 'ltr'
|
||||
% endif
|
||||
|
||||
<%block name="js_extra"/>
|
||||
<script type="text/javascript" src="${static.url('js/vendor/noreferrer.js')}" charset="utf-8"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
{% load compressed %}{% load sekizai_tags i18n microsite %}{% load url from future %}{% load staticfiles %}
|
||||
{% load compressed %}
|
||||
{% load sekizai_tags i18n microsite %}
|
||||
{% load url from future %}
|
||||
{% load staticfiles %}
|
||||
<html lang="{{LANGUAGE_CODE}}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
@@ -38,10 +41,13 @@
|
||||
</div>
|
||||
{% if IS_REQUEST_IN_MICROSITE %}
|
||||
{# For now we don't support overriden Django templates in microsites. Leave footer blank for now which is better than saying Edx.#}
|
||||
{% elif IS_EDX_DOMAIN and not ENABLE_FOOTER_V3 %}
|
||||
{% include "footer-edx-v2.html" %}
|
||||
{% elif IS_EDX_DOMAIN and ENABLE_FOOTER_V3 %}
|
||||
{% include "footer-edx-v3.html" %}
|
||||
{% elif IS_EDX_DOMAIN %}
|
||||
{# TODO (ECOM-1339): Remove this check once we switch to the v3 footer permanently. #}
|
||||
{% if ENABLE_BRANDING_API %}
|
||||
{% include "footer-edx-v3.html" %}
|
||||
{% else %}
|
||||
{% include "footer-edx-v2.html" %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% include "footer.html" %}
|
||||
{% endif %}
|
||||
|
||||
@@ -27,5 +27,5 @@
|
||||
</header>
|
||||
|
||||
<%block name="js_extra">
|
||||
<%static:js group='rwd_header_footer'/>
|
||||
<%static:js group='rwd_header'/>
|
||||
</%block>
|
||||
|
||||
@@ -20,7 +20,7 @@ from verify_student.views import PayAndVerifyView
|
||||
% endfor
|
||||
</%block>
|
||||
<%block name="js_extra">
|
||||
<%static:js group='rwd_header_footer'/>
|
||||
<%static:js group='rwd_header'/>
|
||||
<script src="${static.url('js/vendor/underscore-min.js')}"></script>
|
||||
<script src="${static.url('js/vendor/underscore.string.min.js')}"></script>
|
||||
<script src="${static.url('js/vendor/backbone-min.js')}"></script>
|
||||
|
||||
@@ -34,7 +34,7 @@ from verify_student.views import PayAndVerifyView
|
||||
% endfor
|
||||
</%block>
|
||||
<%block name="js_extra">
|
||||
<%static:js group='rwd_header_footer'/>
|
||||
<%static:js group='rwd_header'/>
|
||||
<script src="${static.url('js/vendor/underscore-min.js')}"></script>
|
||||
<script src="${static.url('js/vendor/underscore.string.min.js')}"></script>
|
||||
<script src="${static.url('js/vendor/backbone-min.js')}"></script>
|
||||
|
||||
@@ -427,6 +427,8 @@ if settings.COURSEWARE_ENABLED:
|
||||
# Student Notes
|
||||
url(r'^courses/{}/edxnotes'.format(settings.COURSE_ID_PATTERN),
|
||||
include('edxnotes.urls'), name="edxnotes_endpoints"),
|
||||
|
||||
url(r'^api/branding/v1/', include('branding.api_urls')),
|
||||
)
|
||||
|
||||
# allow course staff to change to student view of courseware
|
||||
|
||||
Reference in New Issue
Block a user