Review changes
This commit is contained in:
@@ -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($("<script>", {id: "system-feedback-tpl", type: "text/template"}).text(tpl))
|
||||
@addMatchers
|
||||
toBeShown: ->
|
||||
@actual.hasClass("is-shown") and not @actual.hasClass("is-hiding")
|
||||
toBeHiding: ->
|
||||
@actual.hasClass("is-hiding") and not @actual.hasClass("is-shown")
|
||||
toContainText: (text) ->
|
||||
# remove this when we upgrade jasmine-jquery
|
||||
trimmedText = $.trim(@actual.text())
|
||||
if text and $.isFunction(text.test)
|
||||
return text.test(trimmedText)
|
||||
else
|
||||
return trimmedText.indexOf(text) != -1;
|
||||
toHaveBeenPrevented: ->
|
||||
# remove this when we upgrade jasmine-jquery
|
||||
eventName = @actual.eventName
|
||||
selector = @actual.selector
|
||||
@message = ->
|
||||
[
|
||||
"Expected event #{eventName} to have been prevented on #{selector}",
|
||||
"Expected event #{eventName} not to have been prevented on #{selector}"
|
||||
]
|
||||
return jasmine.JQuery.events.wasPrevented(selector, eventName)
|
||||
|
||||
describe "SystemFeedback", ->
|
||||
beforeEach ->
|
||||
@options =
|
||||
title: "Portal"
|
||||
message: "Welcome to the Aperture Science Computer-Aided Enrichment Center"
|
||||
# it will be interesting to see when this.render is called, so lets spy on it
|
||||
@renderSpy = spyOn(AlertView.Confirmation.prototype, 'render').andCallThrough()
|
||||
@showSpy = spyOn(AlertView.Confirmation.prototype, 'show').andCallThrough()
|
||||
@hideSpy = spyOn(AlertView.Confirmation.prototype, 'hide').andCallThrough()
|
||||
@clock = sinon.useFakeTimers()
|
||||
|
||||
afterEach ->
|
||||
@clock.restore()
|
||||
|
||||
it "requires a type and an intent", ->
|
||||
neither = =>
|
||||
new SystemFeedback(@options)
|
||||
noType = =>
|
||||
options = $.extend({}, @options)
|
||||
options.intent = "confirmation"
|
||||
new SystemFeedback(options)
|
||||
noIntent = =>
|
||||
options = $.extend({}, @options)
|
||||
options.type = "alert"
|
||||
new SystemFeedback(options)
|
||||
both = =>
|
||||
options = $.extend({}, @options)
|
||||
options.type = "alert"
|
||||
options.intent = "confirmation"
|
||||
new SystemFeedback(options)
|
||||
|
||||
expect(neither).toThrow()
|
||||
expect(noType).toThrow()
|
||||
expect(noIntent).toThrow()
|
||||
expect(both).not.toThrow()
|
||||
|
||||
# for simplicity, we'll use AlertView.Confirmation from here on,
|
||||
# which extends and proxies to SystemFeedback
|
||||
|
||||
it "does not show on initalize", ->
|
||||
view = new AlertView.Confirmation(@options)
|
||||
expect(@renderSpy).not.toHaveBeenCalled()
|
||||
expect(@showSpy).not.toHaveBeenCalled()
|
||||
|
||||
# Disabled flaky test TNL-559
|
||||
xit "renders the template", ->
|
||||
view = new AlertView.Confirmation(@options)
|
||||
view.show()
|
||||
|
||||
expect(view.$(".action-close")).toBeDefined()
|
||||
expect(view.$('.wrapper')).toBeShown()
|
||||
expect(view.$el).toContainText(@options.title)
|
||||
expect(view.$el).toContainText(@options.message)
|
||||
|
||||
# Disabled flaky test TNL-559
|
||||
xit "close button sends a .hide() message", ->
|
||||
view = new AlertView.Confirmation(@options).show()
|
||||
view.$(".action-close").click()
|
||||
expect(@hideSpy).toHaveBeenCalled()
|
||||
@clock.tick(900)
|
||||
expect(view.$('.wrapper')).toBeHiding()
|
||||
|
||||
describe "PromptView", ->
|
||||
# for some reason, expect($("body")) blows up the test runner, so this test
|
||||
# just exercises the Prompt rather than asserting on anything. Best I can
|
||||
# do for now. :(
|
||||
it "changes class on body", ->
|
||||
# expect($("body")).not.toHaveClass("prompt-is-shown")
|
||||
view = new PromptView.Confirmation({
|
||||
title: "Portal"
|
||||
message: "Welcome to the Aperture Science Computer-Aided Enrichment Center"
|
||||
})
|
||||
# expect($("body")).toHaveClass("prompt-is-shown")
|
||||
view.hide()
|
||||
# expect($("body")).not.toHaveClass("prompt-is-shown")
|
||||
|
||||
describe "NotificationView.Mini", ->
|
||||
beforeEach ->
|
||||
@view = new NotificationView.Mini()
|
||||
|
||||
it "should have minShown set to 1250 by default", ->
|
||||
expect(@view.options.minShown).toEqual(1250)
|
||||
|
||||
it "should have closeIcon set to false by default", ->
|
||||
expect(@view.options.closeIcon).toBeFalsy()
|
||||
|
||||
# Disabled flaky test TNL-559
|
||||
xdescribe "SystemFeedback click events", ->
|
||||
beforeEach ->
|
||||
@primaryClickSpy = jasmine.createSpy('primaryClick')
|
||||
@secondaryClickSpy = jasmine.createSpy('secondaryClick')
|
||||
@view = new NotificationView.Warning(
|
||||
title: "Unsaved",
|
||||
message: "Your content is currently Unsaved.",
|
||||
actions:
|
||||
primary:
|
||||
text: "Save",
|
||||
class: "save-button",
|
||||
click: @primaryClickSpy
|
||||
secondary:
|
||||
text: "Revert",
|
||||
class: "cancel-button",
|
||||
click: @secondaryClickSpy
|
||||
)
|
||||
@view.show()
|
||||
|
||||
it "should trigger the primary event on a primary click", ->
|
||||
@view.$(".action-primary").click()
|
||||
expect(@primaryClickSpy).toHaveBeenCalled()
|
||||
expect(@secondaryClickSpy).not.toHaveBeenCalled()
|
||||
|
||||
it "should trigger the secondary event on a secondary click", ->
|
||||
@view.$(".action-secondary").click()
|
||||
expect(@secondaryClickSpy).toHaveBeenCalled()
|
||||
expect(@primaryClickSpy).not.toHaveBeenCalled()
|
||||
|
||||
it "should apply class to primary action", ->
|
||||
expect(@view.$(".action-primary")).toHaveClass("save-button")
|
||||
|
||||
it "should apply class to secondary action", ->
|
||||
expect(@view.$(".action-secondary")).toHaveClass("cancel-button")
|
||||
|
||||
it "should preventDefault on primary action", ->
|
||||
spyOnEvent(".action-primary", "click")
|
||||
@view.$(".action-primary").click()
|
||||
expect("click").toHaveBeenPreventedOn(".action-primary")
|
||||
|
||||
it "should preventDefault on secondary action", ->
|
||||
spyOnEvent(".action-secondary", "click")
|
||||
@view.$(".action-secondary").click()
|
||||
expect("click").toHaveBeenPreventedOn(".action-secondary")
|
||||
|
||||
# Disabled flaky test TNL-559
|
||||
xdescribe "SystemFeedback not preventing events", ->
|
||||
beforeEach ->
|
||||
@clickSpy = jasmine.createSpy('clickSpy')
|
||||
@view = new AlertView.Confirmation(
|
||||
title: "It's all good"
|
||||
message: "No reason for this alert"
|
||||
actions:
|
||||
primary:
|
||||
text: "Whatever"
|
||||
click: @clickSpy
|
||||
preventDefault: false
|
||||
)
|
||||
@view.show()
|
||||
|
||||
it "should not preventDefault", ->
|
||||
spyOnEvent(".action-primary", "click")
|
||||
@view.$(".action-primary").click()
|
||||
expect("click").not.toHaveBeenPreventedOn(".action-primary")
|
||||
expect(@clickSpy).toHaveBeenCalled()
|
||||
|
||||
# Disabled flaky test TNL-559
|
||||
xdescribe "SystemFeedback multiple secondary actions", ->
|
||||
beforeEach ->
|
||||
@secondarySpyOne = jasmine.createSpy('secondarySpyOne')
|
||||
@secondarySpyTwo = jasmine.createSpy('secondarySpyTwo')
|
||||
@view = new NotificationView.Warning(
|
||||
title: "No Primary",
|
||||
message: "Pick a secondary action",
|
||||
actions:
|
||||
secondary: [
|
||||
{
|
||||
text: "Option One"
|
||||
class: "option-one"
|
||||
click: @secondarySpyOne
|
||||
}, {
|
||||
text: "Option Two"
|
||||
class: "option-two"
|
||||
click: @secondarySpyTwo
|
||||
}
|
||||
]
|
||||
)
|
||||
@view.show()
|
||||
|
||||
it "should render both", ->
|
||||
expect(@view.el).toContain(".action-secondary.option-one")
|
||||
expect(@view.el).toContain(".action-secondary.option-two")
|
||||
expect(@view.el).not.toContain(".action-secondary.option-one.option-two")
|
||||
expect(@view.$(".action-secondary.option-one")).toContainText("Option One")
|
||||
expect(@view.$(".action-secondary.option-two")).toContainText("Option Two")
|
||||
|
||||
it "should differentiate clicks (1)", ->
|
||||
@view.$(".option-one").click()
|
||||
expect(@secondarySpyOne).toHaveBeenCalled()
|
||||
expect(@secondarySpyTwo).not.toHaveBeenCalled()
|
||||
|
||||
it "should differentiate clicks (2)", ->
|
||||
@view.$(".option-two").click()
|
||||
expect(@secondarySpyOne).not.toHaveBeenCalled()
|
||||
expect(@secondarySpyTwo).toHaveBeenCalled()
|
||||
|
||||
describe "NotificationView minShown and maxShown", ->
|
||||
beforeEach ->
|
||||
@showSpy = spyOn(NotificationView.Confirmation.prototype, 'show')
|
||||
@showSpy.andCallThrough()
|
||||
@hideSpy = spyOn(NotificationView.Confirmation.prototype, 'hide')
|
||||
@hideSpy.andCallThrough()
|
||||
@clock = sinon.useFakeTimers()
|
||||
|
||||
afterEach ->
|
||||
@clock.restore()
|
||||
|
||||
# Disabled flaky test TNL-559
|
||||
xit "should not have minShown or maxShown by default", ->
|
||||
view = new NotificationView.Confirmation()
|
||||
expect(view.options.minShown).toEqual(0)
|
||||
expect(view.options.maxShown).toEqual(Infinity)
|
||||
|
||||
# Disabled flaky test TNL-559
|
||||
xit "a minShown view should not hide too quickly", ->
|
||||
view = new NotificationView.Confirmation({minShown: 1000})
|
||||
view.show()
|
||||
expect(view.$('.wrapper')).toBeShown()
|
||||
|
||||
# call hide() on it, but the minShown should prevent it from hiding right away
|
||||
view.hide()
|
||||
expect(view.$('.wrapper')).toBeShown()
|
||||
|
||||
# wait for the minShown timeout to expire, and check again
|
||||
@clock.tick(1001)
|
||||
expect(view.$('.wrapper')).toBeHiding()
|
||||
|
||||
# Disabled flaky test TNL-559
|
||||
xit "a maxShown view should hide by itself", ->
|
||||
view = new NotificationView.Confirmation({maxShown: 1000})
|
||||
view.show()
|
||||
expect(view.$('.wrapper')).toBeShown()
|
||||
|
||||
# wait for the maxShown timeout to expire, and check again
|
||||
@clock.tick(1001)
|
||||
expect(view.$('.wrapper')).toBeHiding()
|
||||
|
||||
# Disabled flaky test TNL-559
|
||||
xit "a minShown view can stay visible longer", ->
|
||||
view = new NotificationView.Confirmation({minShown: 1000})
|
||||
view.show()
|
||||
expect(view.$('.wrapper')).toBeShown()
|
||||
|
||||
# wait for the minShown timeout to expire, and check again
|
||||
@clock.tick(1001)
|
||||
expect(@hideSpy).not.toHaveBeenCalled()
|
||||
expect(view.$('.wrapper')).toBeShown()
|
||||
|
||||
# can now hide immediately
|
||||
view.hide()
|
||||
expect(view.$('.wrapper')).toBeHiding()
|
||||
|
||||
# Disabled flaky test TNL-559
|
||||
xit "a maxShown view can hide early", ->
|
||||
view = new NotificationView.Confirmation({maxShown: 1000})
|
||||
view.show()
|
||||
expect(view.$('.wrapper')).toBeShown()
|
||||
|
||||
# wait 50 milliseconds, and hide it early
|
||||
@clock.tick(50)
|
||||
view.hide()
|
||||
expect(view.$('.wrapper')).toBeHiding()
|
||||
|
||||
# wait for timeout to expire, make sure it doesn't do anything weird
|
||||
@clock.tick(1000)
|
||||
expect(view.$('.wrapper')).toBeHiding()
|
||||
|
||||
it "a view can have both maxShown and minShown", ->
|
||||
view = new NotificationView.Confirmation({minShown: 1000, maxShown: 2000})
|
||||
view.show()
|
||||
|
||||
# can't hide early
|
||||
@clock.tick(50)
|
||||
view.hide()
|
||||
expect(view.$('.wrapper')).toBeShown()
|
||||
@clock.tick(1000)
|
||||
expect(view.$('.wrapper')).toBeHiding()
|
||||
|
||||
# show it again, and let it hide automatically
|
||||
view.show()
|
||||
@clock.tick(1050)
|
||||
expect(view.$('.wrapper')).toBeShown()
|
||||
@clock.tick(1000)
|
||||
expect(view.$('.wrapper')).toBeHiding()
|
||||
@@ -1,7 +1,10 @@
|
||||
/**
|
||||
* Provides useful utilities for views.
|
||||
*/
|
||||
define(["jquery", "underscore", "gettext", "js/views/feedback_notification", "js/views/feedback_prompt"],
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(["jquery", "underscore", "gettext", "common/js/components/views/feedback_notification",
|
||||
"common/js/components/views/feedback_prompt"],
|
||||
function ($, _, gettext, NotificationView, PromptView) {
|
||||
var toggleExpandCollapse, showLoadingIndicator, hideLoadingIndicator, confirmThenRunOperation,
|
||||
runOperationShowingMessage, disableElementWhileRunning, getScrollOffset, setScrollOffset,
|
||||
@@ -246,3 +249,4 @@ define(["jquery", "underscore", "gettext", "js/views/feedback_notification", "js
|
||||
'checkTotalKeyLengthViolations': checkTotalKeyLengthViolations
|
||||
};
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -1,146 +1,152 @@
|
||||
define(["jquery", "underscore", "underscore.string", "backbone", "js/utils/templates"],
|
||||
function($, _, str, Backbone, TemplateUtils) {
|
||||
var SystemFeedback = Backbone.View.extend({
|
||||
options: {
|
||||
title: "",
|
||||
message: "",
|
||||
intent: null, // "warning", "confirmation", "error", "announcement", "step-required", etc
|
||||
type: null, // "alert", "notification", or "prompt": set by subclass
|
||||
shown: true, // is this view currently being shown?
|
||||
icon: true, // should we render an icon related to the message intent?
|
||||
closeIcon: true, // should we render a close button in the top right corner?
|
||||
minShown: 0, // length of time after this view has been shown before it can be hidden (milliseconds)
|
||||
maxShown: Infinity // length of time after this view has been shown before it will be automatically hidden (milliseconds)
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(["jquery",
|
||||
"underscore",
|
||||
"underscore.string",
|
||||
"backbone",
|
||||
"text!common/templates/components/system-feedback.underscore"],
|
||||
function($, _, str, Backbone, systemFeedbackTemplate) {
|
||||
var SystemFeedback = Backbone.View.extend({
|
||||
options: {
|
||||
title: "",
|
||||
message: "",
|
||||
intent: null, // "warning", "confirmation", "error", "announcement", "step-required", etc
|
||||
type: null, // "alert", "notification", or "prompt": set by subclass
|
||||
shown: true, // is this view currently being shown?
|
||||
icon: true, // should we render an icon related to the message intent?
|
||||
closeIcon: true, // should we render a close button in the top right corner?
|
||||
minShown: 0, // length of time after this view has been shown before it can be hidden (milliseconds)
|
||||
maxShown: Infinity // length of time after this view has been shown before it will be automatically hidden (milliseconds)
|
||||
|
||||
/* Could also have an "actions" hash: here is an example demonstrating
|
||||
the expected structure. For each action, by default the framework
|
||||
will call preventDefault on the click event before the function is
|
||||
run; to make it not do that, just pass `preventDefault: false` in
|
||||
the action object.
|
||||
/* Could also have an "actions" hash: here is an example demonstrating
|
||||
the expected structure. For each action, by default the framework
|
||||
will call preventDefault on the click event before the function is
|
||||
run; to make it not do that, just pass `preventDefault: false` in
|
||||
the action object.
|
||||
|
||||
actions: {
|
||||
primary: {
|
||||
"text": "Save",
|
||||
"class": "action-save",
|
||||
"click": function(view) {
|
||||
// do something when Save is clicked
|
||||
actions: {
|
||||
primary: {
|
||||
"text": "Save",
|
||||
"class": "action-save",
|
||||
"click": function(view) {
|
||||
// do something when Save is clicked
|
||||
}
|
||||
},
|
||||
secondary: [
|
||||
{
|
||||
"text": "Cancel",
|
||||
"class": "action-cancel",
|
||||
"click": function(view) {}
|
||||
}, {
|
||||
"text": "Discard Changes",
|
||||
"class": "action-discard",
|
||||
"click": function(view) {}
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
if (!this.options.type) {
|
||||
throw "SystemFeedback: type required (given " +
|
||||
JSON.stringify(this.options) + ")";
|
||||
}
|
||||
if (!this.options.intent) {
|
||||
throw "SystemFeedback: intent required (given " +
|
||||
JSON.stringify(this.options) + ")";
|
||||
}
|
||||
this.setElement($("#page-" + this.options.type));
|
||||
// handle single "secondary" action
|
||||
if (this.options.actions && this.options.actions.secondary &&
|
||||
!_.isArray(this.options.actions.secondary)) {
|
||||
this.options.actions.secondary = [this.options.actions.secondary];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// public API: show() and hide()
|
||||
show: function() {
|
||||
clearTimeout(this.hideTimeout);
|
||||
this.options.shown = true;
|
||||
this.shownAt = new Date();
|
||||
this.render();
|
||||
if ($.isNumeric(this.options.maxShown)) {
|
||||
this.hideTimeout = setTimeout(_.bind(this.hide, this),
|
||||
this.options.maxShown);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if (this.shownAt && $.isNumeric(this.options.minShown) &&
|
||||
this.options.minShown > new Date() - this.shownAt) {
|
||||
clearTimeout(this.hideTimeout);
|
||||
this.hideTimeout = setTimeout(_.bind(this.hide, this),
|
||||
this.options.minShown - (new Date() - this.shownAt));
|
||||
} else {
|
||||
this.options.shown = false;
|
||||
delete this.shownAt;
|
||||
this.render();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// the rest of the API should be considered semi-private
|
||||
events: {
|
||||
"click .action-close": "hide",
|
||||
"click .action-primary": "primaryClick",
|
||||
"click .action-secondary": "secondaryClick"
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// there can be only one active view of a given type at a time: only
|
||||
// one alert, only one notification, only one prompt. Therefore, we'll
|
||||
// use a singleton approach.
|
||||
var singleton = SystemFeedback["active_" + this.options.type];
|
||||
if (singleton && singleton !== this) {
|
||||
singleton.stopListening();
|
||||
singleton.undelegateEvents();
|
||||
}
|
||||
this.$el.html(_.template(systemFeedbackTemplate)(this.options));
|
||||
SystemFeedback["active_" + this.options.type] = this;
|
||||
return this;
|
||||
},
|
||||
|
||||
primaryClick: function(event) {
|
||||
var actions, primary;
|
||||
actions = this.options.actions;
|
||||
if (!actions) { return; }
|
||||
primary = actions.primary;
|
||||
if (!primary) { return; }
|
||||
if (primary.preventDefault !== false) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if (primary.click) {
|
||||
primary.click.call(event.target, this, event);
|
||||
}
|
||||
},
|
||||
secondary: [
|
||||
{
|
||||
"text": "Cancel",
|
||||
"class": "action-cancel",
|
||||
"click": function(view) {}
|
||||
}, {
|
||||
"text": "Discard Changes",
|
||||
"class": "action-discard",
|
||||
"click": function(view) {}
|
||||
|
||||
secondaryClick: function(event) {
|
||||
var actions, secondaryList, secondary, i;
|
||||
actions = this.options.actions;
|
||||
if (!actions) { return; }
|
||||
secondaryList = actions.secondary;
|
||||
if (!secondaryList) { return; }
|
||||
// which secondary action was clicked?
|
||||
i = 0; // default to the first secondary action (easier for testing)
|
||||
if (event && event.target) {
|
||||
i = _.indexOf(this.$(".action-secondary"), event.target);
|
||||
}
|
||||
secondary = secondaryList[i];
|
||||
if (secondary.preventDefault !== false) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if (secondary.click) {
|
||||
secondary.click.call(event.target, this, event);
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
if (!this.options.type) {
|
||||
throw "SystemFeedback: type required (given " +
|
||||
JSON.stringify(this.options) + ")";
|
||||
}
|
||||
if (!this.options.intent) {
|
||||
throw "SystemFeedback: intent required (given " +
|
||||
JSON.stringify(this.options) + ")";
|
||||
}
|
||||
this.template = TemplateUtils.loadTemplate("system-feedback");
|
||||
this.setElement($("#page-" + this.options.type));
|
||||
// handle single "secondary" action
|
||||
if (this.options.actions && this.options.actions.secondary &&
|
||||
!_.isArray(this.options.actions.secondary)) {
|
||||
this.options.actions.secondary = [this.options.actions.secondary];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// public API: show() and hide()
|
||||
show: function() {
|
||||
clearTimeout(this.hideTimeout);
|
||||
this.options.shown = true;
|
||||
this.shownAt = new Date();
|
||||
this.render();
|
||||
if ($.isNumeric(this.options.maxShown)) {
|
||||
this.hideTimeout = setTimeout(_.bind(this.hide, this),
|
||||
this.options.maxShown);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if (this.shownAt && $.isNumeric(this.options.minShown) &&
|
||||
this.options.minShown > new Date() - this.shownAt) {
|
||||
clearTimeout(this.hideTimeout);
|
||||
this.hideTimeout = setTimeout(_.bind(this.hide, this),
|
||||
this.options.minShown - (new Date() - this.shownAt));
|
||||
} else {
|
||||
this.options.shown = false;
|
||||
delete this.shownAt;
|
||||
this.render();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// the rest of the API should be considered semi-private
|
||||
events: {
|
||||
"click .action-close": "hide",
|
||||
"click .action-primary": "primaryClick",
|
||||
"click .action-secondary": "secondaryClick"
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// there can be only one active view of a given type at a time: only
|
||||
// one alert, only one notification, only one prompt. Therefore, we'll
|
||||
// use a singleton approach.
|
||||
var singleton = SystemFeedback["active_" + this.options.type];
|
||||
if (singleton && singleton !== this) {
|
||||
singleton.stopListening();
|
||||
singleton.undelegateEvents();
|
||||
}
|
||||
this.$el.html(this.template(this.options));
|
||||
SystemFeedback["active_" + this.options.type] = this;
|
||||
return this;
|
||||
},
|
||||
|
||||
primaryClick: function(event) {
|
||||
var actions, primary;
|
||||
actions = this.options.actions;
|
||||
if (!actions) { return; }
|
||||
primary = actions.primary;
|
||||
if (!primary) { return; }
|
||||
if (primary.preventDefault !== false) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if (primary.click) {
|
||||
primary.click.call(event.target, this, event);
|
||||
}
|
||||
},
|
||||
|
||||
secondaryClick: function(event) {
|
||||
var actions, secondaryList, secondary, i;
|
||||
actions = this.options.actions;
|
||||
if (!actions) { return; }
|
||||
secondaryList = actions.secondary;
|
||||
if (!secondaryList) { return; }
|
||||
// which secondary action was clicked?
|
||||
i = 0; // default to the first secondary action (easier for testing)
|
||||
if (event && event.target) {
|
||||
i = _.indexOf(this.$(".action-secondary"), event.target);
|
||||
}
|
||||
secondary = secondaryList[i];
|
||||
if (secondary.preventDefault !== false) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if (secondary.click) {
|
||||
secondary.click.call(event.target, this, event);
|
||||
}
|
||||
}
|
||||
});
|
||||
return SystemFeedback;
|
||||
});
|
||||
return SystemFeedback;
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -1,37 +1,42 @@
|
||||
define(["jquery", "underscore", "underscore.string", "js/views/feedback"], function($, _, str, SystemFeedbackView) {
|
||||
var Alert = SystemFeedbackView.extend({
|
||||
options: $.extend({}, SystemFeedbackView.prototype.options, {
|
||||
type: "alert"
|
||||
}),
|
||||
slide_speed: 900,
|
||||
show: function() {
|
||||
SystemFeedbackView.prototype.show.apply(this, arguments);
|
||||
this.$el.hide();
|
||||
this.$el.slideDown(this.slide_speed);
|
||||
return this;
|
||||
},
|
||||
hide: function () {
|
||||
this.$el.slideUp({
|
||||
duration: this.slide_speed
|
||||
});
|
||||
setTimeout(_.bind(SystemFeedbackView.prototype.hide, this, arguments),
|
||||
this.slideSpeed);
|
||||
}
|
||||
});
|
||||
|
||||
// create Alert.Warning, Alert.Confirmation, etc
|
||||
var capitalCamel, intents;
|
||||
capitalCamel = _.compose(str.capitalize, str.camelize);
|
||||
intents = ["warning", "error", "confirmation", "announcement", "step-required", "help", "mini"];
|
||||
_.each(intents, function(intent) {
|
||||
var subclass;
|
||||
subclass = Alert.extend({
|
||||
options: $.extend({}, Alert.prototype.options, {
|
||||
intent: intent
|
||||
})
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(["jquery", "underscore", "underscore.string", "common/js/components/views/feedback"],
|
||||
function($, _, str, SystemFeedbackView) {
|
||||
str = str || _.str;
|
||||
var Alert = SystemFeedbackView.extend({
|
||||
options: $.extend({}, SystemFeedbackView.prototype.options, {
|
||||
type: "alert"
|
||||
}),
|
||||
slide_speed: 900,
|
||||
show: function() {
|
||||
SystemFeedbackView.prototype.show.apply(this, arguments);
|
||||
this.$el.hide();
|
||||
this.$el.slideDown(this.slide_speed);
|
||||
return this;
|
||||
},
|
||||
hide: function () {
|
||||
this.$el.slideUp({
|
||||
duration: this.slide_speed
|
||||
});
|
||||
setTimeout(_.bind(SystemFeedbackView.prototype.hide, this, arguments),
|
||||
this.slideSpeed);
|
||||
}
|
||||
});
|
||||
Alert[capitalCamel(intent)] = subclass;
|
||||
});
|
||||
|
||||
return Alert;
|
||||
});
|
||||
// create Alert.Warning, Alert.Confirmation, etc
|
||||
var capitalCamel, intents;
|
||||
capitalCamel = _.compose(str.capitalize, str.camelize);
|
||||
intents = ["warning", "error", "confirmation", "announcement", "step-required", "help", "mini"];
|
||||
_.each(intents, function(intent) {
|
||||
var subclass;
|
||||
subclass = Alert.extend({
|
||||
options: $.extend({}, Alert.prototype.options, {
|
||||
intent: intent
|
||||
})
|
||||
});
|
||||
Alert[capitalCamel(intent)] = subclass;
|
||||
});
|
||||
|
||||
return Alert;
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -1,29 +1,34 @@
|
||||
define(["jquery", "underscore", "underscore.string", "js/views/feedback"], function($, _, str, SystemFeedbackView) {
|
||||
var Notification = SystemFeedbackView.extend({
|
||||
options: $.extend({}, SystemFeedbackView.prototype.options, {
|
||||
type: "notification",
|
||||
closeIcon: false
|
||||
})
|
||||
});
|
||||
|
||||
// create Notification.Warning, Notification.Confirmation, etc
|
||||
var capitalCamel, intents;
|
||||
capitalCamel = _.compose(str.capitalize, str.camelize);
|
||||
intents = ["warning", "error", "confirmation", "announcement", "step-required", "help", "mini"];
|
||||
_.each(intents, function(intent) {
|
||||
var subclass;
|
||||
subclass = Notification.extend({
|
||||
options: $.extend({}, Notification.prototype.options, {
|
||||
intent: intent
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(["jquery", "underscore", "underscore.string", "common/js/components/views/feedback"],
|
||||
function($, _, str, SystemFeedbackView) {
|
||||
str = str || _.str;
|
||||
var Notification = SystemFeedbackView.extend({
|
||||
options: $.extend({}, SystemFeedbackView.prototype.options, {
|
||||
type: "notification",
|
||||
closeIcon: false
|
||||
})
|
||||
});
|
||||
Notification[capitalCamel(intent)] = subclass;
|
||||
|
||||
// create Notification.Warning, Notification.Confirmation, etc
|
||||
var capitalCamel, intents;
|
||||
capitalCamel = _.compose(str.capitalize, str.camelize);
|
||||
intents = ["warning", "error", "confirmation", "announcement", "step-required", "help", "mini"];
|
||||
_.each(intents, function(intent) {
|
||||
var subclass;
|
||||
subclass = Notification.extend({
|
||||
options: $.extend({}, Notification.prototype.options, {
|
||||
intent: intent
|
||||
})
|
||||
});
|
||||
Notification[capitalCamel(intent)] = subclass;
|
||||
});
|
||||
|
||||
// set more sensible defaults for Notification.Mini views
|
||||
var miniOptions = Notification.Mini.prototype.options;
|
||||
miniOptions.minShown = 1250;
|
||||
miniOptions.closeIcon = false;
|
||||
|
||||
return Notification;
|
||||
});
|
||||
|
||||
// set more sensible defaults for Notification.Mini views
|
||||
var miniOptions = Notification.Mini.prototype.options;
|
||||
miniOptions.minShown = 1250;
|
||||
miniOptions.closeIcon = false;
|
||||
|
||||
return Notification;
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -1,35 +1,40 @@
|
||||
define(["jquery", "underscore", "underscore.string", "js/views/feedback"], function($, _, str, SystemFeedbackView) {
|
||||
var Prompt = SystemFeedbackView.extend({
|
||||
options: $.extend({}, SystemFeedbackView.prototype.options, {
|
||||
type: "prompt",
|
||||
closeIcon: false,
|
||||
icon: false
|
||||
}),
|
||||
render: function() {
|
||||
if(!window.$body) { window.$body = $(document.body); }
|
||||
if(this.options.shown) {
|
||||
$body.addClass('prompt-is-shown');
|
||||
} else {
|
||||
$body.removeClass('prompt-is-shown');
|
||||
}
|
||||
// super() in Javascript has awkward syntax :(
|
||||
return SystemFeedbackView.prototype.render.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(["jquery", "underscore", "underscore.string", "common/js/components/views/feedback"],
|
||||
function($, _, str, SystemFeedbackView) {
|
||||
str = str || _.str;
|
||||
var Prompt = SystemFeedbackView.extend({
|
||||
options: $.extend({}, SystemFeedbackView.prototype.options, {
|
||||
type: "prompt",
|
||||
closeIcon: false,
|
||||
icon: false
|
||||
}),
|
||||
render: function() {
|
||||
if(!window.$body) { window.$body = $(document.body); }
|
||||
if(this.options.shown) {
|
||||
$body.addClass('prompt-is-shown');
|
||||
} else {
|
||||
$body.removeClass('prompt-is-shown');
|
||||
}
|
||||
// super() in Javascript has awkward syntax :(
|
||||
return SystemFeedbackView.prototype.render.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
|
||||
// create Prompt.Warning, Prompt.Confirmation, etc
|
||||
var capitalCamel, intents;
|
||||
capitalCamel = _.compose(str.capitalize, str.camelize);
|
||||
intents = ["warning", "error", "confirmation", "announcement", "step-required", "help", "mini"];
|
||||
_.each(intents, function(intent) {
|
||||
var subclass;
|
||||
subclass = Prompt.extend({
|
||||
options: $.extend({}, Prompt.prototype.options, {
|
||||
intent: intent
|
||||
})
|
||||
// create Prompt.Warning, Prompt.Confirmation, etc
|
||||
var capitalCamel, intents;
|
||||
capitalCamel = _.compose(str.capitalize, str.camelize);
|
||||
intents = ["warning", "error", "confirmation", "announcement", "step-required", "help", "mini"];
|
||||
_.each(intents, function(intent) {
|
||||
var subclass;
|
||||
subclass = Prompt.extend({
|
||||
options: $.extend({}, Prompt.prototype.options, {
|
||||
intent: intent
|
||||
})
|
||||
});
|
||||
Prompt[capitalCamel(intent)] = subclass;
|
||||
});
|
||||
|
||||
return Prompt;
|
||||
});
|
||||
Prompt[capitalCamel(intent)] = subclass;
|
||||
});
|
||||
|
||||
return Prompt;
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
336
common/static/common/js/spec/components/feedback_spec.js
Normal file
336
common/static/common/js/spec/components/feedback_spec.js
Normal file
@@ -0,0 +1,336 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
(function() {
|
||||
|
||||
define(["jquery", "common/js/components/views/feedback", "common/js/components/views/feedback_notification", "common/js/components/views/feedback_alert", "common/js/components/views/feedback_prompt", "sinon"], function($, SystemFeedback, NotificationView, AlertView, PromptView, sinon) {
|
||||
var tpl;
|
||||
tpl = readFixtures('system-feedback.underscore');
|
||||
beforeEach(function() {
|
||||
setFixtures(sandbox({
|
||||
id: "page-alert"
|
||||
}));
|
||||
appendSetFixtures(sandbox({
|
||||
id: "page-notification"
|
||||
}));
|
||||
appendSetFixtures(sandbox({
|
||||
id: "page-prompt"
|
||||
}));
|
||||
appendSetFixtures($("<script>", {
|
||||
id: "system-feedback-tpl",
|
||||
type: "text/template"
|
||||
}).text(tpl));
|
||||
return this.addMatchers({
|
||||
toBeShown: function() {
|
||||
return this.actual.hasClass("is-shown") && !this.actual.hasClass("is-hiding");
|
||||
},
|
||||
toBeHiding: function() {
|
||||
return this.actual.hasClass("is-hiding") && !this.actual.hasClass("is-shown");
|
||||
},
|
||||
toContainText: function(text) {
|
||||
var trimmedText;
|
||||
trimmedText = $.trim(this.actual.text());
|
||||
if (text && $.isFunction(text.test)) {
|
||||
return text.test(trimmedText);
|
||||
} else {
|
||||
return trimmedText.indexOf(text) !== -1;
|
||||
}
|
||||
},
|
||||
toHaveBeenPrevented: function() {
|
||||
var eventName, selector;
|
||||
eventName = this.actual.eventName;
|
||||
selector = this.actual.selector;
|
||||
this.message = function() {
|
||||
return ["Expected event " + eventName + " to have been prevented on " + selector, "Expected event " + eventName + " not to have been prevented on " + selector];
|
||||
};
|
||||
return jasmine.JQuery.events.wasPrevented(selector, eventName);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe("SystemFeedback", function() {
|
||||
beforeEach(function() {
|
||||
this.options = {
|
||||
title: "Portal",
|
||||
message: "Welcome to the Aperture Science Computer-Aided Enrichment Center"
|
||||
};
|
||||
this.renderSpy = spyOn(AlertView.Confirmation.prototype, 'render').andCallThrough();
|
||||
this.showSpy = spyOn(AlertView.Confirmation.prototype, 'show').andCallThrough();
|
||||
this.hideSpy = spyOn(AlertView.Confirmation.prototype, 'hide').andCallThrough();
|
||||
return this.clock = sinon.useFakeTimers();
|
||||
});
|
||||
afterEach(function() {
|
||||
return this.clock.restore();
|
||||
});
|
||||
it("requires a type and an intent", function() {
|
||||
var both, neither, noIntent, noType,
|
||||
_this = this;
|
||||
neither = function() {
|
||||
return new SystemFeedback(_this.options);
|
||||
};
|
||||
noType = function() {
|
||||
var options;
|
||||
options = $.extend({}, _this.options);
|
||||
options.intent = "confirmation";
|
||||
return new SystemFeedback(options);
|
||||
};
|
||||
noIntent = function() {
|
||||
var options;
|
||||
options = $.extend({}, _this.options);
|
||||
options.type = "alert";
|
||||
return new SystemFeedback(options);
|
||||
};
|
||||
both = function() {
|
||||
var options;
|
||||
options = $.extend({}, _this.options);
|
||||
options.type = "alert";
|
||||
options.intent = "confirmation";
|
||||
return new SystemFeedback(options);
|
||||
};
|
||||
expect(neither).toThrow();
|
||||
expect(noType).toThrow();
|
||||
expect(noIntent).toThrow();
|
||||
return expect(both).not.toThrow();
|
||||
});
|
||||
it("does not show on initalize", function() {
|
||||
var view;
|
||||
view = new AlertView.Confirmation(this.options);
|
||||
expect(this.renderSpy).not.toHaveBeenCalled();
|
||||
return expect(this.showSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
xit("renders the template", function() {
|
||||
var view;
|
||||
view = new AlertView.Confirmation(this.options);
|
||||
view.show();
|
||||
expect(view.$(".action-close")).toBeDefined();
|
||||
expect(view.$('.wrapper')).toBeShown();
|
||||
expect(view.$el).toContainText(this.options.title);
|
||||
return expect(view.$el).toContainText(this.options.message);
|
||||
});
|
||||
return xit("close button sends a .hide() message", function() {
|
||||
var view;
|
||||
view = new AlertView.Confirmation(this.options).show();
|
||||
view.$(".action-close").click();
|
||||
expect(this.hideSpy).toHaveBeenCalled();
|
||||
this.clock.tick(900);
|
||||
return expect(view.$('.wrapper')).toBeHiding();
|
||||
});
|
||||
});
|
||||
describe("PromptView", function() {
|
||||
return it("changes class on body", function() {
|
||||
var view;
|
||||
view = new PromptView.Confirmation({
|
||||
title: "Portal",
|
||||
message: "Welcome to the Aperture Science Computer-Aided Enrichment Center"
|
||||
});
|
||||
return view.hide();
|
||||
});
|
||||
});
|
||||
describe("NotificationView.Mini", function() {
|
||||
beforeEach(function() {
|
||||
return this.view = new NotificationView.Mini();
|
||||
});
|
||||
it("should have minShown set to 1250 by default", function() {
|
||||
return expect(this.view.options.minShown).toEqual(1250);
|
||||
});
|
||||
return it("should have closeIcon set to false by default", function() {
|
||||
return expect(this.view.options.closeIcon).toBeFalsy();
|
||||
});
|
||||
});
|
||||
xdescribe("SystemFeedback click events", function() {
|
||||
beforeEach(function() {
|
||||
this.primaryClickSpy = jasmine.createSpy('primaryClick');
|
||||
this.secondaryClickSpy = jasmine.createSpy('secondaryClick');
|
||||
this.view = new NotificationView.Warning({
|
||||
title: "Unsaved",
|
||||
message: "Your content is currently Unsaved.",
|
||||
actions: {
|
||||
primary: {
|
||||
text: "Save",
|
||||
"class": "save-button",
|
||||
click: this.primaryClickSpy
|
||||
},
|
||||
secondary: {
|
||||
text: "Revert",
|
||||
"class": "cancel-button",
|
||||
click: this.secondaryClickSpy
|
||||
}
|
||||
}
|
||||
});
|
||||
return this.view.show();
|
||||
});
|
||||
it("should trigger the primary event on a primary click", function() {
|
||||
this.view.$(".action-primary").click();
|
||||
expect(this.primaryClickSpy).toHaveBeenCalled();
|
||||
return expect(this.secondaryClickSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
it("should trigger the secondary event on a secondary click", function() {
|
||||
this.view.$(".action-secondary").click();
|
||||
expect(this.secondaryClickSpy).toHaveBeenCalled();
|
||||
return expect(this.primaryClickSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
it("should apply class to primary action", function() {
|
||||
return expect(this.view.$(".action-primary")).toHaveClass("save-button");
|
||||
});
|
||||
it("should apply class to secondary action", function() {
|
||||
return expect(this.view.$(".action-secondary")).toHaveClass("cancel-button");
|
||||
});
|
||||
it("should preventDefault on primary action", function() {
|
||||
spyOnEvent(".action-primary", "click");
|
||||
this.view.$(".action-primary").click();
|
||||
return expect("click").toHaveBeenPreventedOn(".action-primary");
|
||||
});
|
||||
return it("should preventDefault on secondary action", function() {
|
||||
spyOnEvent(".action-secondary", "click");
|
||||
this.view.$(".action-secondary").click();
|
||||
return expect("click").toHaveBeenPreventedOn(".action-secondary");
|
||||
});
|
||||
});
|
||||
xdescribe("SystemFeedback not preventing events", function() {
|
||||
beforeEach(function() {
|
||||
this.clickSpy = jasmine.createSpy('clickSpy');
|
||||
this.view = new AlertView.Confirmation({
|
||||
title: "It's all good",
|
||||
message: "No reason for this alert",
|
||||
actions: {
|
||||
primary: {
|
||||
text: "Whatever",
|
||||
click: this.clickSpy,
|
||||
preventDefault: false
|
||||
}
|
||||
}
|
||||
});
|
||||
return this.view.show();
|
||||
});
|
||||
return it("should not preventDefault", function() {
|
||||
spyOnEvent(".action-primary", "click");
|
||||
this.view.$(".action-primary").click();
|
||||
expect("click").not.toHaveBeenPreventedOn(".action-primary");
|
||||
return expect(this.clickSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
xdescribe("SystemFeedback multiple secondary actions", function() {
|
||||
beforeEach(function() {
|
||||
this.secondarySpyOne = jasmine.createSpy('secondarySpyOne');
|
||||
this.secondarySpyTwo = jasmine.createSpy('secondarySpyTwo');
|
||||
this.view = new NotificationView.Warning({
|
||||
title: "No Primary",
|
||||
message: "Pick a secondary action",
|
||||
actions: {
|
||||
secondary: [
|
||||
{
|
||||
text: "Option One",
|
||||
"class": "option-one",
|
||||
click: this.secondarySpyOne
|
||||
}, {
|
||||
text: "Option Two",
|
||||
"class": "option-two",
|
||||
click: this.secondarySpyTwo
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
return this.view.show();
|
||||
});
|
||||
it("should render both", function() {
|
||||
expect(this.view.el).toContain(".action-secondary.option-one");
|
||||
expect(this.view.el).toContain(".action-secondary.option-two");
|
||||
expect(this.view.el).not.toContain(".action-secondary.option-one.option-two");
|
||||
expect(this.view.$(".action-secondary.option-one")).toContainText("Option One");
|
||||
return expect(this.view.$(".action-secondary.option-two")).toContainText("Option Two");
|
||||
});
|
||||
it("should differentiate clicks (1)", function() {
|
||||
this.view.$(".option-one").click();
|
||||
expect(this.secondarySpyOne).toHaveBeenCalled();
|
||||
return expect(this.secondarySpyTwo).not.toHaveBeenCalled();
|
||||
});
|
||||
return it("should differentiate clicks (2)", function() {
|
||||
this.view.$(".option-two").click();
|
||||
expect(this.secondarySpyOne).not.toHaveBeenCalled();
|
||||
return expect(this.secondarySpyTwo).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
return describe("NotificationView minShown and maxShown", function() {
|
||||
beforeEach(function() {
|
||||
this.showSpy = spyOn(NotificationView.Confirmation.prototype, 'show');
|
||||
this.showSpy.andCallThrough();
|
||||
this.hideSpy = spyOn(NotificationView.Confirmation.prototype, 'hide');
|
||||
this.hideSpy.andCallThrough();
|
||||
return this.clock = sinon.useFakeTimers();
|
||||
});
|
||||
afterEach(function() {
|
||||
return this.clock.restore();
|
||||
});
|
||||
xit("should not have minShown or maxShown by default", function() {
|
||||
var view;
|
||||
view = new NotificationView.Confirmation();
|
||||
expect(view.options.minShown).toEqual(0);
|
||||
return expect(view.options.maxShown).toEqual(Infinity);
|
||||
});
|
||||
xit("a minShown view should not hide too quickly", function() {
|
||||
var view;
|
||||
view = new NotificationView.Confirmation({
|
||||
minShown: 1000
|
||||
});
|
||||
view.show();
|
||||
expect(view.$('.wrapper')).toBeShown();
|
||||
view.hide();
|
||||
expect(view.$('.wrapper')).toBeShown();
|
||||
this.clock.tick(1001);
|
||||
return expect(view.$('.wrapper')).toBeHiding();
|
||||
});
|
||||
xit("a maxShown view should hide by itself", function() {
|
||||
var view;
|
||||
view = new NotificationView.Confirmation({
|
||||
maxShown: 1000
|
||||
});
|
||||
view.show();
|
||||
expect(view.$('.wrapper')).toBeShown();
|
||||
this.clock.tick(1001);
|
||||
return expect(view.$('.wrapper')).toBeHiding();
|
||||
});
|
||||
xit("a minShown view can stay visible longer", function() {
|
||||
var view;
|
||||
view = new NotificationView.Confirmation({
|
||||
minShown: 1000
|
||||
});
|
||||
view.show();
|
||||
expect(view.$('.wrapper')).toBeShown();
|
||||
this.clock.tick(1001);
|
||||
expect(this.hideSpy).not.toHaveBeenCalled();
|
||||
expect(view.$('.wrapper')).toBeShown();
|
||||
view.hide();
|
||||
return expect(view.$('.wrapper')).toBeHiding();
|
||||
});
|
||||
xit("a maxShown view can hide early", function() {
|
||||
var view;
|
||||
view = new NotificationView.Confirmation({
|
||||
maxShown: 1000
|
||||
});
|
||||
view.show();
|
||||
expect(view.$('.wrapper')).toBeShown();
|
||||
this.clock.tick(50);
|
||||
view.hide();
|
||||
expect(view.$('.wrapper')).toBeHiding();
|
||||
this.clock.tick(1000);
|
||||
return expect(view.$('.wrapper')).toBeHiding();
|
||||
});
|
||||
return it("a view can have both maxShown and minShown", function() {
|
||||
var view;
|
||||
view = new NotificationView.Confirmation({
|
||||
minShown: 1000,
|
||||
maxShown: 2000
|
||||
});
|
||||
view.show();
|
||||
this.clock.tick(50);
|
||||
view.hide();
|
||||
expect(view.$('.wrapper')).toBeShown();
|
||||
this.clock.tick(1000);
|
||||
expect(view.$('.wrapper')).toBeHiding();
|
||||
view.show();
|
||||
this.clock.tick(1050);
|
||||
expect(view.$('.wrapper')).toBeShown();
|
||||
this.clock.tick(1000);
|
||||
return expect(view.$('.wrapper')).toBeHiding();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}).call(this);
|
||||
@@ -1,5 +1,7 @@
|
||||
define(["jquery", "underscore", "js/views/baseview", "js/views/utils/view_utils", "js/spec_helpers/edit_helpers"],
|
||||
function ($, _, BaseView, ViewUtils, ViewHelpers) {
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(["jquery", "underscore", "common/js/components/utils/view_utils", "common/js/spec_helpers/view_helpers", 'jasmine-stealth'],
|
||||
function ($, _, ViewUtils, ViewHelpers) {
|
||||
|
||||
describe("ViewUtils", function() {
|
||||
describe("disabled element while running", function() {
|
||||
@@ -90,3 +92,4 @@ define(["jquery", "underscore", "js/views/baseview", "js/views/utils/view_utils"
|
||||
});
|
||||
});
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -1,16 +1,18 @@
|
||||
/**
|
||||
* Provides helper methods for invoking Studio modal windows in Jasmine tests.
|
||||
*/
|
||||
define(["jquery", "js/views/feedback_notification", "js/views/feedback_prompt", 'common/js/spec_helpers/ajax_helpers',
|
||||
"common/js/spec_helpers/template_helpers"],
|
||||
function($, NotificationView, Prompt, AjaxHelpers, TemplateHelpers) {
|
||||
;(function (define) {
|
||||
'use strict';
|
||||
define(["jquery", "common/js/components/views/feedback_notification", "common/js/components/views/feedback_prompt",
|
||||
'common/js/spec_helpers/ajax_helpers'],
|
||||
function($, NotificationView, Prompt, AjaxHelpers) {
|
||||
var installViewTemplates, createFeedbackSpy, verifyFeedbackShowing,
|
||||
verifyFeedbackHidden, createNotificationSpy, verifyNotificationShowing,
|
||||
verifyNotificationHidden, createPromptSpy, confirmPrompt, inlineEdit, verifyInlineEditChange,
|
||||
installMockAnalytics, removeMockAnalytics, verifyPromptShowing, verifyPromptHidden;
|
||||
installMockAnalytics, removeMockAnalytics, verifyPromptShowing, verifyPromptHidden,
|
||||
clickDeleteItem, patchAndVerifyRequest, submitAndVerifyFormSuccess, submitAndVerifyFormError;
|
||||
|
||||
installViewTemplates = function(append) {
|
||||
TemplateHelpers.installTemplate('system-feedback', !append);
|
||||
installViewTemplates = function() {
|
||||
appendSetFixtures('<div id="page-notification"></div>');
|
||||
};
|
||||
|
||||
@@ -144,3 +146,4 @@ define(["jquery", "js/views/feedback_notification", "js/views/feedback_prompt",
|
||||
'submitAndVerifyFormError': submitAndVerifyFormError
|
||||
};
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -21,17 +21,16 @@
|
||||
|
||||
<% if(obj.actions) { %>
|
||||
<nav class="nav-actions">
|
||||
<h3 class="sr"><%= type %> Actions</h3>
|
||||
<ul>
|
||||
<% if(actions.primary) { %>
|
||||
<li class="nav-item">
|
||||
<a href="#" class="button action-primary <%= actions.primary.class %>"><%= actions.primary.text %></a>
|
||||
<button class="action-primary <%= actions.primary.class %>"><%= actions.primary.text %></button>
|
||||
</li>
|
||||
<% } %>
|
||||
<% if(actions.secondary) {
|
||||
_.each(actions.secondary, function(secondary) { %>
|
||||
<li class="nav-item">
|
||||
<a href="#" class="button action-secondary <%= secondary.class %>"><%= secondary.text %></a>
|
||||
<button class="action-secondary <%= secondary.class %>"><%= secondary.text %></button>
|
||||
</li>
|
||||
<% });
|
||||
} %>
|
||||
|
||||
@@ -74,13 +74,13 @@ define([
|
||||
return profileView;
|
||||
};
|
||||
|
||||
clickLeaveTeam = function(requests, view, confirmLeave) {
|
||||
clickLeaveTeam = function(requests, view, options) {
|
||||
expect(view.$(leaveTeamLinkSelector).length).toBe(1);
|
||||
|
||||
// click on Leave Team link under Team Details
|
||||
view.$(leaveTeamLinkSelector).click();
|
||||
|
||||
if (confirmLeave) {
|
||||
if (!options.cancel) {
|
||||
// click on Confirm button on dialog
|
||||
$('.prompt.warning .action-primary').click();
|
||||
|
||||
@@ -121,7 +121,7 @@ define([
|
||||
view = createTeamProfileView(requests, {membership: DEFAULT_MEMBERSHIP});
|
||||
|
||||
expect(view.$('.new-post-btn').length).toEqual(1);
|
||||
clickLeaveTeam(requests, view, true);
|
||||
clickLeaveTeam(requests, view, {cancel: false});
|
||||
expect(view.$('.new-post-btn').length).toEqual(0);
|
||||
});
|
||||
});
|
||||
@@ -188,7 +188,7 @@ define([
|
||||
requests, {country: 'US', language: 'en', membership: DEFAULT_MEMBERSHIP}
|
||||
);
|
||||
assertTeamDetails(view, 1, true);
|
||||
clickLeaveTeam(requests, view, true);
|
||||
clickLeaveTeam(requests, view, {cancel: false});
|
||||
assertTeamDetails(view, 0, false);
|
||||
});
|
||||
|
||||
@@ -199,7 +199,7 @@ define([
|
||||
requests, {country: 'US', language: 'en', membership: DEFAULT_MEMBERSHIP}
|
||||
);
|
||||
assertTeamDetails(view, 1, true);
|
||||
clickLeaveTeam(requests, view, false);
|
||||
clickLeaveTeam(requests, view, {cancel: true});
|
||||
assertTeamDetails(view, 1, true);
|
||||
});
|
||||
|
||||
|
||||
@@ -81,4 +81,4 @@
|
||||
|
||||
// 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
|
||||
|
||||
1
lms/static/sass/_mixins-inherited.scss
Symbolic link
1
lms/static/sass/_mixins-inherited.scss
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../common/static/sass/_mixins-inherited.scss
|
||||
1
lms/static/sass/_mixins.scss
Symbolic link
1
lms/static/sass/_mixins.scss
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../common/static/sass/_mixins.scss
|
||||
Reference in New Issue
Block a user