Fix #1128: Lock focus in modals to improve accessibility

This commit is contained in:
Agate 2020-07-03 16:07:44 +02:00
parent c5755e21a5
commit 0094cbb7d1
11 changed files with 40 additions and 13 deletions

View File

@ -0,0 +1 @@
Use semantic headers for accessibility (#1121)

View File

@ -20,6 +20,7 @@
"core-js": "^3.6.4", "core-js": "^3.6.4",
"diff": "^4.0.1", "diff": "^4.0.1",
"django-channels": "^1.1.6", "django-channels": "^1.1.6",
"focus-trap": "^5.1.0",
"fomantic-ui-css": "^2.8.3", "fomantic-ui-css": "^2.8.3",
"howler": "^2.0.14", "howler": "^2.0.14",
"js-logger": "^1.4.1", "js-logger": "^1.4.1",

View File

@ -209,7 +209,7 @@ import $ from 'jquery'
import moment from "moment" import moment from "moment"
import lodash from '@/lodash' import lodash from '@/lodash'
import time from "@/utils/time" import time from "@/utils/time"
import createFocusTrap from 'focus-trap'
import store from "@/store" import store from "@/store"
export default { export default {
@ -224,11 +224,14 @@ export default {
showVolume: false, showVolume: false,
isShuffling: false, isShuffling: false,
tracksChangeBuffer: null, tracksChangeBuffer: null,
focusTrap: null,
time time
} }
}, },
mounted () { mounted () {
let self = this let self = this
this.focusTrap = createFocusTrap(this.$el, {allowOutsideClick: () => { return true }})
this.focusTrap.activate()
this.$nextTick(() => { this.$nextTick(() => {
setTimeout(() => { setTimeout(() => {
this.scrollToCurrent() this.scrollToCurrent()

View File

@ -35,7 +35,7 @@
</form> </form>
</div> </div>
<div class="actions"> <div class="actions">
<div class="ui basic cancel button"><translate translate-context="*/*/Button.Label/Verb">Cancel</translate></div> <button class="ui basic cancel button"><translate translate-context="*/*/Button.Label/Verb">Cancel</translate></button>
</div> </div>
</modal> </modal>
</template> </template>

View File

@ -36,7 +36,7 @@
</div> </div>
</section> </section>
<footer class="actions"> <footer class="actions">
<div class="ui basic cancel button"><translate translate-context="*/*/Button.Label/Verb">Close</translate></div> <button class="ui basic cancel button"><translate translate-context="*/*/Button.Label/Verb">Close</translate></button>
</footer> </footer>
</modal> </modal>
</template> </template>

View File

@ -25,7 +25,6 @@
</label> </label>
<input <input
ref="username" ref="username"
tabindex="1"
required required
name="username" name="username"
type="text" type="text"
@ -50,7 +49,7 @@
<translate translate-context="Contant/Auth/Paragraph" :translate-params="{domain: $store.getters['instance/domain']}">You will be redirected to %{ domain } to authenticate.</translate> <translate translate-context="Contant/Auth/Paragraph" :translate-params="{domain: $store.getters['instance/domain']}">You will be redirected to %{ domain } to authenticate.</translate>
</p> </p>
</template> </template>
<button tabindex="3" :class="['ui', {'loading': isLoading}, 'right', 'floated', buttonClasses, 'button']" type="submit"> <button :class="['ui', {'loading': isLoading}, 'right', 'floated', buttonClasses, 'button']" type="submit">
<translate translate-context="*/Login/*/Verb">Login</translate> <translate translate-context="*/Login/*/Verb">Login</translate>
</button> </button>
</form> </form>

View File

@ -14,14 +14,14 @@
</div> </div>
</div> </div>
<div class="actions"> <div class="actions">
<div class="ui basic cancel button"> <button class="ui basic cancel button">
<translate translate-context="*/*/Button.Label/Verb">Cancel</translate> <translate translate-context="*/*/Button.Label/Verb">Cancel</translate>
</div> </button>
<div :class="['ui', 'confirm', confirmButtonColor, 'button']" @click="confirm"> <button :class="['ui', 'confirm', confirmButtonColor, 'button']" @click="confirm">
<slot name="modal-confirm"> <slot name="modal-confirm">
<translate translate-context="Modal/*/Button.Label/Short, Verb">Confirm</translate> <translate translate-context="Modal/*/Button.Label/Short, Verb">Confirm</translate>
</slot> </slot>
</div> </button>
</div> </div>
</modal> </modal>
</div> </div>

View File

@ -37,8 +37,8 @@
</div> </div>
</div> </div>
<div class="actions"> <div class="actions">
<div class="ui basic cancel button"><translate translate-context="*/*/Button.Label/Verb">Cancel</translate></div> <button class="ui basic cancel button"><translate translate-context="*/*/Button.Label/Verb">Cancel</translate></button>
<div :class="['ui', 'success', {loading: isLoading}, 'button']" @click="hide"><translate translate-context="Popup/*/Button.Label">Hide content</translate></div> <button :class="['ui', 'success', {loading: isLoading}, 'button']" @click="hide"><translate translate-context="Popup/*/Button.Label">Hide content</translate></button>
</div> </div>
</modal> </modal>
</template> </template>

View File

@ -71,7 +71,7 @@
</div> </div>
</div> </div>
<div class="actions"> <div class="actions">
<div class="ui basic cancel button"><translate translate-context="*/*/Button.Label/Verb">Cancel</translate></div> <button class="ui basic cancel button"><translate translate-context="*/*/Button.Label/Verb">Cancel</translate></button>
<button <button
v-if="canSubmit" v-if="canSubmit"
:class="['ui', 'success', {loading: isLoading}, 'button']" :class="['ui', 'success', {loading: isLoading}, 'button']"

View File

@ -9,6 +9,7 @@
<script> <script>
import $ from 'jquery' import $ from 'jquery'
import createFocusTrap from 'focus-trap'
export default { export default {
props: { props: {
@ -17,9 +18,13 @@ export default {
}, },
data () { data () {
return { return {
control: null control: null,
focusTrap: null,
} }
}, },
mounted () {
this.focusTrap = createFocusTrap(this.$el)
},
beforeDestroy () { beforeDestroy () {
if (this.control) { if (this.control) {
$(this.$el).modal('hide') $(this.$el).modal('hide')
@ -38,6 +43,11 @@ export default {
}.bind(this), }.bind(this),
onHidden: function () { onHidden: function () {
this.$emit('update:show', false) this.$emit('update:show', false)
this.focusTrap.pause()
}.bind(this),
onVisible: function () {
this.focusTrap.activate()
this.focusTrap.unpause()
}.bind(this) }.bind(this)
}) })
} }

View File

@ -4375,6 +4375,14 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3" inherits "^2.0.3"
readable-stream "^2.3.6" readable-stream "^2.3.6"
focus-trap@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-5.1.0.tgz#64a0bfabd95c382103397dbc96bfef3a3cf8e5ad"
integrity sha512-CkB/nrO55069QAUjWFBpX6oc+9V90Qhgpe6fBWApzruMq5gnlh90Oo7iSSDK7pKiV5ugG6OY2AXM5mxcmL3lwQ==
dependencies:
tabbable "^4.0.0"
xtend "^4.0.1"
follow-redirects@1.5.10: follow-redirects@1.5.10:
version "1.5.10" version "1.5.10"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
@ -9206,6 +9214,11 @@ symbol-tree@^3.2.2:
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
tabbable@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-4.0.0.tgz#5bff1d1135df1482cf0f0206434f15eadbeb9261"
integrity sha512-H1XoH1URcBOa/rZZWxLxHCtOdVUEev+9vo5YdYhC9tCY4wnybX+VQrCYuy9ubkg69fCBxCONJOSLGfw0DWMffQ==
table@^5.2.3: table@^5.2.3:
version "5.4.6" version "5.4.6"
resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"