Bok_choy tests for upload/remove profile image.
TNL-1538
This commit is contained in:
committed by
Andy Armstrong
parent
ca1f2f7768
commit
c2d83bd4a6
@@ -5,6 +5,8 @@ from . import BASE_URL
|
||||
from bok_choy.page_object import PageObject
|
||||
from .fields import FieldsMixin
|
||||
from bok_choy.promise import EmptyPromise
|
||||
from .instructor_dashboard import InstructorDashboardPage
|
||||
from selenium.webdriver import ActionChains
|
||||
|
||||
|
||||
PROFILE_VISIBILITY_SELECTOR = '#u-field-select-account_privacy option[value="{}"]'
|
||||
@@ -165,3 +167,109 @@ class LearnerProfilePage(FieldsMixin, PageObject):
|
||||
"""
|
||||
self.wait_for_ajax()
|
||||
return self.q(css='#u-field-message-account_privacy').visible
|
||||
|
||||
@property
|
||||
def profile_has_default_image(self):
|
||||
"""
|
||||
Return bool if image field has default photo or not.
|
||||
"""
|
||||
self.wait_for_field('image')
|
||||
default_links = self.q(css='.image-frame').attrs('src')
|
||||
return 'default-profile' in default_links[0] if default_links else False
|
||||
|
||||
def mouse_hover(self, element):
|
||||
"""
|
||||
Mouse over on given element.
|
||||
"""
|
||||
mouse_hover_action = ActionChains(self.browser).move_to_element(element)
|
||||
mouse_hover_action.perform()
|
||||
|
||||
def profile_has_image_with_public_access(self):
|
||||
"""
|
||||
Check if image is present with remove/upload access.
|
||||
"""
|
||||
self.wait_for_field('image')
|
||||
|
||||
self.mouse_hover(self.browser.find_element_by_css_selector('.image-wrapper'))
|
||||
self.wait_for_element_visibility('.u-field-upload-button', "upload button is visible")
|
||||
return self.q(css='.u-field-upload-button').visible
|
||||
|
||||
def profile_has_image_with_private_access(self):
|
||||
"""
|
||||
Check if image is present with remove/upload access.
|
||||
"""
|
||||
self.wait_for_field('image')
|
||||
return self.q(css='.u-field-upload-button').visible
|
||||
|
||||
def upload_file(self, filename):
|
||||
"""
|
||||
Helper method to upload an image file.
|
||||
"""
|
||||
self.wait_for_element_visibility('.u-field-upload-button', "upload button is visible")
|
||||
file_path = InstructorDashboardPage.get_asset_path(filename)
|
||||
|
||||
# make the elements visible.
|
||||
self.browser.execute_script('$(".u-field-upload-button").css("opacity",1);')
|
||||
self.browser.execute_script('$(".upload-button-input").css("opacity",1);')
|
||||
|
||||
self.wait_for_element_visibility('.upload-button-input', "upload button is visible")
|
||||
|
||||
self.browser.execute_script('$(".upload-submit").show();')
|
||||
|
||||
# First send_keys will initialize the jquery auto upload plugin.
|
||||
self.q(css='.upload-button-input').results[0].send_keys(file_path)
|
||||
self.q(css='.upload-submit').first.click()
|
||||
self.q(css='.upload-button-input').results[0].send_keys(file_path)
|
||||
|
||||
self.wait_for_ajax()
|
||||
|
||||
def upload_correct_image_file(self, filename):
|
||||
"""
|
||||
Selects the correct file and clicks the upload button.
|
||||
"""
|
||||
self._upload_file(filename)
|
||||
|
||||
@property
|
||||
def image_upload_success(self):
|
||||
"""
|
||||
Returns the bool, if image is updated or not.
|
||||
"""
|
||||
self.wait_for_field('image')
|
||||
self.wait_for_ajax()
|
||||
|
||||
self.wait_for_element_visibility('.image-frame', "image box is visible")
|
||||
image_link = self.q(css='.image-frame').attrs('src')
|
||||
return 'default-profile' not in image_link[0]
|
||||
|
||||
@property
|
||||
def profile_image_message(self):
|
||||
"""
|
||||
Returns the text message for profile image.
|
||||
"""
|
||||
self.wait_for_field('image')
|
||||
self.wait_for_ajax()
|
||||
return self.q(css='.message-banner p').text[0]
|
||||
|
||||
def remove_profile_image(self):
|
||||
"""
|
||||
Removes the profile image.
|
||||
"""
|
||||
self.wait_for_field('image')
|
||||
self.wait_for_ajax()
|
||||
|
||||
self.wait_for_element_visibility('.image-wrapper', "remove button is visible")
|
||||
self.browser.execute_script('$(".u-field-remove-button").css("opacity",1);')
|
||||
self.mouse_hover(self.browser.find_element_by_css_selector('.image-wrapper'))
|
||||
|
||||
self.wait_for_element_visibility('.u-field-remove-button', "remove button is visible")
|
||||
self.q(css='.u-field-remove-button').first.click()
|
||||
|
||||
self.mouse_hover(self.browser.find_element_by_css_selector('.image-wrapper'))
|
||||
self.wait_for_element_visibility('.u-field-upload-button', "upload button is visible")
|
||||
return True
|
||||
|
||||
@property
|
||||
def remove_link_present(self):
|
||||
self.wait_for_field('image')
|
||||
self.mouse_hover(self.browser.find_element_by_css_selector('.image-wrapper'))
|
||||
return self.q(css='.u-field-remove-button').visible
|
||||
|
||||
@@ -111,6 +111,13 @@ class OwnLearnerProfilePageTest(LearnerProfileTestMixin, WebAppTest):
|
||||
self.assertEqual(profile_page.age_limit_message_present, message is not None)
|
||||
self.assertIn(message, profile_page.profile_forced_private_message)
|
||||
|
||||
def assert_default_image_has_public_access(self, profile_page):
|
||||
"""
|
||||
Assert that profile image has public access.
|
||||
"""
|
||||
self.assertTrue(profile_page.profile_has_default_image)
|
||||
self.assertTrue(profile_page.profile_has_image_with_public_access())
|
||||
|
||||
def test_dashboard_learner_profile_link(self):
|
||||
"""
|
||||
Scenario: Verify that my profile link is present on dashboard page and we can navigate to correct page.
|
||||
@@ -320,6 +327,171 @@ class OwnLearnerProfilePageTest(LearnerProfileTestMixin, WebAppTest):
|
||||
)
|
||||
self.verify_profile_page_view_event(user_id, visibility=self.PRIVACY_PRIVATE)
|
||||
|
||||
def test_user_can_only_see_default_image_for_private_profile(self):
|
||||
"""
|
||||
Scenario: Default profile image behaves correctly for under age user.
|
||||
|
||||
Given that I am on my profile page with private access
|
||||
And I can see default image
|
||||
When I move my cursor to the image
|
||||
Then i cannot see the upload/remove image text
|
||||
And i cannot upload/remove the image.
|
||||
"""
|
||||
year_of_birth = datetime.now().year - 5
|
||||
username, user_id = self.log_in_as_unique_user()
|
||||
profile_page = self.visit_profile_page(username, privacy=self.PRIVACY_PRIVATE)
|
||||
|
||||
self.verify_profile_forced_private_message(
|
||||
username,
|
||||
year_of_birth,
|
||||
message='You must be over 13 to share a full profile.'
|
||||
)
|
||||
self.assertTrue(profile_page.profile_has_default_image)
|
||||
self.assertFalse(profile_page.profile_has_image_with_private_access())
|
||||
|
||||
def test_user_can_see_default_image_for_public_profile(self):
|
||||
"""
|
||||
Scenario: Default profile image behaves correctly for public profile.
|
||||
|
||||
Given that I am on my profile page with public access
|
||||
And I can see default image
|
||||
When I move my cursor to the image
|
||||
Then i can see the upload/remove image text
|
||||
And i am able to upload new image
|
||||
"""
|
||||
username, user_id = self.log_in_as_unique_user()
|
||||
profile_page = self.visit_profile_page(username, privacy=self.PRIVACY_PUBLIC)
|
||||
|
||||
self.assert_default_image_has_public_access(profile_page)
|
||||
|
||||
def test_user_can_upload_the_profile_image_with_success(self):
|
||||
"""
|
||||
Scenario: Upload profile image works correctly.
|
||||
|
||||
Given that I am on my profile page with public access
|
||||
And I can see default image
|
||||
When I move my cursor to the image
|
||||
Then i can see the upload/remove image text
|
||||
When i upload new image via file uploader
|
||||
Then i can see the changed image
|
||||
And i can also see the latest image after reload.
|
||||
"""
|
||||
username, user_id = self.log_in_as_unique_user()
|
||||
profile_page = self.visit_profile_page(username, privacy=self.PRIVACY_PUBLIC)
|
||||
|
||||
self.assert_default_image_has_public_access(profile_page)
|
||||
|
||||
profile_page.upload_file(filename='image.jpg')
|
||||
self.assertTrue(profile_page.image_upload_success)
|
||||
profile_page.visit()
|
||||
self.assertTrue(profile_page.image_upload_success)
|
||||
|
||||
def test_user_can_see_error_for_exceeding_max_file_size_limit(self):
|
||||
"""
|
||||
Scenario: Upload profile image does not work for > 1MB image file.
|
||||
|
||||
Given that I am on my profile page with public access
|
||||
And I can see default image
|
||||
When I move my cursor to the image
|
||||
Then i can see the upload/remove image text
|
||||
When i upload new > 1MB image via file uploader
|
||||
Then i can see the error message for file size limit
|
||||
And i can still see the default image after page reload.
|
||||
"""
|
||||
username, user_id = self.log_in_as_unique_user()
|
||||
profile_page = self.visit_profile_page(username, privacy=self.PRIVACY_PUBLIC)
|
||||
|
||||
self.assert_default_image_has_public_access(profile_page)
|
||||
|
||||
profile_page.upload_file(filename='larger_image.jpg')
|
||||
self.assertEqual(profile_page.profile_image_message, "Your image must be smaller than 1 MB in size.")
|
||||
profile_page.visit()
|
||||
self.assertTrue(profile_page.profile_has_default_image)
|
||||
|
||||
def test_user_can_see_error_for_file_size_below_the_min_limit(self):
|
||||
"""
|
||||
Scenario: Upload profile image does not work for < 100 Bytes image file.
|
||||
|
||||
Given that I am on my profile page with public access
|
||||
And I can see default image
|
||||
When I move my cursor to the image
|
||||
Then i can see the upload/remove image text
|
||||
When i upload new < 100 Bytes image via file uploader
|
||||
Then i can see the error message for minimum file size limit
|
||||
And i can still see the default image after page reload.
|
||||
"""
|
||||
username, user_id = self.log_in_as_unique_user()
|
||||
profile_page = self.visit_profile_page(username, privacy=self.PRIVACY_PUBLIC)
|
||||
|
||||
self.assert_default_image_has_public_access(profile_page)
|
||||
|
||||
profile_page.upload_file(filename='list-icon-visited.png')
|
||||
self.assertEqual(profile_page.profile_image_message, "Your image must be at least 100 bytes in size.")
|
||||
profile_page.visit()
|
||||
self.assertTrue(profile_page.profile_has_default_image)
|
||||
|
||||
def test_user_can_see_error_for_wrong_file_type(self):
|
||||
"""
|
||||
Scenario: Upload profile image does not work for wrong file types.
|
||||
|
||||
Given that I am on my profile page with public access
|
||||
And I can see default image
|
||||
When I move my cursor to the image
|
||||
Then i can see the upload/remove image text
|
||||
When i upload new csv file via file uploader
|
||||
Then i can see the error message for wrong/unsupported file type
|
||||
And i can still see the default image after page reload.
|
||||
"""
|
||||
username, user_id = self.log_in_as_unique_user()
|
||||
profile_page = self.visit_profile_page(username, privacy=self.PRIVACY_PUBLIC)
|
||||
|
||||
self.assert_default_image_has_public_access(profile_page)
|
||||
|
||||
profile_page.upload_file(filename='cohort_users_only_username.csv')
|
||||
self.assertEqual(profile_page.profile_image_message, "Unsupported file type.")
|
||||
profile_page.visit()
|
||||
self.assertTrue(profile_page.profile_has_default_image)
|
||||
|
||||
def test_user_can_remove_profile_image(self):
|
||||
"""
|
||||
Scenario: Remove profile image works correctly.
|
||||
|
||||
Given that I am on my profile page with public access
|
||||
And I can see default image
|
||||
When I move my cursor to the image
|
||||
Then i can see the upload/remove image text
|
||||
When i click on the remove image link
|
||||
Then i can see the default image
|
||||
And i can still see the default image after page reload.
|
||||
"""
|
||||
username, user_id = self.log_in_as_unique_user()
|
||||
profile_page = self.visit_profile_page(username, privacy=self.PRIVACY_PUBLIC)
|
||||
|
||||
self.assert_default_image_has_public_access(profile_page)
|
||||
|
||||
profile_page.upload_file(filename='image.jpg')
|
||||
self.assertTrue(profile_page.image_upload_success)
|
||||
self.assertTrue(profile_page.remove_profile_image())
|
||||
self.assertTrue(profile_page.profile_has_default_image)
|
||||
profile_page.visit()
|
||||
self.assertTrue(profile_page.profile_has_default_image)
|
||||
|
||||
def test_user_cannot_remove_default_image(self):
|
||||
"""
|
||||
Scenario: Remove profile image does not works for default images.
|
||||
|
||||
Given that I am on my profile page with public access
|
||||
And I can see default image
|
||||
When I move my cursor to the image
|
||||
Then i can see only the upload image text
|
||||
And i cannot see the remove image text
|
||||
"""
|
||||
username, user_id = self.log_in_as_unique_user()
|
||||
profile_page = self.visit_profile_page(username, privacy=self.PRIVACY_PUBLIC)
|
||||
|
||||
self.assert_default_image_has_public_access(profile_page)
|
||||
self.assertFalse(profile_page.remove_link_present)
|
||||
|
||||
|
||||
class DifferentUserLearnerProfilePageTest(LearnerProfileTestMixin, WebAppTest):
|
||||
"""
|
||||
|
||||
BIN
common/test/data/uploads/larger_image.jpg
Normal file
BIN
common/test/data/uploads/larger_image.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
BIN
common/test/data/uploads/list-icon-visited.png
Normal file
BIN
common/test/data/uploads/list-icon-visited.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 99 B |
@@ -131,6 +131,14 @@ MOCK_SEARCH_BACKING_FILE = (
|
||||
import uuid
|
||||
SECRET_KEY = uuid.uuid4().hex
|
||||
|
||||
# Set dummy values for profile image settings.
|
||||
PROFILE_IMAGE_BACKEND = {
|
||||
'class': 'storages.backends.overwrite.OverwriteStorage',
|
||||
'options': {
|
||||
'location': os.path.join(MEDIA_ROOT, 'profile-images/'),
|
||||
'base_url': os.path.join(MEDIA_URL, 'profile-images/'),
|
||||
},
|
||||
}
|
||||
#####################################################################
|
||||
# Lastly, see if the developer has any local overrides.
|
||||
try:
|
||||
|
||||
20
lms/static/js/fixtures/student_profile/student_profile.html
Normal file
20
lms/static/js/fixtures/student_profile/student_profile.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<div class="message-banner" aria-live="polite"></div>
|
||||
<div class="wrapper-profile">
|
||||
<div class="ui-loading-indicator">
|
||||
<p>
|
||||
<span class="spin">
|
||||
<i class="icon fa fa-refresh"></i>
|
||||
</span>
|
||||
|
||||
<span class="copy">
|
||||
Loading
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="ui-loading-error is-hidden">
|
||||
<i class="fa fa-exclamation-triangle message-error" aria-hidden=true></i>
|
||||
<span class="copy">
|
||||
An error occurred. Please reload the page.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -18,7 +18,7 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
|
||||
var requests;
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures('<div class="message-banner"></div><div class="wrapper-profile"><div class="ui-loading-indicator"><p><span class="spin"><i class="icon fa fa-refresh"></i></span> <span class="copy">Loading</span></p></div><div class="ui-loading-error is-hidden"><i class="fa fa-exclamation-triangle message-error" aria-hidden=true></i><span class="copy">An error occurred. Please reload the page.</span></div></div>');
|
||||
loadFixtures('js/fixtures/student_profile/student_profile.html');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_readonly');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_dropdown');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_textarea');
|
||||
|
||||
@@ -10,15 +10,20 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
|
||||
|
||||
describe("edx.user.LearnerProfileFields", function () {
|
||||
|
||||
var createImageView = function (ownProfile, hasImage, imageMaxBytes, imageMinBytes, yearOfBirth) {
|
||||
var MOCK_YEAR_OF_BIRTH = 1989;
|
||||
var MOCK_IMAGE_MAX_BYTES = 64;
|
||||
var MOCK_IMAGE_MIN_BYTES = 16;
|
||||
|
||||
var createImageView = function (options) {
|
||||
var yearOfBirth = _.isUndefined(options.yearOfBirth) ? MOCK_YEAR_OF_BIRTH : options.yearOfBirth;
|
||||
var imageMaxBytes = _.isUndefined(options.imageMaxBytes) ? MOCK_IMAGE_MAX_BYTES : options.imageMaxBytes;
|
||||
var imageMinBytes = _.isUndefined(options.imageMinBytes) ? MOCK_IMAGE_MIN_BYTES : options.imageMinBytes;
|
||||
|
||||
var imageData = {
|
||||
image_url_large: '/media/profile-images/default.jpg',
|
||||
has_image: hasImage ? true : false
|
||||
has_image: options.hasImage ? true : false
|
||||
};
|
||||
|
||||
yearOfBirth = _.isUndefined(yearOfBirth) ? 1989 : yearOfBirth;
|
||||
|
||||
var accountSettingsModel = new UserAccountModel();
|
||||
accountSettingsModel.set({'profile_image': imageData});
|
||||
accountSettingsModel.set({'year_of_birth': yearOfBirth});
|
||||
@@ -30,15 +35,10 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
|
||||
el: $('.message-banner')
|
||||
});
|
||||
|
||||
imageMaxBytes = imageMaxBytes || 64;
|
||||
imageMinBytes = imageMinBytes || 16;
|
||||
|
||||
var editable = ownProfile ? 'toggle' : 'never';
|
||||
|
||||
return new LearnerProfileFields.ProfileImageFieldView({
|
||||
model: accountSettingsModel,
|
||||
valueAttribute: "profile_image",
|
||||
editable: editable === 'toggle',
|
||||
editable: options.ownProfile,
|
||||
messageView: messageView,
|
||||
imageMaxBytes: imageMaxBytes,
|
||||
imageMinBytes: imageMinBytes,
|
||||
@@ -48,7 +48,7 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures('<div class="message-banner"></div><div class="wrapper-profile"><div class="ui-loading-indicator"><p><span class="spin"><i class="icon fa fa-refresh"></i></span> <span class="copy">Loading</span></p></div><div class="ui-loading-error is-hidden"><i class="fa fa-exclamation-triangle message-error" aria-hidden=true></i><span class="copy">An error occurred. Please reload the page.</span></div></div>');
|
||||
loadFixtures('js/fixtures/student_profile/student_profile.html');
|
||||
TemplateHelpers.installTemplate('templates/student_profile/learner_profile');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_image');
|
||||
TemplateHelpers.installTemplate("templates/fields/message_banner");
|
||||
@@ -62,215 +62,230 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
|
||||
);
|
||||
};
|
||||
|
||||
it("can upload profile image", function() {
|
||||
|
||||
var imageView = createImageView(true, false);
|
||||
imageView.render();
|
||||
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
|
||||
var imageName = 'profile_image.jpg';
|
||||
|
||||
// Initialize jquery file uploader
|
||||
imageView.$('.upload-button-input').fileupload({
|
||||
var initializeUploader = function (view) {
|
||||
view.$('.upload-button-input').fileupload({
|
||||
url: Helpers.IMAGE_UPLOAD_API_URL,
|
||||
type: 'POST',
|
||||
add: imageView.fileSelected,
|
||||
done: imageView.imageChangeSucceeded,
|
||||
fail: imageView.imageChangeFailed
|
||||
add: view.fileSelected,
|
||||
done: view.imageChangeSucceeded,
|
||||
fail: view.imageChangeFailed
|
||||
});
|
||||
};
|
||||
|
||||
describe("ProfileImageFieldView", function () {
|
||||
|
||||
var verifyImageUploadButtonMessage = function (view, inProgress) {
|
||||
var iconName = inProgress ? 'fa-spinner' : 'fa-camera';
|
||||
var message = inProgress ? view.titleUploading : view.uploadButtonTitle();
|
||||
expect(view.$('.upload-button-icon i').attr('class')).toContain(iconName);
|
||||
expect(view.$('.upload-button-title').text().trim()).toBe(message);
|
||||
};
|
||||
|
||||
var verifyImageRemoveButtonMessage = function (view, inProgress) {
|
||||
var iconName = inProgress ? 'fa-spinner' : 'fa-remove';
|
||||
var message = inProgress ? view.titleRemoving : view.removeButtonTitle();
|
||||
expect(view.$('.remove-button-icon i').attr('class')).toContain(iconName);
|
||||
expect(view.$('.remove-button-title').text().trim()).toBe(message);
|
||||
};
|
||||
|
||||
it("can upload profile image", function() {
|
||||
|
||||
var imageView = createImageView({ownProfile: true, hasImage: false});
|
||||
imageView.render();
|
||||
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
var imageName = 'profile_image.jpg';
|
||||
|
||||
initializeUploader(imageView);
|
||||
|
||||
// Remove button should not be present for default image
|
||||
expect(imageView.$('.u-field-remove-button').css('display') === 'none').toBeTruthy();
|
||||
|
||||
// For default image, image title should be `Upload an image`
|
||||
verifyImageUploadButtonMessage(imageView, false);
|
||||
|
||||
// Add image to upload queue. Validate the image size and send POST request to upload image
|
||||
imageView.$('.upload-button-input').fileupload('add', {files: [createFakeImageFile(60)]});
|
||||
|
||||
// Verify image upload progress message
|
||||
verifyImageUploadButtonMessage(imageView, true);
|
||||
|
||||
// Verify if POST request received for image upload
|
||||
AjaxHelpers.expectRequest(requests, 'POST', Helpers.IMAGE_UPLOAD_API_URL, new FormData());
|
||||
|
||||
// Send 204 NO CONTENT to confirm the image upload success
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
|
||||
// Upon successful image upload, account settings model will be fetched to
|
||||
// get the url for newly uploaded image, So we need to send the response for that GET
|
||||
var data = {profile_image: {
|
||||
image_url_large: '/media/profile-images/' + imageName,
|
||||
has_image: true
|
||||
}};
|
||||
AjaxHelpers.respondWithJson(requests, data);
|
||||
|
||||
// Verify uploaded image name
|
||||
expect(imageView.$('.image-frame').attr('src')).toContain(imageName);
|
||||
|
||||
// Remove button should be present after successful image upload
|
||||
expect(imageView.$('.u-field-remove-button').css('display') !== 'none').toBeTruthy();
|
||||
|
||||
// After image upload, image title should be `Change image`
|
||||
verifyImageUploadButtonMessage(imageView, false);
|
||||
});
|
||||
|
||||
// Remove button should not be present for default image
|
||||
expect(imageView.$('.u-field-remove-button').css('display') === 'none').toBeTruthy();
|
||||
it("can remove profile image", function() {
|
||||
|
||||
// For default image, image title should be `Upload an image`
|
||||
expect(imageView.$('.upload-button-title').text().trim()).toBe(imageView.titleAdd);
|
||||
var imageView = createImageView({ownProfile: true, hasImage: false});
|
||||
imageView.render();
|
||||
|
||||
// Add image to upload queue, this will validate the image size and send POST request to upload image
|
||||
imageView.$('.upload-button-input').fileupload('add', {files: [createFakeImageFile(60)]});
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
|
||||
// Verify image upload progress message
|
||||
expect(imageView.$('.upload-button-title').text().trim()).toBe(imageView.titleUploading);
|
||||
// Verify image remove title
|
||||
verifyImageRemoveButtonMessage(imageView, false);
|
||||
|
||||
// Verify if POST request received for image upload
|
||||
AjaxHelpers.expectRequest(requests, 'POST', Helpers.IMAGE_UPLOAD_API_URL, new FormData());
|
||||
imageView.$('.u-field-remove-button').click();
|
||||
|
||||
// Send 204 NO CONTENT to confirm the image upload success
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
// Verify image remove progress message
|
||||
verifyImageRemoveButtonMessage(imageView, true);
|
||||
|
||||
// Upon successful image upload, account settings model will be fetched to get the url for newly uploaded image
|
||||
// So we need to send the response for that GET
|
||||
var data = {profile_image: {
|
||||
image_url_large: '/media/profile-images/' + imageName,
|
||||
has_image: true
|
||||
}};
|
||||
AjaxHelpers.respondWithJson(requests, data);
|
||||
// Verify if POST request received for image remove
|
||||
AjaxHelpers.expectRequest(requests, 'POST', Helpers.IMAGE_REMOVE_API_URL, null);
|
||||
|
||||
// Verify uploaded image name
|
||||
expect(imageView.$('.image-frame').attr('src')).toContain(imageName);
|
||||
// Send 204 NO CONTENT to confirm the image removal success
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
|
||||
// Remove button should be present after successful image upload
|
||||
expect(imageView.$('.u-field-remove-button').css('display') !== 'none').toBeTruthy();
|
||||
// Upon successful image removal, account settings model will be fetched to get default image url
|
||||
// So we need to send the response for that GET
|
||||
var data = {profile_image: {
|
||||
image_url_large: '/media/profile-images/default.jpg',
|
||||
has_image: false
|
||||
}};
|
||||
AjaxHelpers.respondWithJson(requests, data);
|
||||
|
||||
// After image upload, image title should be `Change image`
|
||||
expect(imageView.$('.upload-button-title').text().trim()).toBe(imageView.titleEdit);
|
||||
});
|
||||
|
||||
it("can remove profile image", function() {
|
||||
var imageView = createImageView(true, true);
|
||||
imageView.render();
|
||||
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
|
||||
imageView.$('.u-field-remove-button').click();
|
||||
|
||||
// Verify image remove progress message
|
||||
expect(imageView.$('.remove-button-title').text().trim()).toBe(imageView.titleRemoving);
|
||||
|
||||
// Verify if POST request received for image remove
|
||||
AjaxHelpers.expectRequest(requests, 'POST', Helpers.IMAGE_REMOVE_API_URL, null);
|
||||
|
||||
// Send 204 NO CONTENT to confirm the image removal success
|
||||
AjaxHelpers.respondWithNoContent(requests);
|
||||
|
||||
// Upon successful image removal, account settings model will be fetched to get the default image url
|
||||
// So we need to send the response for that GET
|
||||
var data = {profile_image: {
|
||||
image_url_large: '/media/profile-images/default.jpg',
|
||||
has_image: false
|
||||
}};
|
||||
AjaxHelpers.respondWithJson(requests, data);
|
||||
|
||||
// Remove button should not be present for default image
|
||||
expect(imageView.$('.u-field-remove-button').css('display') === 'none').toBeTruthy();
|
||||
});
|
||||
|
||||
it("can't remove default profile image", function() {
|
||||
var imageView = createImageView(true, false);
|
||||
imageView.render();
|
||||
|
||||
spyOn(imageView, 'clickedRemoveButton');
|
||||
|
||||
// Remove button should not be present for default image
|
||||
expect(imageView.$('.u-field-remove-button').css('display') === 'none').toBeTruthy();
|
||||
|
||||
imageView.$('.u-field-remove-button').click();
|
||||
|
||||
// Remove button click handler should not be called
|
||||
expect(imageView.clickedRemoveButton).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("can't upload image having size greater than max size", function() {
|
||||
var imageView = createImageView(true, false);
|
||||
imageView.render();
|
||||
|
||||
// Initialize jquery file uploader
|
||||
imageView.$('.upload-button-input').fileupload({
|
||||
url: Helpers.IMAGE_UPLOAD_API_URL,
|
||||
type: 'POST',
|
||||
add: imageView.fileSelected,
|
||||
done: imageView.imageChangeSucceeded,
|
||||
fail: imageView.imageChangeFailed
|
||||
// Remove button should not be present for default image
|
||||
expect(imageView.$('.u-field-remove-button').css('display') === 'none').toBeTruthy();
|
||||
});
|
||||
|
||||
// Add image to upload queue, this will validate the image size
|
||||
imageView.$('.upload-button-input').fileupload('add', {files: [createFakeImageFile(70)]});
|
||||
it("can't remove default profile image", function() {
|
||||
|
||||
// Verify error message
|
||||
expect($('.message-banner').text().trim()).toBe('Your image must be smaller than 64 Bytes in size.');
|
||||
});
|
||||
var imageView = createImageView({ownProfile: true, hasImage: false});
|
||||
imageView.render();
|
||||
|
||||
it("can't upload image having size less than min size", function() {
|
||||
var imageView = createImageView(true, false);
|
||||
imageView.render();
|
||||
spyOn(imageView, 'clickedRemoveButton');
|
||||
|
||||
// Initialize jquery file uploader
|
||||
imageView.$('.upload-button-input').fileupload({
|
||||
url: Helpers.IMAGE_UPLOAD_API_URL,
|
||||
type: 'POST',
|
||||
add: imageView.fileSelected,
|
||||
done: imageView.imageChangeSucceeded,
|
||||
fail: imageView.imageChangeFailed
|
||||
// Remove button should not be present for default image
|
||||
expect(imageView.$('.u-field-remove-button').css('display') === 'none').toBeTruthy();
|
||||
|
||||
imageView.$('.u-field-remove-button').click();
|
||||
|
||||
// Remove button click handler should not be called
|
||||
expect(imageView.clickedRemoveButton).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// Add image to upload queue, this will validate the image size
|
||||
imageView.$('.upload-button-input').fileupload('add', {files: [createFakeImageFile(10)]});
|
||||
it("can't upload image having size greater than max size", function() {
|
||||
|
||||
// Verify error message
|
||||
expect($('.message-banner').text().trim()).toBe('Your image must be at least 16 Bytes in size.');
|
||||
});
|
||||
var imageView = createImageView({ownProfile: true, hasImage: false});
|
||||
imageView.render();
|
||||
|
||||
it("can't upload/remove image if parental consent required", function() {
|
||||
var imageView = createImageView(true, false, 64, 16, '');
|
||||
imageView.render();
|
||||
initializeUploader(imageView);
|
||||
|
||||
spyOn(imageView, 'clickedUploadButton');
|
||||
spyOn(imageView, 'clickedRemoveButton');
|
||||
// Add image to upload queue, this will validate the image size
|
||||
imageView.$('.upload-button-input').fileupload('add', {files: [createFakeImageFile(70)]});
|
||||
|
||||
expect(imageView.$('.u-field-upload-button').css('display') === 'none').toBeTruthy();
|
||||
expect(imageView.$('.u-field-remove-button').css('display') === 'none').toBeTruthy();
|
||||
|
||||
imageView.$('.u-field-upload-button').click();
|
||||
imageView.$('.u-field-remove-button').click();
|
||||
|
||||
expect(imageView.clickedUploadButton).not.toHaveBeenCalled();
|
||||
expect(imageView.clickedRemoveButton).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("can't upload image on others profile", function() {
|
||||
var imageView = createImageView(false);
|
||||
imageView.render();
|
||||
|
||||
spyOn(imageView, 'clickedUploadButton');
|
||||
spyOn(imageView, 'clickedRemoveButton');
|
||||
|
||||
expect(imageView.$('.u-field-upload-button').css('display') === 'none').toBeTruthy();
|
||||
expect(imageView.$('.u-field-remove-button').css('display') === 'none').toBeTruthy();
|
||||
|
||||
imageView.$('.u-field-upload-button').click();
|
||||
imageView.$('.u-field-remove-button').click();
|
||||
|
||||
expect(imageView.clickedUploadButton).not.toHaveBeenCalled();
|
||||
expect(imageView.clickedRemoveButton).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows message if we try to navigate away during image upload/remove", function() {
|
||||
var imageView = createImageView(true, false);
|
||||
spyOn(imageView, 'onBeforeUnload');
|
||||
imageView.render();
|
||||
|
||||
// Initialize jquery file uploader
|
||||
imageView.$('.upload-button-input').fileupload({
|
||||
url: Helpers.IMAGE_UPLOAD_API_URL,
|
||||
type: 'POST',
|
||||
add: imageView.fileSelected,
|
||||
done: imageView.imageChangeSucceeded,
|
||||
fail: imageView.imageChangeFailed
|
||||
// Verify error message
|
||||
expect($('.message-banner').text().trim())
|
||||
.toBe('Your image must be smaller than 64 bytes in size.');
|
||||
});
|
||||
|
||||
// Add image to upload queue, this will validate the image size and send POST request to upload image
|
||||
imageView.$('.upload-button-input').fileupload('add', {files: [createFakeImageFile(60)]});
|
||||
it("can't upload image having size less than min size", function() {
|
||||
var imageView = createImageView({ownProfile: true, hasImage: false});
|
||||
imageView.render();
|
||||
|
||||
// Verify image upload progress message
|
||||
expect(imageView.$('.upload-button-title').text().trim()).toBe(imageView.titleUploading);
|
||||
initializeUploader(imageView);
|
||||
|
||||
$(window).trigger('beforeunload');
|
||||
// Add image to upload queue, this will validate the image size
|
||||
imageView.$('.upload-button-input').fileupload('add', {files: [createFakeImageFile(10)]});
|
||||
|
||||
expect(imageView.onBeforeUnload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('renders message correctly', function() {
|
||||
var messageSelector = '.message-banner';
|
||||
var messageView = new MessageBannerView({
|
||||
el: $(messageSelector)
|
||||
// Verify error message
|
||||
expect($('.message-banner').text().trim()).toBe('Your image must be at least 16 bytes in size.');
|
||||
});
|
||||
|
||||
messageView.showMessage('I am message view');
|
||||
// Verify error message
|
||||
expect($(messageSelector).text().trim()).toBe('I am message view');
|
||||
it("can't upload and remove image if parental consent required", function() {
|
||||
|
||||
messageView.hideMessage();
|
||||
expect($(messageSelector).text().trim()).toBe('');
|
||||
var imageView = createImageView({ownProfile: true, hasImage: false, yearOfBirth: ''});
|
||||
imageView.render();
|
||||
|
||||
spyOn(imageView, 'clickedUploadButton');
|
||||
spyOn(imageView, 'clickedRemoveButton');
|
||||
|
||||
expect(imageView.$('.u-field-upload-button').css('display') === 'none').toBeTruthy();
|
||||
expect(imageView.$('.u-field-remove-button').css('display') === 'none').toBeTruthy();
|
||||
|
||||
imageView.$('.u-field-upload-button').click();
|
||||
imageView.$('.u-field-remove-button').click();
|
||||
|
||||
expect(imageView.clickedUploadButton).not.toHaveBeenCalled();
|
||||
expect(imageView.clickedRemoveButton).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("can't upload and remove image on others profile", function() {
|
||||
|
||||
var imageView = createImageView({ownProfile: false});
|
||||
imageView.render();
|
||||
|
||||
spyOn(imageView, 'clickedUploadButton');
|
||||
spyOn(imageView, 'clickedRemoveButton');
|
||||
|
||||
expect(imageView.$('.u-field-upload-button').css('display') === 'none').toBeTruthy();
|
||||
expect(imageView.$('.u-field-remove-button').css('display') === 'none').toBeTruthy();
|
||||
|
||||
imageView.$('.u-field-upload-button').click();
|
||||
imageView.$('.u-field-remove-button').click();
|
||||
|
||||
expect(imageView.clickedUploadButton).not.toHaveBeenCalled();
|
||||
expect(imageView.clickedRemoveButton).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows message if we try to navigate away during image upload/remove", function() {
|
||||
var imageView = createImageView({ownProfile: true, hasImage: false});
|
||||
spyOn(imageView, 'onBeforeUnload');
|
||||
imageView.render();
|
||||
|
||||
initializeUploader(imageView);
|
||||
|
||||
// Add image to upload queue, this will validate image size and send POST request to upload image
|
||||
imageView.$('.upload-button-input').fileupload('add', {files: [createFakeImageFile(60)]});
|
||||
|
||||
// Verify image upload progress message
|
||||
verifyImageUploadButtonMessage(imageView, true);
|
||||
|
||||
$(window).trigger('beforeunload');
|
||||
expect(imageView.onBeforeUnload).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows error message for HTTP 500", function() {
|
||||
var imageView = createImageView({ownProfile: true, hasImage: false});
|
||||
imageView.render();
|
||||
|
||||
var requests = AjaxHelpers.requests(this);
|
||||
|
||||
initializeUploader(imageView);
|
||||
|
||||
// Add image to upload queue. Validate the image size and send POST request to upload image
|
||||
imageView.$('.upload-button-input').fileupload('add', {files: [createFakeImageFile(60)]});
|
||||
|
||||
// Verify image upload progress message
|
||||
verifyImageUploadButtonMessage(imageView, true);
|
||||
|
||||
// Verify if POST request received for image upload
|
||||
AjaxHelpers.expectRequest(requests, 'POST', Helpers.IMAGE_UPLOAD_API_URL, new FormData());
|
||||
|
||||
// Send HTTP 500
|
||||
AjaxHelpers.respondWithError(requests);
|
||||
|
||||
expect($('.message-banner').text().trim()).toBe(imageView.errorMessage);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -124,7 +124,7 @@ define(['backbone', 'jquery', 'underscore', 'js/common_helpers/ajax_helpers', 'j
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures('<div class="message-banner"></div><div class="wrapper-profile"><div class="ui-loading-indicator"><p><span class="spin"><i class="icon fa fa-refresh"></i></span> <span class="copy">Loading</span></p></div><div class="ui-loading-error is-hidden"><i class="fa fa-exclamation-triangle message-error" aria-hidden=true></i><span class="copy">An error occurred. Please reload the page.</span></div></div>');
|
||||
loadFixtures('js/fixtures/student_profile/student_profile.html');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_readonly');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_dropdown');
|
||||
TemplateHelpers.installTemplate('templates/fields/field_textarea');
|
||||
|
||||
27
lms/static/js/spec/views/message_banner_spec.js
Normal file
27
lms/static/js/spec/views/message_banner_spec.js
Normal file
@@ -0,0 +1,27 @@
|
||||
define(['backbone', 'jquery', 'underscore', 'js/views/message_banner'
|
||||
],
|
||||
function (Backbone, $, _, MessageBannerView) {
|
||||
'use strict';
|
||||
|
||||
describe("MessageBannerView", function () {
|
||||
|
||||
beforeEach(function () {
|
||||
setFixtures('<div class="message-banner"></div>');
|
||||
TemplateHelpers.installTemplate("templates/fields/message_banner");
|
||||
});
|
||||
|
||||
it('renders message correctly', function() {
|
||||
var messageSelector = '.message-banner';
|
||||
var messageView = new MessageBannerView({
|
||||
el: $(messageSelector)
|
||||
});
|
||||
|
||||
messageView.showMessage('I am message view');
|
||||
// Verify error message
|
||||
expect($(messageSelector).text().trim()).toBe('I am message view');
|
||||
|
||||
messageView.hideMessage();
|
||||
expect($(messageSelector).text().trim()).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -9,7 +9,7 @@
|
||||
'js/student_profile/views/learner_profile_view',
|
||||
'js/student_account/views/account_settings_fields',
|
||||
'js/views/message_banner'
|
||||
], function (gettext, $, _, Backbone, AccountSettingsModel, AccountPreferencesModel, FieldsView,
|
||||
], function (gettext, $, _, Backbone, Logger, AccountSettingsModel, AccountPreferencesModel, FieldsView,
|
||||
LearnerProfileFieldsView, LearnerProfileView, AccountSettingsFieldViews, MessageBannerView) {
|
||||
|
||||
return function (options) {
|
||||
|
||||
@@ -48,21 +48,15 @@
|
||||
this.$('.profile-section-one-fields').append(this.options.usernameFieldView.render().el);
|
||||
|
||||
var imageView = this.options.profileImageFieldView;
|
||||
imageView.undelegateEvents();
|
||||
this.$('.profile-image-field').append(imageView.render().el);
|
||||
imageView.delegateEvents();
|
||||
|
||||
if (this.showFullProfile()) {
|
||||
_.each(this.options.sectionOneFieldViews, function (fieldView) {
|
||||
fieldView.undelegateEvents();
|
||||
view.$('.profile-section-one-fields').append(fieldView.render().el);
|
||||
fieldView.delegateEvents();
|
||||
});
|
||||
|
||||
_.each(this.options.sectionTwoFieldViews, function (fieldView) {
|
||||
fieldView.undelegateEvents();
|
||||
view.$('.profile-section-two-fields').append(fieldView.render().el);
|
||||
fieldView.delegateEvents();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -225,6 +225,7 @@
|
||||
value: this.modelValue(),
|
||||
message: this.helpMessage
|
||||
}));
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
},
|
||||
|
||||
@@ -260,6 +261,7 @@
|
||||
value: this.modelValue(),
|
||||
message: this.helpMessage
|
||||
}));
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
},
|
||||
|
||||
@@ -308,7 +310,7 @@
|
||||
selectOptions: this.options.options,
|
||||
message: this.helpMessage
|
||||
}));
|
||||
|
||||
this.delegateEvents();
|
||||
this.updateValueInField();
|
||||
|
||||
if (this.editable === 'toggle') {
|
||||
@@ -415,7 +417,7 @@
|
||||
value: value,
|
||||
message: this.helpMessage
|
||||
}));
|
||||
|
||||
this.delegateEvents();
|
||||
this.title((this.modelValue() || this.mode === 'edit') ? this.options.title : this.indicators['plus'] + this.options.title);
|
||||
|
||||
if (this.editable === 'toggle') {
|
||||
@@ -491,6 +493,7 @@
|
||||
linkHref: this.options.linkHref,
|
||||
message: this.helpMessage
|
||||
}));
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
},
|
||||
|
||||
@@ -523,7 +526,8 @@
|
||||
|
||||
events: {
|
||||
'click .u-field-upload-button': 'clickedUploadButton',
|
||||
'click .u-field-remove-button': 'clickedRemoveButton'
|
||||
'click .u-field-remove-button': 'clickedRemoveButton',
|
||||
'click .upload-submit': 'clickedUploadButton'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
@@ -543,6 +547,7 @@
|
||||
removeButtonIcon: _.result(this, 'iconRemove'),
|
||||
removeButtonTitle: _.result(this, 'removeButtonTitle')
|
||||
}));
|
||||
this.delegateEvents();
|
||||
this.updateButtonsVisibility();
|
||||
this.watchForPageUnload();
|
||||
return this;
|
||||
@@ -558,9 +563,9 @@
|
||||
|
||||
uploadButtonTitle: function () {
|
||||
if (this.isShowingPlaceholder()) {
|
||||
return _.result(this, 'titleAdd')
|
||||
return _.result(this, 'titleAdd');
|
||||
} else {
|
||||
return _.result(this, 'titleEdit')
|
||||
return _.result(this, 'titleEdit');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -569,7 +574,7 @@
|
||||
},
|
||||
|
||||
isEditingAllowed: function () {
|
||||
return true
|
||||
return true;
|
||||
},
|
||||
|
||||
isShowingPlaceholder: function () {
|
||||
@@ -594,7 +599,7 @@
|
||||
}
|
||||
},
|
||||
|
||||
clickedUploadButton: function (e, data) {
|
||||
clickedUploadButton: function () {
|
||||
$(this.uploadButtonSelector).fileupload({
|
||||
url: this.options.imageUploadUrl,
|
||||
type: 'POST',
|
||||
@@ -604,24 +609,22 @@
|
||||
});
|
||||
},
|
||||
|
||||
clickedRemoveButton: function (e, data) {
|
||||
clickedRemoveButton: function () {
|
||||
var view = this;
|
||||
this.setCurrentStatus('removing');
|
||||
this.setUploadButtonVisibility('none');
|
||||
this.showRemovalInProgressMessage();
|
||||
$.ajax({
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: this.options.imageRemoveUrl,
|
||||
success: function (data, status, xhr) {
|
||||
view.imageChangeSucceeded();
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
view.showImageChangeFailedMessage(xhr.status, xhr.responseText);
|
||||
}
|
||||
url: this.options.imageRemoveUrl
|
||||
}).done(function () {
|
||||
view.imageChangeSucceeded();
|
||||
}).fail(function (jqXHR) {
|
||||
view.showImageChangeFailedMessage(jqXHR.status, jqXHR.responseText);
|
||||
});
|
||||
},
|
||||
|
||||
imageChangeSucceeded: function (e, data) {
|
||||
imageChangeSucceeded: function () {
|
||||
this.render();
|
||||
},
|
||||
|
||||
@@ -645,11 +648,19 @@
|
||||
var humanReadableSize;
|
||||
if (imageBytes < this.options.imageMinBytes) {
|
||||
humanReadableSize = this.bytesToHumanReadable(this.options.imageMinBytes);
|
||||
this.showErrorMessage(interpolate_text(gettext("Your image must be at least {size} in size."), {size: humanReadableSize}));
|
||||
this.showErrorMessage(
|
||||
interpolate_text(
|
||||
gettext("Your image must be at least {size} in size."), {size: humanReadableSize}
|
||||
)
|
||||
);
|
||||
return false;
|
||||
} else if (imageBytes > this.options.imageMaxBytes) {
|
||||
humanReadableSize = this.bytesToHumanReadable(this.options.imageMaxBytes);
|
||||
this.showErrorMessage(interpolate_text(gettext("Your image must be smaller than {size} in size."), {size: humanReadableSize}));
|
||||
this.showErrorMessage(
|
||||
interpolate_text(
|
||||
gettext("Your image must be smaller than {size} in size."), {size: humanReadableSize}
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -675,27 +686,25 @@
|
||||
return this.$('.image-wrapper').attr('data-status');
|
||||
},
|
||||
|
||||
inProgress: function() {
|
||||
var status = this.getCurrentStatus();
|
||||
return _.isUndefined(status) ? false : true;
|
||||
},
|
||||
|
||||
watchForPageUnload: function () {
|
||||
$(window).on('beforeunload', this.onBeforeUnload);
|
||||
},
|
||||
|
||||
onBeforeUnload: function () {
|
||||
console.log('Do you really want to go away?');
|
||||
var status = this.getCurrentStatus();
|
||||
if (status === 'uploading') {
|
||||
return gettext("Upload is in progress. To avoid errors, stay on this page until the process is complete.");
|
||||
return gettext(
|
||||
"Upload is in progress. To avoid errors, stay on this page until the process is complete."
|
||||
);
|
||||
} else if (status === 'removing') {
|
||||
return gettext("Removal is in progress. To avoid errors, stay on this page until the process is complete.");
|
||||
return gettext(
|
||||
"Removal is in progress. To avoid errors, stay on this page until the process is complete."
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
bytesToHumanReadable: function (size) {
|
||||
var units = ['Bytes', 'KB', 'MB'];
|
||||
var units = ['bytes', 'KB', 'MB'];
|
||||
var i = 0;
|
||||
while(size >= 1024) {
|
||||
size /= 1024;
|
||||
|
||||
@@ -6,14 +6,18 @@
|
||||
|
||||
var MessageBannerView = Backbone.View.extend({
|
||||
|
||||
initialize: function (options) {
|
||||
initialize: function () {
|
||||
this.template = _.template($('#message_banner-tpl').text());
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.html(this.template({
|
||||
message: this.message
|
||||
}));
|
||||
if (_.isUndefined(this.message) || _.isNull(this.message)) {
|
||||
this.$el.html('');
|
||||
} else {
|
||||
this.$el.html(this.template({
|
||||
message: this.message
|
||||
}));
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
@@ -23,10 +27,11 @@
|
||||
},
|
||||
|
||||
hideMessage: function () {
|
||||
this.$el.html('');
|
||||
this.message = null;
|
||||
this.render();
|
||||
}
|
||||
});
|
||||
|
||||
return MessageBannerView;
|
||||
})
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
padding: 0;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.u-field-image {
|
||||
@@ -43,16 +42,18 @@
|
||||
|
||||
.image-frame {
|
||||
position: relative;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
width: $profile-image-dimension;
|
||||
height: $profile-image-dimension;
|
||||
border-radius: ($baseline/4);
|
||||
}
|
||||
|
||||
.u-field-upload-button {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
width: $profile-image-dimension;
|
||||
height: $profile-image-dimension;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
@include transition(all $tmg-f1 ease-in-out 0s);
|
||||
|
||||
i {
|
||||
color: $white;
|
||||
@@ -61,13 +62,15 @@
|
||||
|
||||
.upload-button-icon, .upload-button-title {
|
||||
text-align: center;
|
||||
transform: translateY(45px);
|
||||
transform: translateY(35px);
|
||||
display: block;
|
||||
color: $white;
|
||||
margin-bottom: ($baseline/4);
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
.upload-button-input {
|
||||
width: 120px;
|
||||
width: $profile-image-dimension;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -77,17 +80,24 @@
|
||||
}
|
||||
|
||||
.u-field-remove-button {
|
||||
width: 120px;
|
||||
height: 20px;
|
||||
width: $profile-image-dimension;
|
||||
height: $baseline;
|
||||
opacity: 0;
|
||||
position: relative;
|
||||
margin-top: 2px;
|
||||
text-align: center;
|
||||
|
||||
&:focus, &:active {
|
||||
box-shadow: none;
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.u-field-upload-button, .u-field-remove-button {
|
||||
opacity: 1;
|
||||
background-color: $shadow-d2;
|
||||
border-radius: ($baseline/4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
<span class="upload-button-title" aria-live="polite"><%= uploadButtonTitle %></span>
|
||||
<input class="upload-button-input" type="file" name="<%= id %>"/>
|
||||
</label>
|
||||
<button class="upload-submit" type="button" hidden="true"><%= uploadButtonTitle %></button>
|
||||
|
||||
<button class="u-field-remove-button" type="button">
|
||||
<span class="remove-button-icon" aria-hidden="true"><%= removeButtonIcon %></span>
|
||||
<span class="remove-button-title" aria-live="polite"><%= removeButtonTitle %></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user