Skip to content
Permalink
Browse files
feat(v-b-toggle): check for target ID via href if a link (#5398)
* feat(v-b-toggle): check for target ID via `href` if a link

* Update toggle.js

* Update toggle.js

* Update toggle.js

* Update toggle.js

* Update toggle.js

* Update toggle.spec.js

* Update toggle.js

* Update README.md

Co-authored-by: Jacob Müller <jacob.mueller.elz@gmail.com>
  • Loading branch information
tmorehouse and jacobmllr95 committed May 19, 2020
1 parent 9d5150c commit 33e39b007225ba86a0c84a66e3ee60b9d2f01fed
Showing 3 changed files with 215 additions and 114 deletions.
@@ -16,7 +16,7 @@ details and caveats.

## Directive syntax and usage

The directive is applied to the element or component that triggers the visibility of hte target. The
The directive is applied to the element or component that triggers the visibility of the target. The
target component can be specified (via its ID) as either a directive modifier(s), the directive
argument, or as a string/array passed to as the directive value:

@@ -34,7 +34,7 @@ argument, or as a string/array passed to as the directive value:

Modifiers, argument, and the value can be used at the same time when targeting multiple components.

### Example usage
**Example usage:**

```html
<template>
@@ -62,6 +62,44 @@ Modifiers, argument, and the value can be used at the same time when targeting m
<!-- v-b-toggle-directive.vue -->
```

## Usage on links

<span class="badge badge-info small">2.15.0+</span>

If placing the directive on a link (or a component that renders a link), the target ID can
alternatively be specified via the `href` attribute.

Note that the browser URL will change and the page may scroll the target into view. To prevent the
URL from changing and the page from scrolling, add `@click.prevent` to the link.

**Example usage:**

```html
<template>
<div>
<div class="mb-3">
<a v-b-toggle href="#example-collapse" @click.prevent>Toggle Collapse</a>
<b-button v-b-toggle href="#example-sidebar" @click.prevent>Toggle Sidebar</b-button>
</div>

<b-collapse id="example-collapse">
<b-card title="Collapsible card">
Hello world!
</b-card>
</b-collapse>

<b-sidebar id="example-sidebar" title="Sidebar" shadow>
<div class="px-3 py-2">
Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis
in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
</div>
</b-sidebar>
</div>
</template>

<!-- v-b-toggle-links.vue -->
```

## Hiding and showing content in the toggle trigger element

When using the `v-b-toggle` directive, the class `collapsed` will automatically be placed on the
@@ -1,7 +1,16 @@
import KeyCodes from '../../utils/key-codes'
import looseEqual from '../../utils/loose-equal'
import { arrayIncludes, concat } from '../../utils/array'
import { addClass, hasAttr, isDisabled, removeAttr, removeClass, setAttr } from '../../utils/dom'
import {
addClass,
getAttr,
hasAttr,
isDisabled,
isTag,
removeAttr,
removeClass,
setAttr
} from '../../utils/dom'
import { isBrowser } from '../../utils/env'
import { eventOn, eventOff } from '../../utils/events'
import { isString } from '../../utils/inspect'
@@ -51,19 +60,29 @@ export const EVENT_STATE_REQUEST = 'bv::request::collapse::state'

const KEYDOWN_KEY_CODES = [ENTER, SPACE]

const RX_HASH = /^#/
const RX_HASH_ID = /^#[A-Za-z]+[\w\-:.]*$/
const RX_SPLIT_SEPARATOR = /\s+/

// --- Helper methods ---

const isNonStandardTag = el => !arrayIncludes(['BUTTON', 'A'], el.tagName)
const isNonStandardTag = el => !arrayIncludes(['button', 'a'], el.tagName.toLowerCase())

const getTargets = ({ modifiers, arg, value }) => {
const getTargets = ({ modifiers, arg, value }, el) => {
// Any modifiers are considered target IDs
const targets = keys(modifiers || {})

// If value is a string, split out individual targets (if space delimited)
value = isString(value) ? value.split(RX_SPLIT_SEPARATOR) : value

// Support target ID as link href (`href="#id"`)
if (isTag(el.tagName, 'a')) {
const href = getAttr(el, 'href') || ''
if (RX_HASH_ID.test(href)) {
targets.push(href.replace(RX_HASH, ''))
}
}

// Add ID from `arg` (if provided), and support value
// as a single string ID or an array of string IDs
// If `value` is not an array or string, then it gets filtered out
@@ -172,7 +191,7 @@ const handleUpdate = (el, binding, vnode) => {
setToggleState(el, el[BV_TOGGLE_STATE])

// Parse list of target IDs
const targets = getTargets(binding)
const targets = getTargets(binding, el)

/* istanbul ignore else */
// Ensure the `aria-controls` hasn't been overwritten

0 comments on commit 33e39b0

Please sign in to comment.