From 6134e8b5ed5ba2535b80377dcc68d8369d581964 Mon Sep 17 00:00:00 2001 From: muhammad-ammar Date: Wed, 26 Aug 2015 15:11:34 +0500 Subject: [PATCH 1/2] Move studio dialog code into common --- .../contentstore/features/common.py | 6 +- .../contentstore/features/component.py | 2 +- .../contentstore/features/course-export.py | 3 +- .../contentstore/features/course-outline.py | 2 +- cms/static/coffee/spec/main.coffee | 3 - cms/static/coffee/spec/main_spec.coffee | 2 - .../coffee/spec/views/assets_spec.coffee | 9 +- .../coffee/spec/views/textbook_spec.coffee | 9 +- .../coffee/spec/views/upload_spec.coffee | 2 - cms/static/coffee/src/main.coffee | 2 +- cms/static/coffee/src/views/tabs.coffee | 4 +- .../coffee/src/xblock/cms.runtime.v1.coffee | 2 +- cms/static/js/base.js | 7 +- .../spec/views/certificate_details_spec.js | 4 +- .../spec/views/certificate_editor_spec.js | 4 +- .../spec/views/certificate_preview_spec.js | 2 +- .../spec/views/certificates_list_spec.js | 2 +- .../certificates/views/certificate_details.js | 2 +- .../certificates/views/certificate_preview.js | 4 +- .../certificates/views/signatory_details.js | 2 +- .../js/certificates/views/signatory_editor.js | 6 +- cms/static/js/factories/export.js | 2 +- cms/static/js/index.js | 2 +- cms/static/js/models/section.js | 2 +- .../js/spec/utils/drag_and_drop_spec.js | 2 +- .../spec/video/file_uploader_editor_spec.js | 1 - .../js/spec/video/translations_editor_spec.js | 1 - cms/static/js/spec/views/assets_spec.js | 2 +- .../js/spec/views/group_configuration_spec.js | 4 +- .../js/spec/views/paged_container_spec.js | 2 - .../views/pages/container_subviews_spec.js | 4 +- .../spec/views/pages/course_outline_spec.js | 2 +- .../js/spec/views/pages/course_rerun_spec.js | 4 +- cms/static/js/spec/views/pages/index_spec.js | 4 +- .../js/spec/views/pages/library_users_spec.js | 7 +- cms/static/js/spec/views/unit_outline_spec.js | 2 +- .../js/spec_helpers/assertion_helpers.js | 3 +- cms/static/js/spec_helpers/modal_helpers.js | 2 +- cms/static/js/utils/drag_and_drop.js | 2 +- cms/static/js/views/asset.js | 3 +- cms/static/js/views/assets.js | 2 +- cms/static/js/views/baseview.js | 2 +- cms/static/js/views/components/add_xblock.js | 2 +- cms/static/js/views/container.js | 2 +- cms/static/js/views/content_group_item.js | 2 +- cms/static/js/views/course_info_handout.js | 2 +- cms/static/js/views/course_info_update.js | 3 +- cms/static/js/views/course_outline.js | 2 +- cms/static/js/views/course_rerun.js | 2 +- cms/static/js/views/edit_textbook.js | 2 +- cms/static/js/views/list_item.js | 2 +- cms/static/js/views/list_item_editor.js | 2 +- cms/static/js/views/list_textbooks.js | 2 +- cms/static/js/views/manage_users_and_roles.js | 3 +- cms/static/js/views/modals/edit_xblock.js | 2 +- cms/static/js/views/overview.js | 4 +- .../js/views/overview_assignment_grader.js | 2 +- cms/static/js/views/paged_container.js | 4 +- cms/static/js/views/pages/container.js | 2 +- .../js/views/pages/container_subviews.js | 2 +- cms/static/js/views/pages/course_outline.js | 4 +- cms/static/js/views/settings/main.js | 2 +- cms/static/js/views/show_textbook.js | 3 +- .../js/views/utils/create_course_utils.js | 2 +- .../js/views/utils/create_library_utils.js | 2 +- .../js/views/utils/create_utils_base.js | 2 +- cms/static/js/views/utils/xblock_utils.js | 2 +- cms/static/js/views/validation.js | 2 +- cms/static/js/views/xblock_outline.js | 2 +- .../sass/elements/_system-feedback.scss | 18 +- cms/templates/base.html | 5 - .../common/js/components}/utils/view_utils.js | 0 .../common/js/components}/views/feedback.js | 0 .../js/components}/views/feedback_alert.js | 0 .../views/feedback_notification.js | 0 .../js/components}/views/feedback_prompt.js | 0 .../js/spec/components}/view_utils_spec.js | 0 .../common}/js/spec_helpers/view_helpers.js | 0 .../components}/system-feedback.underscore | 0 common/static/js/spec/main_requirejs.js | 4 +- common/static/js_test_requirejs.yml | 1 + common/static/sass/_mixins.scss | 7 + common/test/acceptance/pages/lms/teams.py | 16 +- common/test/acceptance/pages/studio/utils.py | 7 +- .../teams/js/spec/views/team_profile_spec.js | 44 +- .../static/teams/js/views/team_profile.js | 37 +- .../teams/templates/teams/teams.html | 2 +- lms/static/sass/_build-lms.scss | 7 +- lms/static/sass/_shame.scss | 19 + lms/static/sass/base/_variables.scss | 65 +- .../sass/elements/_system-feedback.scss | 953 +++++++++++++++++- lms/templates/main.html | 1 + 92 files changed, 1226 insertions(+), 157 deletions(-) rename {cms/static/js/views => common/static/common/js/components}/utils/view_utils.js (100%) rename {cms/static/js => common/static/common/js/components}/views/feedback.js (100%) rename {cms/static/js => common/static/common/js/components}/views/feedback_alert.js (100%) rename {cms/static/js => common/static/common/js/components}/views/feedback_notification.js (100%) rename {cms/static/js => common/static/common/js/components}/views/feedback_prompt.js (100%) rename {cms/static/js/spec/views/utils => common/static/common/js/spec/components}/view_utils_spec.js (100%) rename {cms/static => common/static/common}/js/spec_helpers/view_helpers.js (100%) rename {cms/templates/js => common/static/common/templates/components}/system-feedback.underscore (100%) diff --git a/cms/djangoapps/contentstore/features/common.py b/cms/djangoapps/contentstore/features/common.py index 692ec695ce..98a774fcc2 100644 --- a/cms/djangoapps/contentstore/features/common.py +++ b/cms/djangoapps/contentstore/features/common.py @@ -92,7 +92,7 @@ def press_the_notification_button(_step, name): # the "Save" button at the UI level. # Instead, we use JavaScript to reliably click # the button. - btn_css = 'div#page-notification a.action-%s' % name.lower() + btn_css = 'div#page-notification button.action-%s' % name.lower() world.trigger_event(btn_css, event='focus') world.browser.execute_script("$('{}').click()".format(btn_css)) world.wait_for_ajax_complete() @@ -284,7 +284,7 @@ def button_disabled(step, value): def _do_studio_prompt_action(intent, action): """ Wait for a studio prompt to appear and press the specified action button - See cms/static/js/views/feedback_prompt.js for implementation + See common/js/components/views/feedback_prompt.js for implementation """ assert intent in [ 'warning', @@ -299,7 +299,7 @@ def _do_studio_prompt_action(intent, action): world.wait_for_present('div.wrapper-prompt.is-shown#prompt-{}'.format(intent)) - action_css = 'li.nav-item > a.action-{}'.format(action) + action_css = 'li.nav-item > button.action-{}'.format(action) world.trigger_event(action_css, event='focus') world.browser.execute_script("$('{}').click()".format(action_css)) diff --git a/cms/djangoapps/contentstore/features/component.py b/cms/djangoapps/contentstore/features/component.py index 1d3f7e3a47..c2f62e69e4 100644 --- a/cms/djangoapps/contentstore/features/component.py +++ b/cms/djangoapps/contentstore/features/component.py @@ -97,7 +97,7 @@ def delete_components(step, number): world.wait_for_xmodule() delete_btn_css = 'a.delete-button' prompt_css = 'div#prompt-warning' - btn_css = '{} a.button.action-primary'.format(prompt_css) + btn_css = '{} button.action-primary'.format(prompt_css) saving_mini_css = 'div#page-notification .wrapper-notification-mini' for _ in range(int(number)): world.css_click(delete_btn_css) diff --git a/cms/djangoapps/contentstore/features/course-export.py b/cms/djangoapps/contentstore/features/course-export.py index 38f2dc5c32..5a0867565d 100644 --- a/cms/djangoapps/contentstore/features/course-export.py +++ b/cms/djangoapps/contentstore/features/course-export.py @@ -49,8 +49,7 @@ def get_an_error_dialog(step): @step('I can click to go to the unit with the error$') def i_click_on_error_dialog(step): - world.wait_for_visible(".button.action-primary") - world.click_link_by_text('Correct failed component') + world.css_click("button.action-primary") problem_string = unicode(world.scenario_dict['COURSE'].id.make_usage_key("problem", 'ignore')) problem_string = u"Problem {}".format(problem_string[:problem_string.rfind('ignore')]) diff --git a/cms/djangoapps/contentstore/features/course-outline.py b/cms/djangoapps/contentstore/features/course-outline.py index 6ab7f85e81..702364b1a0 100644 --- a/cms/djangoapps/contentstore/features/course-outline.py +++ b/cms/djangoapps/contentstore/features/course-outline.py @@ -75,7 +75,7 @@ def i_press_the_section_delete_icon(step): @step(u'I will confirm all alerts') def i_confirm_all_alerts(step): - confirm_locator = '.prompt .nav-actions a.action-primary' + confirm_locator = '.prompt .nav-actions button.action-primary' world.css_click(confirm_locator) diff --git a/cms/static/coffee/spec/main.coffee b/cms/static/coffee/spec/main.coffee index 8bbae2219e..b211eb3fdf 100644 --- a/cms/static/coffee/spec/main.coffee +++ b/cms/static/coffee/spec/main.coffee @@ -220,7 +220,6 @@ define([ "coffee/spec/models/settings_grading_spec", "coffee/spec/models/textbook_spec", "coffee/spec/models/upload_spec", - "coffee/spec/views/course_info_spec", "coffee/spec/views/feedback_spec", "coffee/spec/views/metadata_edit_spec", "coffee/spec/views/module_edit_spec", "coffee/spec/views/textbook_spec", "coffee/spec/views/upload_spec", @@ -254,8 +253,6 @@ define([ "js/spec/views/license_spec", "js/spec/views/paging_spec", - "js/spec/views/utils/view_utils_spec", - "js/spec/views/pages/container_spec", "js/spec/views/pages/container_subviews_spec", "js/spec/views/pages/group_configurations_spec", diff --git a/cms/static/coffee/spec/main_spec.coffee b/cms/static/coffee/spec/main_spec.coffee index 45cbd52bbc..66e8048889 100644 --- a/cms/static/coffee/spec/main_spec.coffee +++ b/cms/static/coffee/spec/main_spec.coffee @@ -21,10 +21,8 @@ require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_h expect($.ajaxSettings.headers["X-CSRFToken"]).toEqual("stubCSRFToken") describe "AJAX Errors", -> - tpl = readFixtures('system-feedback.underscore') beforeEach -> - setFixtures($(" - ## js templates - -
<% online_help_token = self.online_help_token() if hasattr(self, 'online_help_token') else None %> diff --git a/cms/static/js/views/utils/view_utils.js b/common/static/common/js/components/utils/view_utils.js similarity index 100% rename from cms/static/js/views/utils/view_utils.js rename to common/static/common/js/components/utils/view_utils.js diff --git a/cms/static/js/views/feedback.js b/common/static/common/js/components/views/feedback.js similarity index 100% rename from cms/static/js/views/feedback.js rename to common/static/common/js/components/views/feedback.js diff --git a/cms/static/js/views/feedback_alert.js b/common/static/common/js/components/views/feedback_alert.js similarity index 100% rename from cms/static/js/views/feedback_alert.js rename to common/static/common/js/components/views/feedback_alert.js diff --git a/cms/static/js/views/feedback_notification.js b/common/static/common/js/components/views/feedback_notification.js similarity index 100% rename from cms/static/js/views/feedback_notification.js rename to common/static/common/js/components/views/feedback_notification.js diff --git a/cms/static/js/views/feedback_prompt.js b/common/static/common/js/components/views/feedback_prompt.js similarity index 100% rename from cms/static/js/views/feedback_prompt.js rename to common/static/common/js/components/views/feedback_prompt.js diff --git a/cms/static/js/spec/views/utils/view_utils_spec.js b/common/static/common/js/spec/components/view_utils_spec.js similarity index 100% rename from cms/static/js/spec/views/utils/view_utils_spec.js rename to common/static/common/js/spec/components/view_utils_spec.js diff --git a/cms/static/js/spec_helpers/view_helpers.js b/common/static/common/js/spec_helpers/view_helpers.js similarity index 100% rename from cms/static/js/spec_helpers/view_helpers.js rename to common/static/common/js/spec_helpers/view_helpers.js diff --git a/cms/templates/js/system-feedback.underscore b/common/static/common/templates/components/system-feedback.underscore similarity index 100% rename from cms/templates/js/system-feedback.underscore rename to common/static/common/templates/components/system-feedback.underscore diff --git a/common/static/js/spec/main_requirejs.js b/common/static/js/spec/main_requirejs.js index ac83443fe6..ac29c68b3c 100644 --- a/common/static/js/spec/main_requirejs.js +++ b/common/static/js/spec/main_requirejs.js @@ -159,7 +159,9 @@ 'common-requirejs/include/common/js/spec/components/paginated_view_spec.js', 'common-requirejs/include/common/js/spec/components/paging_collection_spec.js', 'common-requirejs/include/common/js/spec/components/paging_header_spec.js', - 'common-requirejs/include/common/js/spec/components/paging_footer_spec.js' + 'common-requirejs/include/common/js/spec/components/paging_footer_spec.js', + 'common-requirejs/include/common/js/spec/components/view_utils_spec.js', + 'common-requirejs/include/common/js/spec/components/feedback_spec.js' ]); }).call(this, requirejs, define); diff --git a/common/static/js_test_requirejs.yml b/common/static/js_test_requirejs.yml index f5e2411587..391322c05c 100644 --- a/common/static/js_test_requirejs.yml +++ b/common/static/js_test_requirejs.yml @@ -44,6 +44,7 @@ lib_paths: - coffee/src/jquery.immediateDescendents.js - js/vendor/requirejs/text.js - js/vendor/sinon-1.7.1.js + - js/vendor/jasmine-stealth.js # Paths to source JavaScript files src_paths: diff --git a/common/static/sass/_mixins.scss b/common/static/sass/_mixins.scss index 9b78525951..2b85aa0186 100644 --- a/common/static/sass/_mixins.scss +++ b/common/static/sass/_mixins.scss @@ -437,3 +437,10 @@ -webkit-font-smoothing: antialiased; speak: none; } + +%btn-no-style { + background: transparent; + border: 0; + padding: 0; + margin: 0; +} diff --git a/common/test/acceptance/pages/lms/teams.py b/common/test/acceptance/pages/lms/teams.py index 6015f46a53..cf24e937df 100644 --- a/common/test/acceptance/pages/lms/teams.py +++ b/common/test/acceptance/pages/lms/teams.py @@ -6,6 +6,7 @@ Teams pages. from .course_page import CoursePage from .discussion import InlineDiscussionPage from ..common.paging import PaginatedUIMixin +from ...pages.studio.utils import confirm_prompt from .fields import FieldsMixin @@ -334,14 +335,17 @@ class TeamPage(CoursePage, PaginatedUIMixin): """Verifies that team leave link is present""" return self.q(css='.leave-team-link').present - def click_leave_team_link(self, remaining_members=0): + def click_leave_team_link(self, remaining_members=0, cancel=False): """ Click on Leave Team link""" self.q(css='.leave-team-link').first.click() - self.wait_for( - lambda: self.join_team_button_present, - description="Join Team button did not become present" - ) - self.wait_for_capacity_text(remaining_members) + confirm_prompt(self, cancel, require_notification=False) + + if cancel is False: + self.wait_for( + lambda: self.join_team_button_present, + description="Join Team button did not become present" + ) + self.wait_for_capacity_text(remaining_members) @property def team_members(self): diff --git a/common/test/acceptance/pages/studio/utils.py b/common/test/acceptance/pages/studio/utils.py index 1f85601c93..d2394db5a9 100644 --- a/common/test/acceptance/pages/studio/utils.py +++ b/common/test/acceptance/pages/studio/utils.py @@ -59,7 +59,7 @@ def press_the_notification_button(page, name): # the "Save" button at the UI level. # Instead, we use JavaScript to reliably click # the button. - btn_css = 'div#page-notification a.action-%s' % name.lower() + btn_css = 'div#page-notification button.action-%s' % name.lower() page.browser.execute_script("$('{}').focus().click()".format(btn_css)) page.wait_for_ajax() @@ -177,7 +177,7 @@ def get_codemirror_value(page, index=0, find_prefix="$"): ) -def confirm_prompt(page, cancel=False): +def confirm_prompt(page, cancel=False, require_notification=None): """ Ensures that a modal prompt and confirmation button are visible, then clicks the button. The prompt is canceled iff cancel is True. @@ -185,7 +185,8 @@ def confirm_prompt(page, cancel=False): page.wait_for_element_visibility('.prompt', 'Prompt is visible') confirmation_button_css = '.prompt .action-' + ('secondary' if cancel else 'primary') page.wait_for_element_visibility(confirmation_button_css, 'Confirmation button is visible') - click_css(page, confirmation_button_css, require_notification=(not cancel)) + require_notification = (not cancel) if require_notification is None else require_notification + click_css(page, confirmation_button_css, require_notification=require_notification) def set_input_value(page, css, value): diff --git a/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js b/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js index 4f97096113..da7921ce7c 100644 --- a/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js +++ b/lms/djangoapps/teams/static/teams/js/spec/views/team_profile_spec.js @@ -21,7 +21,7 @@ define([ ]; beforeEach(function () { - setFixtures('
'); + setFixtures('
'); DiscussionSpecHelper.setUnderscoreFixtures(); }); @@ -74,19 +74,29 @@ define([ return profileView; }; - clickLeaveTeam = function(requests, view) { + clickLeaveTeam = function(requests, view, confirmLeave) { expect(view.$(leaveTeamLinkSelector).length).toBe(1); // click on Leave Team link under Team Details view.$(leaveTeamLinkSelector).click(); - // expect a request to DELETE the team membership - AjaxHelpers.expectJsonRequest(requests, 'DELETE', 'api/team/v0/team_membership/test-team,bilbo'); - AjaxHelpers.respondWithNoContent(requests); + if (confirmLeave) { + // click on Confirm button on dialog + $('.prompt.warning .action-primary').click(); - // expect a request to refetch the user's team memberships - AjaxHelpers.expectJsonRequest(requests, 'GET', '/api/team/v0/teams/test-team'); - AjaxHelpers.respondWithJson(requests, createTeamModelData({country: 'US', language: 'en'})); + // expect a request to DELETE the team membership + AjaxHelpers.expectJsonRequest(requests, 'DELETE', 'api/team/v0/team_membership/test-team,bilbo'); + AjaxHelpers.respondWithNoContent(requests); + + // expect a request to refetch the user's team memberships + AjaxHelpers.expectJsonRequest(requests, 'GET', '/api/team/v0/teams/test-team'); + AjaxHelpers.respondWithJson(requests, createTeamModelData({country: 'US', language: 'en'})); + } else { + var requestCount = requests.length; + // click on Cancel button on dialog + $('.prompt.warning .action-secondary').click(); + expect(requests.length).toBe(requestCount); + } }; describe('DiscussionsView', function() { @@ -111,7 +121,7 @@ define([ view = createTeamProfileView(requests, {membership: DEFAULT_MEMBERSHIP}); expect(view.$('.new-post-btn').length).toEqual(1); - clickLeaveTeam(requests, view); + clickLeaveTeam(requests, view, true); expect(view.$('.new-post-btn').length).toEqual(0); }); }); @@ -178,10 +188,21 @@ define([ requests, {country: 'US', language: 'en', membership: DEFAULT_MEMBERSHIP} ); assertTeamDetails(view, 1, true); - clickLeaveTeam(requests, view); + clickLeaveTeam(requests, view, true); assertTeamDetails(view, 0, false); }); + it("wouldn't do anything if user click on Cancel button on dialog", function() { + var requests = AjaxHelpers.requests(this); + + var view = createTeamProfileView( + requests, {country: 'US', language: 'en', membership: DEFAULT_MEMBERSHIP} + ); + assertTeamDetails(view, 1, true); + clickLeaveTeam(requests, view, false); + assertTeamDetails(view, 1, true); + }); + it('shows correct error messages', function () { var requests = AjaxHelpers.requests(this); @@ -189,7 +210,10 @@ define([ var view = createTeamProfileView( requests, {country: 'US', language: 'en', membership: DEFAULT_MEMBERSHIP} ); + // click leave team link view.$('.leave-team-link').click(); + // click Confirm button on dialog + $('.prompt.warning .action-primary').click(); AjaxHelpers.respondWithTextError(requests, 400, errorMessage); expect($('.msg-content .copy').text().trim()).toBe(expectedMessage); }; diff --git a/lms/djangoapps/teams/static/teams/js/views/team_profile.js b/lms/djangoapps/teams/static/teams/js/views/team_profile.js index 8184283dec..a10deffb6f 100644 --- a/lms/djangoapps/teams/static/teams/js/views/team_profile.js +++ b/lms/djangoapps/teams/static/teams/js/views/team_profile.js @@ -4,10 +4,11 @@ ;(function (define) { 'use strict'; define(['backbone', 'underscore', 'gettext', 'teams/js/views/team_discussion', + 'common/js/components/utils/view_utils', 'teams/js/views/team_utils', 'text!teams/templates/team-profile.underscore', 'text!teams/templates/team-member.underscore'], - function (Backbone, _, gettext, TeamDiscussionView, TeamUtils, teamTemplate, teamMemberTemplate) { + function (Backbone, _, gettext, TeamDiscussionView, ViewUtils, TeamUtils, teamTemplate, teamMemberTemplate) { var TeamProfileView = Backbone.View.extend({ errorMessage: gettext("An error occurred. Try again."), @@ -72,20 +73,28 @@ leaveTeam: function (event) { event.preventDefault(); var view = this; - $.ajax({ - type: 'DELETE', - url: view.teamMembershipDetailUrl.replace('team_id', view.model.get('id')) - }).done(function (data) { - view.model.fetch() - .done(function() { - view.teamEvents.trigger('teams:update', { - action: 'leave', - team: view.model - }); + ViewUtils.confirmThenRunOperation( + gettext("Leave this team?"), + gettext("If you leave, you can no longer post in this team's discussions. Your place will be available to another learner."), + gettext("Confirm"), + function() { + $.ajax({ + type: 'DELETE', + url: view.teamMembershipDetailUrl.replace('team_id', view.model.get('id')) + }).done(function (data) { + view.model.fetch() + .done(function() { + view.teamEvents.trigger('teams:update', { + action: 'leave', + team: view.model + }); + }); + }).fail(function (data) { + TeamUtils.parseAndShowMessage(data, view.errorMessage); }); - }).fail(function (data) { - TeamUtils.parseAndShowMessage(data, view.errorMessage); - }); + } + ); + $('.wrapper-prompt').focus(); } }); diff --git a/lms/djangoapps/teams/templates/teams/teams.html b/lms/djangoapps/teams/templates/teams/teams.html index 1ad546763e..81b207d3f8 100644 --- a/lms/djangoapps/teams/templates/teams/teams.html +++ b/lms/djangoapps/teams/templates/teams/teams.html @@ -5,7 +5,7 @@ <%namespace name='static' file='/static_content.html'/> <%inherit file="/main.html" /> -<%block name="bodyclass">view-teams is-in-course course +<%block name="bodyclass">view-teams is-in-course course js <%block name="pagetitle">${_("Teams")} <%block name="headextra"> diff --git a/lms/static/sass/_build-lms.scss b/lms/static/sass/_build-lms.scss index 5b0298dc04..e9b7aee5be 100644 --- a/lms/static/sass/_build-lms.scss +++ b/lms/static/sass/_build-lms.scss @@ -15,7 +15,6 @@ // base - elements @import 'elements/typography'; @import 'elements/controls'; -@import 'elements/system-feedback'; @import 'elements/creative-commons'; // shared - course @@ -76,6 +75,10 @@ // news @import 'news'; +@import 'mixins'; +@import 'mixins-inherited'; +@import 'elements/system-feedback'; + // overrides @import 'developer'; // used for any developer-created scss that needs further polish/refactoring -@import 'shame'; // used for any bad-form/orphaned scss +@import 'shame'; // used for any bad-form/orphaned scss \ No newline at end of file diff --git a/lms/static/sass/_shame.scss b/lms/static/sass/_shame.scss index c2e3770643..c8a37991ca 100644 --- a/lms/static/sass/_shame.scss +++ b/lms/static/sass/_shame.scss @@ -198,3 +198,22 @@ footer .references { .course-content .discussion-post.edit-post-form .topic-submenu { list-style: none; } + + +// LMS system feedback button overrides +.is-in-course .wrapper-prompt .nav-actions { + button { + font-family: inherit; + } + + .action-primary { + @extend %t-action4; + } + + .action-secondary { + @extend %btn-no-style; + @extend %t-strong; + box-shadow: none; + text-shadow: none; + } +} diff --git a/lms/static/sass/base/_variables.scss b/lms/static/sass/base/_variables.scss index 0efe2c758a..0acb8b8392 100644 --- a/lms/static/sass/base/_variables.scss +++ b/lms/static/sass/base/_variables.scss @@ -134,6 +134,68 @@ $green-u1: desaturate($green,15%); $green-u2: desaturate($green,30%); $green-u3: desaturate($green,45%); +$yellow: rgb(255, 252, 221); // yellow color used by LMS +//$yellow: rgb(237, 189, 60); // yellow color used by Studio +$yellow-l1: tint($yellow,20%); +$yellow-l2: tint($yellow,40%); +$yellow-l3: tint($yellow,60%); +$yellow-l4: tint($yellow,80%); +$yellow-l5: tint($yellow,90%); +$yellow-d1: shade($yellow,20%); +$yellow-d2: shade($yellow,40%); +$yellow-d3: shade($yellow,60%); +$yellow-d4: shade($yellow,80%); +$yellow-s1: saturate($yellow,15%); +$yellow-s2: saturate($yellow,30%); +$yellow-s3: saturate($yellow,45%); +$yellow-u1: desaturate($yellow,15%); +$yellow-u2: desaturate($yellow,30%); +$yellow-u3: desaturate($yellow,45%); + +$blue: rgb(0, 120, 176); +$blue-l1: tint($blue,20%); +$blue-l2: tint($blue,40%); +$blue-l3: tint($blue,60%); +$blue-l4: tint($blue,80%); +$blue-l5: tint($blue,90%); +$blue-d1: shade($blue,20%); +$blue-d2: shade($blue,40%); +$blue-d3: shade($blue,60%); +$blue-d4: shade($blue,80%); +$blue-s1: saturate($blue,15%); +$blue-s2: saturate($blue,30%); +$blue-s3: saturate($blue,45%); +$blue-u1: desaturate($blue,15%); +$blue-u2: desaturate($blue,30%); +$blue-u3: desaturate($blue,45%); +$blue-t0: rgba($blue, 0.125); +$blue-t1: rgba($blue, 0.25); +$blue-t2: rgba($blue, 0.50); +$blue-t3: rgba($blue, 0.75); + +$orange: rgb(237, 189, 60); +$orange-l1: tint($orange,20%); +$orange-l2: tint($orange,40%); +$orange-l3: tint($orange,60%); +$orange-l4: tint($orange,80%); +$orange-l5: tint($orange,90%); +$orange-d1: shade($orange,20%); +$orange-d2: shade($orange,40%); +$orange-d3: shade($orange,60%); +$orange-d4: shade($orange,80%); +$orange-s1: saturate($orange,15%); +$orange-s2: saturate($orange,30%); +$orange-s3: saturate($orange,45%); +$orange-u1: desaturate($orange,15%); +$orange-u2: desaturate($orange,30%); +$orange-u3: desaturate($orange,45%); + +// ==================== + +// copied from cms/static/sass/_variables.scss +$ui-notification-height: ($baseline*10); + + // ==================== // COLORS: social platforms @@ -144,8 +206,7 @@ $linkedin-blue: #0077B5; // ==================== // TODO: both blue and yellow variables differ from CMS rgb value, need to confirm change to CMS variable is ok in current platform uses before switching. -$blue: rgb(0, 120, 176); -$yellow: rgb(255, 252, 221); +//$yellow: rgb(255, 252, 221); // ==================== diff --git a/lms/static/sass/elements/_system-feedback.scss b/lms/static/sass/elements/_system-feedback.scss index 41cb5ea92e..8c09a050ce 100644 --- a/lms/static/sass/elements/_system-feedback.scss +++ b/lms/static/sass/elements/_system-feedback.scss @@ -145,9 +145,960 @@ } } - // prompts // notifications // alerts + + +// all the below sass is copied from cms/static/sass/elements/_system-feedback.scss + +// studio - elements - system feedback +// ==================== + +// messages +.message { + @extend %t-copy-sub1; + display: block; +} + +.message-status { + @include border-top-radius(2px); + @include box-sizing(border-box); + @extend %t-strong; + display: none; + border-bottom: 2px solid $yellow-d2; + margin: 0 0 $baseline 0; + padding: ($baseline/2) $baseline; + background: $yellow-d1; + color: $white; + + .feedback-symbol { + @extend %t-icon5; + position: relative; + top: 1px; + display: inline-block; + margin-right: ($baseline/2); + } + + .text { + display: inline-block; + } + + &.error { + border-color: $red-d3; + background: $red-l1; + } + + &.is-shown { + display: block; + } +} + + +// alerts, notifications, prompts, and status communication +// ==================== + +// shared +.wrapper-notification, .wrapper-alert, .prompt { + @include box-sizing(border-box); + + .copy { + @extend %t-copy-sub1; + } +} + +.wrapper-notification, .wrapper-alert, .prompt { + background: $gray-d3; + + .copy { + color: $gray-l2; + + .title { + color: $white; + } + + .nav-actions { + + .action-primary { + color: $gray-d4; + } + } + } +} + +.alert, .notification, .prompt { + + // types - confirm + &.confirm { + + .nav-actions .action-primary { + @include blue-button(); + @extend %t-action4; + border-color: $blue-d2; + } + + .action-secondary { + color: $blue; + + &:hover { + color: $blue-s2; + } + } + } + + // types - warning + &.warning { + + .nav-actions .action-primary { + @include orange-button(); + @extend %t-action4; + border-color: $orange-d2; + color: $gray-d4; + } + + .action-secondary { + color: $orange; + + &:hover { + color: $orange-s2; + } + } + } + + // types - error + &.error { + + .nav-actions .action-primary { + @include red-button(); + @extend %t-action4; + border-color: $red-d2; + } + + .action-secondary { + color: $red-l1; + + &:hover { + color: $red; + } + } + } + + // types - announcement + &.announcement { + + .nav-actions .action-primary { + @include blue-button(); + @extend %t-action4; + border-color: $blue-d2; + } + + .action-secondary { + color: $blue; + + &:hover { + color: $blue-s2; + } + } + } + + // types - confirmation + &.confirmation { + + .nav-actions .action-primary { + @include green-button(); + @extend %t-action4; + border-color: $green-d2; + } + + .action-secondary { + color: $green; + + &:hover { + color: $green-s2; + } + } + } + + // types - step required + &.step-required { + + .nav-actions .action-primary { + @include pink-button(); + @extend %t-action4; + border-color: $pink-d2; + } + + .action-secondary { + color: $pink; + + &:hover { + color: $pink-s1; + } + } + } +} + +// prompts +.wrapper-prompt { + @extend %ui-depth5; + @include transition(all $tmg-f3 ease-in-out 0s); + position: fixed; + top: 0; + background: $black-t1; + width: 100%; + height: 100%; + text-align: center; + + &:before { + content: ''; + display: inline-block; + height: 100%; + vertical-align: middle; + margin-right: -0.25em; /* Adjusts for spacing */ + } + + .prompt { + border-radius: ($baseline/5); + box-shadow: 0 0 3px $shadow-d1; + display: inline-block; + vertical-align: middle; + width: $baseline*17.5; + border: 4px solid $black; + @include text-align(left); + + .copy { + border-top: 4px solid $blue; + padding: $baseline; + } + + .nav-actions { + box-shadow: inset 0 1px 2px $shadow-d1; + border-top: 1px solid $black-t1; + padding: ($baseline*0.75) $baseline; + background: $gray-d4; + + .nav-item { + display: inline-block; + @include margin-right($baseline*0.75); + + &:last-child { + @include margin-right(0); + } + } + + .action-primary { + @extend %t-action4; + @extend %t-strong; + } + + .action-secondary { + @extend %t-action4; + } + } + } + + // types of prompts - error + .prompt.error { + + .feedback-symbol { + color: $red-l1; + } + + .copy { + border-top-color: $red-l1; + } + } + + // types of prompts - confirmation + .prompt.confirmation { + + .feedback-symbol { + color: $green; + } + + .copy { + border-top-color: $green; + } + } + + // types of prompts - error + .prompt.warning { + + .feedback-symbol { + color: $orange; + } + + .copy { + border-top-color: $orange; + } + } +} + +// ==================== + +// notifications +.wrapper-notification { + @extend %ui-depth5; + @include clearfix(); + box-shadow: 0 -1px 3px $shadow, inset 0 3px 1px $blue; + position: fixed; + bottom: 0; + width: 100%; + padding: $baseline ($baseline*2); + + &.wrapper-notification-warning { + box-shadow: 0 -1px 3px $shadow, inset 0 3px 1px $orange; + + .feedback-symbol { + color: $orange; + } + } + + &.wrapper-notification-error { + box-shadow: 0 -1px 3px $shadow, inset 0 3px 1px $red-l1; + + .feedback-symbol { + color: $red-l1; + } + } + + &.wrapper-notification-confirmation { + box-shadow: 0 -1px 3px $shadow, inset 0 3px 1px $green; + + .feedback-symbol { + color: $green; + } + } + + &.wrapper-notification-mini { + box-shadow: 0 -1px 3px $shadow, inset 0 3px 1px $pink; + } + + // shorter/status notifications + &.wrapper-notification-status { + @include border-top-radius(3px); + right: ($baseline); + width: auto; + border: 4px solid $black; + border-bottom: none; + padding: ($baseline/2) $baseline; + + .notification { + @include box-sizing(border-box); + @include clearfix(); + width: 100%; + max-width: none; + min-width: none; + + .feedback-symbol, .copy { + float: none; + display: inline-block; + vertical-align: middle; + } + + .feedback-symbol { + width: $baseline; + height: ($baseline*1.25); + margin-right: ($baseline/4); + line-height: 3rem; + } + + .copy { + + } + } + } + + // help notifications + &.wrapper-notification-help { + @include border-top-radius(3px); + width: ($baseline*14); + right: ($baseline); + border: 4px solid $black; + border-bottom: none; + padding: $baseline; + + .notification { + @include box-sizing(border-box); + @include clearfix(); + width: 100%; + max-width: none; + min-width: none; + + .feedback-symbol { + width: $baseline; + margin-right: ($baseline*0.75); + } + + .action-notification-close { + right: 0; + } + + .copy { + width: ($baseline*10); + } + } + } +} + +.notification { + @include box-sizing(border-box); + @include clearfix(); + margin: 0 auto; + width: flex-grid(12); + max-width: $fg-max-width; + min-width: $fg-min-width; + + strong { + @extend %t-strong; + } + + .feedback-symbol, .copy { + float: left; + display: inline-block; + vertical-align: middle; + } + + .feedback-symbol { + @include transition (color $tmg-f1 ease-in-out 0s); + @extend %t-icon3; + width: flex-grid(1, 12); + height: ($baseline*1.25); + margin-top: ($baseline/4); + margin-right: flex-gutter(); + text-align: right; + color: $white; + } + + .copy { + @extend %t-copy-sub1; + width: flex-grid(10, 12); + color: $gray-l2; + + .title { + @extend %t-title7; + margin-bottom: 0; + color: $white; + } + } + + // with actions + &.has-actions { + + .feedback-symbol { + width: flex-grid(1, 12); + } + + .copy { + width: flex-grid(7, 12); + @include margin-right(flex-gutter()); + } + + .nav-actions { + width: flex-grid(4, 12); + @include float(left); + margin-top: ($baseline/4); + text-align: right; + + .nav-item { + display: inline-block; + vertical-align: middle; + @include margin-right($baseline/2); + + &:last-child { + @include margin-right(0); + } + } + } + + .action-primary { + @include blue-button(); + @extend %t-strong; + border-color: $blue-d2; + } + + .action-secondary { + + @extend %t-action4; + } + } + + &.confirmation { + + .copy { + margin-top: ($baseline/5); + } + } + + &.mini { + width: auto; + max-width: none; + min-width: 0; + + .feedback-symbol { + @include animation(rotateCW $tmg-s3 linear infinite); + width: 25px; + margin: -4px 10px 0 0; + @include transform-origin(52% 60%); + } + + .copy { + width: auto; + } + + .title { + @extend %cont-truncated; + } + + .copy p { + @extend %cont-text-sr; + } + } +} + +// ==================== + +// alerts +.wrapper-alert { + @extend %ui-depth2; + @include box-sizing(border-box); + box-shadow: 0 1px 1px $white, inset 0 2px 2px $shadow-d1, inset 0 -4px 1px $blue; + position: relative; + overflow: hidden; + width: 100%; + border-top: 1px solid $black; + padding: $baseline ($baseline*2) ($baseline*1.5) ($baseline*2); + background: $gray-d3; + + // needed since page load is very slow + display: none; + + // needed since page load is very slow + &.is-shown { + display: block; + } + + &.wrapper-alert-warning { + box-shadow: 0 1px 1px $white, inset 0 2px 2px $shadow-d1, inset 0 -4px 1px $orange; + + .feedback-symbol { + color: $orange; + } + } + + &.wrapper-alert-error { + box-shadow: 0 1px 1px $white, inset 0 2px 2px $shadow-d1, inset 0 -4px 1px $red-l1; + + .feedback-symbol { + color: $red-l1; + } + } + + &.wrapper-alert-confirmation { + box-shadow: 0 1px 1px $white, inset 0 2px 2px $shadow-d1, inset 0 -4px 1px $green; + + .feedback-symbol { + color: $green; + } + } + + &.wrapper-alert-announcement { + box-shadow: 0 1px 1px $white, inset 0 2px 2px $shadow-d1, inset 0 -4px 1px $blue; + + .feedback-symbol { + color: $blue; + } + } + + &.wrapper-alert-step-required { + box-shadow: 0 1px 1px $white, inset 0 2px 2px $shadow-d1, inset 0 -4px 1px $pink; + + .feedback-symbol { + color: $pink; + } + } +} + +// adopted alerts +.alert { + @include box-sizing(border-box); + @include clearfix(); + margin: 0 auto; + width: flex-grid(12); + max-width: $fg-max-width; + min-width: $fg-min-width; + color: $white; + + strong { + @extend %t-strong; + } + + .feedback-symbol, .copy { + float: left; + } + + .feedback-symbol { + @include transition (color $tmg-f1 ease-in-out 0s); + @extend %t-icon3; + width: flex-grid(1, 12); + margin: ($baseline/4) flex-gutter() 0 0; + text-align: right; + } + + .copy { + width: flex-grid(10, 12); + margin-top: ($baseline/2); + color: $gray-l2; + + .title { + @extend %t-title7; + margin-bottom: 0; + color: $white; + } + } + + // with actions + &.has-actions { + + .feedback-symbol { + width: flex-grid(1, 12); + } + + .copy { + width: flex-grid(7, 12); + @include margin-right(flex-gutter()); + } + + .nav-actions { + width: flex-grid(4, 12); + @include float(left); + margin-top: ($baseline/2); + text-align: right; + + .nav-item { + display: inline-block; + vertical-align: middle; + @include margin-right($baseline/2); + + &:last-child { + @include margin-right(0); + } + + .action-primary { + @extend %t-action4; + @extend %t-strong; + } + + .action-secondary { + @extend %t-action4; + } + } + } +} + + // with cancel + .action-alert-close { + @include border-bottom-radius(($baseline/5)); + position: absolute; + top: -($baseline/10); + right: $baseline; + padding: ($baseline/4) ($baseline/2) 0 ($baseline/2); + background: $gray-d4; + text-align: center; + + .label { + @extend %cont-text-sr; + } + + .icon { + @extend %t-icon6; + color: $white; + width: auto; + margin: 0; + padding: 2px; + } + + &:hover { + background: $gray-d1; + } + } + + // with dismiss (to sunset action-alert-clos) + .action-dismiss { + + .button { + // I tried moving the btn-secondary-white into lms/static/sass/elements/_controls.scss + // but sass compiler fails to find ui-btn-secondary, ui-btn-secondary is defined in + // lms/static/sass/_mixins.scss. I also tried reordering the _mixins.scss import in + // lms/static/sass/_build-lms.scss but issue is still there, so i made it optional. + // Making this optional wouldn't cause any issue for confirmation dialog at-least. + @extend %btn-secondary-white !optional; + padding:($baseline/4) ($baseline/2); + } + + .icon,.button-copy { + display: inline-block; + vertical-align: middle; + } + + .icon { + @extend %t-icon4; + margin-right: ($baseline/4); + } + + .button-copy { + @extend %t-copy-sub1; + } + } +} + +// ==================== + +// js enabled +.js { + + // prompt set-up + .wrapper-prompt { + visibility: hidden; + pointer-events: none; + + .prompt { + + } + } + + // prompt showing + &.prompt-is-shown { + + .wrapper-prompt.is-shown { + visibility: visible; + pointer-events: auto; + + .prompt { + @include animation(bounceIn $tmg-f1 ease-in-out 1); + } + } + } + + // prompt hiding + &.prompt-is-hiding { + + .wrapper-prompt { + + .prompt { + @include animation(bounceOut $tmg-f1 ease-in-out 1); + } + } + } + + // alert showing/hiding done by jQuery + .wrapper-alert { } + + // notification showing/hiding + .wrapper-notification { + bottom: -($ui-notification-height); + + // varying animations + &.is-shown { + @include animation(notificationSlideUp $tmg-s1 ease-in-out 1); + @include animation-fill-mode(forwards); + } + + &.is-hiding { + @include animation(notificationSlideDown $tmg-s1 ease-in-out 1); + @include animation-fill-mode(forwards); + } + } +} + +// ==================== + +// block-level messages and validation +.wrapper-message { + + .message { + @extend %t-copy-sub1; + background-color: $gray-d2; + padding: ($baseline/2) ($baseline*0.75); + color: $white; + + .icon { + font-style: normal; + } + + &.information { + @extend %t-copy-sub1; + background-color: $gray-l5; + color: $gray-d2; + } + + &.validation { + background-color: $gray-d2; + color: $white; + + a { + color: $blue-l2; + } + } + + &.has-warnings { + border-bottom: 3px solid $orange; + + .fa-warning { + margin-right: ($baseline/2); + color: $orange; + } + } + + &.has-errors { + border-bottom: 3px solid $red-l2; + + .fa-exclamation-circle { + margin-right: ($baseline/2); + color: $red-l2; + } + } + } + + .message-list { + margin-bottom: 0; + } + + .message-actions { + padding: ($baseline/2) $baseline; + background-color: $gray-d1; + + .actions-list { + @extend %actions-list !optional; + } + } +} + + +// ==================== + +// temporary +body.uxdesign.alerts { + + .content-primary, .content-supplementary { + @include box-sizing(border-box); + float: left; + } + + .content-primary { + @extend %ui-window; + width: flex-grid(12, 12); + @include margin-right(flex-gutter()); + padding: $baseline ($baseline*1.5); + + > section { + margin-bottom: ($baseline*2); + + &:last-child { + margin-bottom: 0; + } + } + + ul { + + li { + @include clearfix(); + width: flex-grid(12, 12); + margin-bottom: ($baseline/4); + border-bottom: 1px solid $gray-l4; + padding-bottom: ($baseline/4); + + &:last-child { + margin-bottom: 0; + border-bottom: none; + padding-bottom: 0; + } + + a { + @include float(left); + width: flex-grid(5, 12); + @include margin-right(flex-gutter()); + } + } + } + } +} + +// ==================== + +// artifact styles +.main-wrapper { + + .alert { + @extend %t-copy-sub1; + padding: 15px 20px; + margin-bottom: ($baseline*1.5); + border-radius: 3px; + border: 1px solid #edbd3c; + border-radius: 3px; + background: #fbf6e1; + // background: #edbd3c; + @include clearfix(); + + .alert-message { + @include float(left); + margin: 4px 0 0 0; + color: $gray-d3; + } + + strong { + @extend %t-strong; + } + + .alert-action { + @include float(left); + + &.secondary { + @include orange-button; + } + } + } +} + +body.error { + background: $gray-d4; + color: $gray-d3; + + .primary-header { + display: none; + } + + .error-prompt { + width: 700px; + margin: 150px auto; + padding: 60px 50px 90px; + border-radius: 3px; + background: $white; + text-align: center; + } + + h1 { + @extend %t-title1; + @extend %t-light; + float: none; + margin: 0; + color: $gray-d3; + } + + .description { + @extend %t-copy-lead2; + margin-bottom: 50px; + } + + .back-button { + @include blue-button(); + @extend %t-action1; + padding: 14px 40px 18px; + } +} + +.advance-modules-remove-text { + margin-top: ($baseline/2); +} diff --git a/lms/templates/main.html b/lms/templates/main.html index d06f612e8f..40c62ee6f3 100644 --- a/lms/templates/main.html +++ b/lms/templates/main.html @@ -125,6 +125,7 @@ from branding import api as branding_api +
% if not disable_window_wrap:
% endif From d8b419c64f85bab82d76910f1f4c4a23ec409c64 Mon Sep 17 00:00:00 2001 From: muhammad-ammar Date: Wed, 26 Aug 2015 16:48:03 +0500 Subject: [PATCH 2/2] Review changes --- .../coffee/spec/views/feedback_spec.coffee | 315 ---------------- .../common/js/components/utils/view_utils.js | 6 +- .../common/js/components/views/feedback.js | 284 +++++++-------- .../js/components/views/feedback_alert.js | 75 ++-- .../components/views/feedback_notification.js | 57 +-- .../js/components/views/feedback_prompt.js | 71 ++-- .../js/spec/components/feedback_spec.js | 336 ++++++++++++++++++ .../js/spec/components/view_utils_spec.js | 7 +- .../common/js/spec_helpers/view_helpers.js | 15 +- .../components/system-feedback.underscore | 5 +- .../teams/js/spec/views/team_profile_spec.js | 10 +- lms/static/sass/_build-lms.scss | 2 +- lms/static/sass/_mixins-inherited.scss | 1 + lms/static/sass/_mixins.scss | 1 + 14 files changed, 619 insertions(+), 566 deletions(-) delete mode 100644 cms/static/coffee/spec/views/feedback_spec.coffee create mode 100644 common/static/common/js/spec/components/feedback_spec.js create mode 120000 lms/static/sass/_mixins-inherited.scss create mode 120000 lms/static/sass/_mixins.scss diff --git a/cms/static/coffee/spec/views/feedback_spec.coffee b/cms/static/coffee/spec/views/feedback_spec.coffee deleted file mode 100644 index 6f27ac93e5..0000000000 --- a/cms/static/coffee/spec/views/feedback_spec.coffee +++ /dev/null @@ -1,315 +0,0 @@ -define ["jquery", "js/views/feedback", "js/views/feedback_notification", "js/views/feedback_alert", - "js/views/feedback_prompt", "sinon"], -($, SystemFeedback, NotificationView, AlertView, PromptView, sinon) -> - - tpl = readFixtures('system-feedback.underscore') - - beforeEach -> - setFixtures(sandbox({id: "page-alert"})) - appendSetFixtures(sandbox({id: "page-notification"})) - appendSetFixtures(sandbox({id: "page-prompt"})) - appendSetFixtures($("