manage focus when deleting a link from profile
also do some minor refactoring around this coffeescript to make it safer and easier to test. fixes CNVS-26490 test plan: - basic regression test around user profile editing (you need to enable profiles in account settings) - specifically, when you delete links while editing the profile, focus should go to the previous delete link button or the bio textarea (if you delete the top one) Change-Id: I15b5e552485c447d51cdccedf9990456de10b13d Reviewed-on: https://gerrit.instructure.com/71298 Tested-by: Jenkins Reviewed-by: Ryan Shaw <ryan@instructure.com> QA-Review: Jeremy Putnam <jeremyp@instructure.com> Product-Review: Simon Williams <simon@instructure.com>
This commit is contained in:
parent
22d80f8698
commit
772cffbae6
|
@ -17,103 +17,7 @@
|
|||
#
|
||||
|
||||
require [
|
||||
'i18n!user_profile',
|
||||
'Backbone'
|
||||
'jquery'
|
||||
'str/htmlEscape'
|
||||
'compiled/util/AvatarWidget'
|
||||
'compiled/tinymce'
|
||||
'jquery.instructure_forms'
|
||||
'tinymce.editor_box'
|
||||
], (I18n, {View}, $, htmlEscape, AvatarWidget) ->
|
||||
|
||||
class ProfileShow extends View
|
||||
|
||||
el: document.body
|
||||
|
||||
events:
|
||||
'click [data-event]': 'handleDeclarativeClick'
|
||||
'submit #edit_profile_form': 'validateForm'
|
||||
'click .report_avatar_link': 'reportAvatarLink'
|
||||
|
||||
attemptedDependencyLoads: 0
|
||||
|
||||
initialize: ->
|
||||
super
|
||||
new AvatarWidget('.profile-link')
|
||||
|
||||
reportAvatarLink: (e) ->
|
||||
e.preventDefault()
|
||||
return if !confirm(I18n.t("Are you sure you want to report this profile picture?"))
|
||||
link = $(e.currentTarget)
|
||||
$('.avatar').hide()
|
||||
$.ajaxJSON(link.attr('href'), "POST", {}, (data) =>
|
||||
$.flashMessage I18n.t("The profile picture has been reported")
|
||||
)
|
||||
|
||||
handleDeclarativeClick: (event) ->
|
||||
event.preventDefault()
|
||||
$target = $ event.currentTarget
|
||||
method = $target.data 'event'
|
||||
@[method]? event, $target
|
||||
|
||||
##
|
||||
# first run initializes some stuff, then is reassigned
|
||||
# to a showEditForm
|
||||
editProfile: ->
|
||||
@initEdit()
|
||||
@editProfile = @showEditForm
|
||||
|
||||
showEditForm: ->
|
||||
@$el.addClass('editing').removeClass('not-editing')
|
||||
@$('.profile_links').removeClass('span6')
|
||||
|
||||
initEdit: ->
|
||||
if @options.links?.length
|
||||
@addLinkField(null, null, title, url) for {title, url} in @options.links
|
||||
else
|
||||
@addLinkField()
|
||||
@addLinkField()
|
||||
|
||||
# setTimeout so tiny has some width to read
|
||||
#setTimeout -> @$('#profile_bio').editorBox()
|
||||
@showEditForm()
|
||||
|
||||
cancelEditProfile: ->
|
||||
@$el.addClass('not-editing').removeClass('editing')
|
||||
@$('.profile_links').addClass('span6')
|
||||
|
||||
##
|
||||
# Event handler that can also be called manually.
|
||||
# When called manually, it will focus the first input in the new row
|
||||
addLinkField: (event, $el, title = '', url = '') ->
|
||||
@$linkFields ?= @$ '#profile_link_fields'
|
||||
$row = $ """
|
||||
<tr>
|
||||
<td><input aria-label="#{htmlEscape I18n.t("Link title")}" type="text" maxlength="255" name="link_titles[]" value="#{htmlEscape title}"></td>
|
||||
<td>→</td>
|
||||
<td><input aria-label="#{htmlEscape I18n.t("Link Url")}" type="text" name="link_urls[]" value="#{htmlEscape url}"></td>
|
||||
<td><a href="#" data-event="removeLinkRow"><span class="screenreader-only">#{htmlEscape I18n.t("Remove")}</span><i class="icon-end"></i></a></td>
|
||||
</tr>
|
||||
"""
|
||||
@$linkFields.append $row
|
||||
|
||||
# focus if called from the "add row" button
|
||||
if event?
|
||||
event.preventDefault()
|
||||
$row.find('input:first').focus()
|
||||
|
||||
removeLinkRow: (event, $el) ->
|
||||
$el.parents('tr').remove()
|
||||
|
||||
validateForm: (event) ->
|
||||
validations =
|
||||
property_validations:
|
||||
'user_profile[title]': (value) ->
|
||||
if value && value.length > 255
|
||||
return I18n.t("profile_title_too_long", "Title is too long")
|
||||
if !$(event.target).validateForm(validations)
|
||||
event.preventDefault()
|
||||
'compiled/views/profiles/ProfileShow'
|
||||
], (ProfileShow) ->
|
||||
|
||||
new ProfileShow ENV.PROFILE
|
||||
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
#
|
||||
# Copyright (C) 2016 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
define [
|
||||
'i18n!user_profile',
|
||||
'Backbone'
|
||||
'jquery'
|
||||
'jst/profiles/addLinkRow'
|
||||
'compiled/util/AvatarWidget'
|
||||
'compiled/tinymce'
|
||||
'jquery.instructure_forms'
|
||||
'tinymce.editor_box'
|
||||
], (I18n, Backbone, $, addLinkRow, AvatarWidget) ->
|
||||
|
||||
class ProfileShow extends Backbone.View
|
||||
|
||||
el: document.body
|
||||
|
||||
events:
|
||||
'click [data-event]': 'handleDeclarativeClick'
|
||||
'submit #edit_profile_form': 'validateForm'
|
||||
'click .report_avatar_link': 'reportAvatarLink'
|
||||
|
||||
attemptedDependencyLoads: 0
|
||||
|
||||
initialize: ->
|
||||
super
|
||||
new AvatarWidget('.profile-link')
|
||||
|
||||
reportAvatarLink: (e) ->
|
||||
e.preventDefault()
|
||||
return if !confirm(I18n.t("Are you sure you want to report this profile picture?"))
|
||||
link = $(e.currentTarget)
|
||||
$('.avatar').hide()
|
||||
$.ajaxJSON(link.attr('href'), "POST", {}, (data) =>
|
||||
$.flashMessage I18n.t("The profile picture has been reported")
|
||||
)
|
||||
|
||||
handleDeclarativeClick: (event) ->
|
||||
event.preventDefault()
|
||||
$target = $ event.currentTarget
|
||||
method = $target.data 'event'
|
||||
@[method]? event, $target
|
||||
|
||||
##
|
||||
# first run initializes some stuff, then is reassigned
|
||||
# to a showEditForm
|
||||
editProfile: ->
|
||||
@initEdit()
|
||||
@editProfile = @showEditForm
|
||||
|
||||
showEditForm: ->
|
||||
@$el.addClass('editing').removeClass('not-editing')
|
||||
@$('.profile_links').removeClass('span6')
|
||||
|
||||
initEdit: ->
|
||||
if @options.links?.length
|
||||
@addLinkField(null, null, title, url) for {title, url} in @options.links
|
||||
else
|
||||
@addLinkField()
|
||||
@addLinkField()
|
||||
|
||||
# setTimeout so tiny has some width to read
|
||||
#setTimeout -> @$('#profile_bio').editorBox()
|
||||
@showEditForm()
|
||||
|
||||
cancelEditProfile: ->
|
||||
@$el.addClass('not-editing').removeClass('editing')
|
||||
@$('.profile_links').addClass('span6')
|
||||
|
||||
##
|
||||
# Event handler that can also be called manually.
|
||||
# When called manually, it will focus the first input in the new row
|
||||
addLinkField: (event, $el, title = '', url = '') ->
|
||||
@$linkFields ?= @$ '#profile_link_fields'
|
||||
$row = $(addLinkRow({title: title, url: url}))
|
||||
@$linkFields.append $row
|
||||
|
||||
# focus if called from the "add row" button
|
||||
if event?
|
||||
event.preventDefault()
|
||||
$row.find('input:first').focus()
|
||||
|
||||
removeLinkRow: (event, $el) ->
|
||||
$parentRow = $el.parents('tr')
|
||||
$toFocus = $parentRow.prev().find('.remove_link_row')
|
||||
if $toFocus.length == 0
|
||||
$toFocus = $('#profile_bio')
|
||||
|
||||
$parentRow.remove()
|
||||
$toFocus.focus()
|
||||
|
||||
validateForm: (event) ->
|
||||
validations =
|
||||
property_validations:
|
||||
'user_profile[title]': (value) ->
|
||||
if value && value.length > 255
|
||||
return I18n.t("profile_title_too_long", "Title is too long")
|
||||
if !$(event.target).validateForm(validations)
|
||||
event.preventDefault()
|
|
@ -0,0 +1,6 @@
|
|||
<tr>
|
||||
<td><input aria-label="{{t "Link title" }}" type="text" maxlength="255" name="link_titles[]" value="{{title}}"></td>
|
||||
<td>→</td>
|
||||
<td><input aria-label="{{t "Link Url" }}" type="text" name="link_urls[]" value="{{url}}"></td>
|
||||
<td><a href="#" class="remove_link_row" data-event="removeLinkRow"><span class="screenreader-only">{{t "Remove" }}</span><i class="icon-end"></i></a></td>
|
||||
</tr>
|
|
@ -151,4 +151,3 @@
|
|||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
define [
|
||||
'jquery'
|
||||
'compiled/views/profiles/ProfileShow'
|
||||
], ($, ProfileShow) ->
|
||||
|
||||
module 'ProfileShow',
|
||||
setup: ->
|
||||
@fixtures = document.getElementById('fixtures')
|
||||
@fixtures.innerHTML = "<div class='.profile-link'></div>"
|
||||
@fixtures.innerHTML += "<textarea id='profile_bio'></textarea>"
|
||||
@fixtures.innerHTML += "<table id='profile_link_fields'></table>"
|
||||
|
||||
teardown: ->
|
||||
@fixtures.innerHTML = ""
|
||||
|
||||
test 'manages focus on link removal', ->
|
||||
@view = new ProfileShow
|
||||
@view.addLinkField()
|
||||
$row1 = $('#profile_link_fields tr:last-child')
|
||||
@view.addLinkField()
|
||||
$row2 = $('#profile_link_fields tr:last-child')
|
||||
|
||||
@view.removeLinkRow(null, $row2.find('.remove_link_row'))
|
||||
equal document.activeElement, $row1.find('.remove_link_row')[0]
|
||||
@view.removeLinkRow(null, $row1.find('.remove_link_row'))
|
||||
equal document.activeElement, $('#profile_bio')[0]
|
Loading…
Reference in New Issue