diff --git a/cms/envs/devstack.py b/cms/envs/devstack.py index 02cd1ed8b1..0c9011bcef 100644 --- a/cms/envs/devstack.py +++ b/cms/envs/devstack.py @@ -87,6 +87,7 @@ DEBUG_TOOLBAR_CONFIG = { 'debug_toolbar.panels.profiling.ProfilingPanel', ), 'SHOW_TOOLBAR_CALLBACK': 'cms.envs.devstack.should_show_debug_toolbar', + 'JQUERY_URL': None, } diff --git a/common/test/acceptance/pages/lms/dashboard.py b/common/test/acceptance/pages/lms/dashboard.py index b8c2408df2..5eadc3ec7a 100644 --- a/common/test/acceptance/pages/lms/dashboard.py +++ b/common/test/acceptance/pages/lms/dashboard.py @@ -169,26 +169,26 @@ class DashboardPage(PageObject): """ Click username dropdown. """ - self.q(css='.dropdown').first.click() + self.q(css='.user-dropdown').first.click() @property def username_dropdown_link_text(self): """ Return list username dropdown links. """ - return self.q(css='.dropdown-menu li a').text + return self.q(css='.user-dropdown-menu li a').text def click_my_profile_link(self): """ Click on `Profile` link. """ - self.q(css='.dropdown-menu li a').nth(1).click() + self.q(css='.user-dropdown-menu li a').nth(1).click() def click_account_settings_link(self): """ Click on `Account` link. """ - self.q(css='.dropdown-menu li a').nth(2).click() + self.q(css='.user-dropdown-menu li a').nth(2).click() @property def language_selector(self): diff --git a/lms/envs/common.py b/lms/envs/common.py index 03bec41bbb..4074841c7e 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -417,6 +417,7 @@ COMMON_ROOT = REPO_ROOT / "common" OPENEDX_ROOT = REPO_ROOT / "openedx" ENV_ROOT = REPO_ROOT.dirname() # virtualenv dir /edx-platform is in COURSES_ROOT = ENV_ROOT / "data" +NODE_MODULES_ROOT = REPO_ROOT / "node_modules" DATA_DIR = COURSES_ROOT @@ -427,7 +428,7 @@ sys.path.append(COMMON_ROOT / 'djangoapps') # For Node.js -system_node_path = os.environ.get("NODE_PATH", REPO_ROOT / 'node_modules') +system_node_path = os.environ.get("NODE_PATH", NODE_MODULES_ROOT) node_paths = [ COMMON_ROOT / "static/js/vendor", @@ -1340,7 +1341,7 @@ main_vendor_js = base_vendor_js + [ base_application_js = [ 'js/src/utility.js', 'js/src/logger.js', - 'js/my_courses_dropdown.js', + 'js/user_dropdown_v1.js', # Custom dropdown keyboard handling for legacy pages 'js/dialog_tab_controls.js', 'js/src/string_utils.js', 'js/form.ext.js', @@ -1612,7 +1613,6 @@ PIPELINE_JS = { 'source_filenames': base_application_js, 'output_filename': 'js/lms-base-application.js', }, - 'application': { 'source_filenames': ( common_js + xblock_runtime_js + base_application_js + lms_application_js + @@ -1641,6 +1641,13 @@ PIPELINE_JS = { 'source_filenames': main_vendor_js, 'output_filename': 'js/lms-main_vendor.js', }, + 'lms_bootstrap': { + 'source_filenames': [ + 'common/js/vendor/tether.js', + 'common/js/vendor/bootstrap.js', + ], + 'output_filename': 'js/lms-bootstrap.js', + }, 'module-descriptor-js': { 'source_filenames': rooted_glob(COMMON_ROOT / 'static/', 'xmodule/descriptors/js/*.js'), 'output_filename': 'js/lms-module-descriptors.js', diff --git a/lms/envs/devstack.py b/lms/envs/devstack.py index d5a5f49cd3..c2ebb0ea57 100644 --- a/lms/envs/devstack.py +++ b/lms/envs/devstack.py @@ -84,7 +84,8 @@ DEBUG_TOOLBAR_PANELS = ( ) DEBUG_TOOLBAR_CONFIG = { - 'SHOW_TOOLBAR_CALLBACK': 'lms.envs.devstack.should_show_debug_toolbar' + 'SHOW_TOOLBAR_CALLBACK': 'lms.envs.devstack.should_show_debug_toolbar', + 'JQUERY_URL': None, } diff --git a/lms/static/js/my_courses_dropdown.js b/lms/static/js/user_dropdown_v1.js similarity index 92% rename from lms/static/js/my_courses_dropdown.js rename to lms/static/js/user_dropdown_v1.js index 3529816e40..930a9cb2d0 100644 --- a/lms/static/js/my_courses_dropdown.js +++ b/lms/static/js/user_dropdown_v1.js @@ -1,9 +1,15 @@ +/** + * Keyboard support for the user dropdown on legacy pages. + * + * Note: this is not used for Pattern Library or Bootstrap pages. + */ + $(document).ready(function() { 'use strict'; // define variables for code legibility - var $dropdownMenuToggle = $('.dropdown'); - var $dropdownMenu = $('.dropdown-menu'); + var $dropdownMenuToggle = $('.user-dropdown'); + var $dropdownMenu = $('.user-dropdown-menu'); var menuItems = $dropdownMenu.find('.dropdown-menuitem'); var keyCodes = { diff --git a/lms/static/sass/bootstrap/_footer.scss b/lms/static/sass/bootstrap/_footer.scss new file mode 100644 index 0000000000..035f4c11f5 --- /dev/null +++ b/lms/static/sass/bootstrap/_footer.scss @@ -0,0 +1,65 @@ +// Open edX: LMS footer +// ==================== + +.wrapper-footer { + box-shadow: 0 -1px 5px 0 $black-t0; + border-top: 1px solid $navbar-light-disabled-color; + background-color: $body-bg; + margin-top: $baseline/2; + padding: $baseline; + font-family: $font-family-sans-serif; + + footer { + max-width: $lms-max-width; + margin: 0 auto; + + .site-nav { + padding: 0; + + .nav-item { + margin-right: $baseline; + + .nav-link { + text-decoration: none; + padding: 0; + color: $brand-inverse; + + &:hover { + color: $brand-primary; + } + } + } + } + + .legal-nav { + padding: 0; + + .nav-item { + .nav-link { + text-decoration: none; + padding: 0; + margin-right: $baseline/4; + font-size: $font-size-sm; + } + } + + li:not(:first-child) a:before { + content: "- "; + } + } + + footer-language-selector { + margin: $baseline 0; + } + + .copyright { + margin-top: $baseline; + font-size: $font-size-xs; + color: $gray-dark; + } + + .footer-about-openedx { + float: right; + } + } +} diff --git a/lms/static/sass/bootstrap/_layouts.scss b/lms/static/sass/bootstrap/_layouts.scss new file mode 100644 index 0000000000..05ded2191a --- /dev/null +++ b/lms/static/sass/bootstrap/_layouts.scss @@ -0,0 +1,47 @@ +// LMS layouts + +.content-wrapper { + .course-tabs { + padding-bottom: none; + + .nav-item { + &.active, &:hover{ + .nav-link { + border-bottom-color: $brand-primary; + color: $brand-primary; + } + } + + .nav-link { + padding: $baseline/2 $baseline*3/4 $baseline*13/20; + border-style: solid; + border-width: 0 0 $baseline/5 0; + border-bottom-color: transparent; + + @media (max-width: map-get($grid-breakpoints, md)) { + border: none; + text-align: left; + padding: 0 0 $baseline/2 0; + } + } + } + } + + .main-container { + border: 1px solid $inverse-color; + background-color: $body-bg; + + .page-header { + border-bottom: 1px solid $inverse-color; + padding: 20px; + } + + .page-content { + padding: 20px; + } + } + + &.container-fluid { + max-width: $lms-max-width; + } +} diff --git a/lms/static/sass/bootstrap/_navigation.scss b/lms/static/sass/bootstrap/_navigation.scss new file mode 100644 index 0000000000..7564c70bcc --- /dev/null +++ b/lms/static/sass/bootstrap/_navigation.scss @@ -0,0 +1,94 @@ +// Local overrides for bootstrap navigation bar theming +.navigation-container { + border-bottom: 1px solid $brand-primary; + text-decoration: none; + + &.slim { + border-bottom: 1px solid $inverse-color; + box-shadow: 0 1px 5px 0 $black-t0; + } + + .navbar { + margin: 0 auto; + max-width: map-get($container-max-widths, xl); + + .logo.slim a { + height: $baseline*3/2; + margin-top: $baseline/5; + } + + .course-header { + font-size: $font-size-lg; + margin: $baseline/2 $baseline/2 0 0; + + .provider { + font-weight: $font-weight-bold; + } + } + + .nav-item { + margin: 0 $baseline 0 0; + font-weight: $font-weight-normal; + font-family: $font-family-sans-serif; + text-transform: uppercase; + list-style: none; + + .nav-link { + color: $brand-primary; + } + + .user-image-frame { + max-width: $baseline*2; + border-radius: $border-radius; + } + + // Dealing with creating a collapsed menu + &.nav-item-open-collapsed-only { + display: none; + } + + @media (max-width: map-get($grid-breakpoints,lg)) { + &.nav-item-open-collapsed, &.nav-item-open-collapsed-only { + display: initial; + margin: $baseline/4 $baseline/2; + + a { + color: $brand-primary; + padding: 0; + text-decoration: none; + + &:hover { + color: $input-border-color; + } + } + } + &.nav-item-hidden-collapsed { + display: none; + } + } + } + + .btn-shopping-cart{ + padding-top: 0.7rem; // $btn-padding-y-lg once themed + } + + .navbar-right .nav-item { + @media (min-width: map-get($grid-breakpoints,lg)) { + .nav-link { + text-transform: none; + color: $brand-inverse; + font-weight: $font-weight-bold; + cursor: pointer; + } + } + + &.dropdown { + cursor: pointer; + + .dropdown-item { + text-transform: initial; + } + } + } + } +} diff --git a/lms/static/sass/bootstrap/_variables.scss b/lms/static/sass/bootstrap/_variables.scss new file mode 100644 index 0000000000..a6c93c5990 --- /dev/null +++ b/lms/static/sass/bootstrap/_variables.scss @@ -0,0 +1,68 @@ +// lms - bootstrap utilities - variables +// ==================== + +// #Units: Unit variables +// #GRID: Grid and layout variables +// #COLORS: Base, palette and theme color definitions + application +// #TYPOGRAPHY: Font definitions and scales +// #ICONS: Icon specific colors + other styling + +// ---------------------------- +// #UNITS +// ---------------------------- +$baseline: 20px !default; + +// ---------------------------- +// #GRID +// ---------------------------- +$lms-max-width: 1180px !default; + +// ---------------------------- +// #COLORS +// ---------------------------- + +$lms-gray: palette(grayscale, base) !default; +$lms-background-color: palette(grayscale, x-back) !default; +$lms-container-background-color: $white !default; +$lms-border-color: palette(grayscale, back) !default; +$lms-label-color: palette(grayscale, black) !default; +$lms-active-color: palette(primary, base) !default; +$lms-preview-menu-color: #c8c8c8 !default; +$success-color: palette(success, accent) !default; +$success-color-hover: palette(success, text) !default; + +$button-bg-hover-color: $white !default; + +$white-transparent: rgba(255, 255, 255, 0) !default; +$white-opacity-40: rgba(255, 255, 255, 0.4) !default; +$white-opacity-60: rgba(255, 255, 255, 0.6) !default; +$white-opacity-70: rgba(255, 255, 255, 0.7) !default; +$white-opacity-80: rgba(255, 255, 255, 0.8) !default; + +$black: rgb(0,0,0) !default; +$black-t0: rgba($black, 0.125) !default; +$black-t1: rgba($black, 0.25) !default; +$black-t2: rgba($black, 0.5) !default; +$black-t3: rgba($black, 0.75) !default; + +$light-grey-transparent: rgba(200,200,200, 0) !default; +$light-grey-solid: rgba(200,200,200, 1) !default; + +// ---------------------------- +// #TYPOGRAPHY +// ---------------------------- +$font-light: 300 !default; +$font-regular: 400 !default; +$font-semibold: 600 !default; +$font-bold: 700 !default; + +// ---------------------------- +// #ICONS +// ---------------------------- +// Icons +$lms-dark-icon-color: $white !default; +$lms-dark-icon-background-color: palette(grayscale, black) !default; + +$site-status-color: rgb(182,37,103) !default; + +$shadow-l1: rgba(0,0,0,0.1) !default; diff --git a/lms/static/sass/bootstrap/lms-main-bootstrap.scss b/lms/static/sass/bootstrap/lms-main-bootstrap.scss new file mode 100644 index 0000000000..1b5298c5d6 --- /dev/null +++ b/lms/static/sass/bootstrap/lms-main-bootstrap.scss @@ -0,0 +1,16 @@ +// ----------------------------- +// LMS main styles for Bootstrap +// ----------------------------- + +// Bootstrap theme +@import 'edx-bootstrap/sass/open-edx/theme'; +@import 'bootstrap/scss/bootstrap'; + +// Variables +@import 'variables'; + +// Elements +@import 'footer'; +@import 'navigation'; +@import 'layouts'; + diff --git a/lms/static/sass/shared/_header.scss b/lms/static/sass/shared/_header.scss index 0390d3c845..939829de25 100644 --- a/lms/static/sass/shared/_header.scss +++ b/lms/static/sass/shared/_header.scss @@ -183,7 +183,7 @@ } } - .dropdown { + .user-dropdown { font-size: $body-font-size; padding: 0 ($baseline/2); color: $base-font-color; @@ -193,7 +193,7 @@ text-shadow: none; } - .dropdown-menu { + .user-dropdown-menu { background: $white; border-radius: 4px; box-shadow: 0 2px 2px 0 rgba(0,0,0, 0.3); diff --git a/lms/templates/footer.html b/lms/templates/footer.html index fc39a595a2..386ca23869 100644 --- a/lms/templates/footer.html +++ b/lms/templates/footer.html @@ -9,75 +9,126 @@ <% footer = get_footer(is_secure=is_secure) %> <%namespace name='static' file='static_content.html'/> - +% endif % if include_dependencies: <%static:js group='base_vendor'/> <%static:css group='style-vendor'/> diff --git a/lms/templates/header.html b/lms/templates/header.html index 9647c3def8..93f1b066a8 100644 --- a/lms/templates/header.html +++ b/lms/templates/header.html @@ -1,4 +1,4 @@ ## mako <%page expression_filter="h" args="online_help_token"/> <%namespace name='static' file='static_content.html'/> -<%include file="${static.get_template_path(relative_path='navigation.html')}" args="online_help_token=online_help_token" /> +<%include file="${static.get_template_path(relative_path='navigation/navigation.html')}" args="online_help_token=online_help_token" /> diff --git a/lms/templates/main.html b/lms/templates/main.html index cb1ed90d6a..e8d162e581 100644 --- a/lms/templates/main.html +++ b/lms/templates/main.html @@ -13,12 +13,14 @@ <%namespace name='static' file='static_content.html'/> <% online_help_token = self.online_help_token() if hasattr(self, 'online_help_token') else None %> <%! +from branding import api as branding_api 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 branding import api as branding_api +from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_string from pipeline_mako import render_require_js_path_overrides + %> @@ -61,25 +63,26 @@ from pipeline_mako import render_require_js_path_overrides <%static:css group='style-vendor'/> - <%static:css group='${self.attr.main_css}'/> - - % if not uses_pattern_library: - % if disable_courseware_js: - <%static:js group='base_vendor'/> - <%static:js group='base_application'/> - % else: - <%static:js group='main_vendor'/> - <%static:js group='application'/> - % endif + % if uses_bootstrap: + % else: - ## TODO: Update to only bring in RequireJS - ## https://openedx.atlassian.net/browse/FEDX-140 + <%static:css group='${self.attr.main_css}'/> + % endif + + % if disable_courseware_js or uses_pattern_library: <%static:js group='base_vendor'/> <%static:js group='base_application'/> + % else: + <%static:js group='main_vendor'/> + <%static:js group='application'/> + % endif + + % if uses_bootstrap: + <%static:js group='lms_bootstrap'/> % endif <%block name="js_overrides"> - ${render_require_js_path_overrides(settings.REQUIRE_JS_PATH_OVERRIDES)} + ${render_require_js_path_overrides(settings.REQUIRE_JS_PATH_OVERRIDES) | n, decode.utf8} % if not disable_courseware_js: @@ -111,7 +114,7 @@ from pipeline_mako import render_require_js_path_overrides % if ga_acct: