Fix #1128: Lock focus in modals to improve accessibility
This commit is contained in:
parent
c5755e21a5
commit
0094cbb7d1
|
@ -0,0 +1 @@
|
||||||
|
Use semantic headers for accessibility (#1121)
|
|
@ -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",
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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']"
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue