Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(b-modal): add dragging (closes #7143)#7170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
nath7098 wants to merge3 commits intobootstrap-vue:dev
base:dev
Choose a base branch
Loading
fromnath7098:dev
Open
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletionssrc/components/modal/README.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -458,6 +458,23 @@ prop `scrollable` to `true`.
<!-- b-modal-scrollable-content.vue -->
```

### Draggable modal

You can make your modal draggable by setting the `draggable` prop to `true`. This will let you drag
it over the screen by grabbing the header.

```html
<div>
<b-button v-b-modal.modal-draggable>Launch draggable modal</b-button>

<b-modal id="modal-draggable" draggable title="BootstrapVue">
<p class="my-4">Draggable modal!</p>
</b-modal>
</div>

<!-- b-modal-draggable-content.vue -->
```

### Vertically centered modal

Vertically center your modal in the viewport by setting the `centered` prop.
Expand Down
6 changes: 6 additions & 0 deletionssrc/components/modal/_modal.scss
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,3 +3,9 @@
.modal-backdrop {
opacity: $modal-backdrop-opacity;
}

// When draggable property is set to true
// cursor is all-scroll on modal-header hover
.modal-drag {
cursor: all-scroll;
}
57 changes: 56 additions & 1 deletionsrc/components/modal/modal.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -125,6 +125,7 @@ export const props = makePropsConfigurable(
centered: makeProp(PROP_TYPE_BOOLEAN, false),
contentClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
dialogClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
draggable: makeProp(PROP_TYPE_BOOLEAN, false),
footerBgVariant: makeProp(PROP_TYPE_STRING),
footerBorderVariant: makeProp(PROP_TYPE_STRING),
footerClass: makeProp(PROP_TYPE_ARRAY_OBJECT_STRING),
Expand DownExpand Up@@ -267,7 +268,8 @@ export const BModal = /*#__PURE__*/ extend({
{
[`bg-${this.headerBgVariant}`]: this.headerBgVariant,
[`text-${this.headerTextVariant}`]: this.headerTextVariant,
[`border-${this.headerBorderVariant}`]: this.headerBorderVariant
[`border-${this.headerBorderVariant}`]: this.headerBorderVariant,
'modal-drag': this.draggable
},
this.headerClass
]
Expand DownExpand Up@@ -611,6 +613,23 @@ export const BModal = /*#__PURE__*/ extend({
}
eventOn(modal, 'mouseup', onceModalMouseup, EVENT_OPTIONS_NO_CAPTURE)
},
onHeaderMouseDown(event) {
const modal = this.$refs.modal
const header = this.$refs.header
// If modal is draggable and clicked target is the header
// Then modal modal can be dragged
if (this.draggable && event.target === header) {
this.onDrag(modal)
}
},
onHeaderMouseUp() {
const modal = this.$refs.modal
if (this.draggable) {
// Removes the mousedown event from modal when dragging is over
// This prevents being able to drag the modal by another part than the header when is has been drag before
modal.onmousedown = null
}
},
onClickOut(event) {
if (this.ignoreBackdropClick) {
// Click was initiated inside the modal content, but finished outside.
Expand DownExpand Up@@ -643,6 +662,41 @@ export const BModal = /*#__PURE__*/ extend({
this.hide(TRIGGER_ESC)
}
},
onDrag(element) {
let pos1 = 0
let pos2 = 0
let pos3 = 0
let pos4 = 0
element.onmousedown = dragMouseDown

function dragMouseDown(e) {
e = e || window.event
e.preventDefault()
pos3 = e.clientX
pos4 = e.clientY
document.onmouseup = _event => closeDragElement(_event, element)
document.onmousemove = elementDrag
}

function elementDrag(e) {
e = e || window.event
e.preventDefault()
// calculate the new cursor position:
pos1 = pos3 - e.clientX
pos2 = pos4 - e.clientY
pos3 = e.clientX
pos4 = e.clientY
// set the element's new position:
element.style.top = element.offsetTop - pos2 + 'px'
element.style.left = element.offsetLeft - pos1 + 'px'
}

function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null
document.onmousemove = null
}
},
// Document focusin listener
focusHandler(event) {
// If focus leaves modal content, bring it back
Expand DownExpand Up@@ -821,6 +875,7 @@ export const BModal = /*#__PURE__*/ extend({
staticClass: 'modal-header',
class: this.headerClasses,
attrs: { id: this.modalHeaderId },
on: { mousedown: this.onHeaderMouseDown, mouseup: this.onHeaderMouseUp },
ref: 'header'
},
[$modalHeader]
Expand Down
186 changes: 186 additions & 0 deletionssrc/components/modal/modal.spec.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -780,6 +780,192 @@ describe('modal', () => {
wrapper.destroy()
})

it('mousedown inside header and mousemove when modal is draggable moves the modal', async () => {
let trigger = null
let called = false
const wrapper = mount(BModal, {
attachTo: document.body,
propsData: {
static: true,
id: 'test',
visible: true,
draggable: true
},
listeners: {
hide: bvEvent => {
called = true
trigger = bvEvent.trigger
}
}
})

expect(wrapper.vm).toBeDefined()

await waitNT(wrapper.vm)
await waitRAF()
await waitNT(wrapper.vm)
await waitRAF()

const $modal = wrapper.find('div.modal')
expect($modal.exists()).toBe(true)

const $header = wrapper.find('.modal-header')
expect($header.exists()).toBe(true)

const $dialog = wrapper.find('div.modal-dialog')
expect($dialog.exists()).toBe(true)

const $footer = wrapper.find('footer.modal-footer')
expect($footer.exists()).toBe(true)

expect($modal.element.style.display).toEqual('block')

expect(wrapper.emitted('hide')).toBeUndefined()
expect(trigger).toEqual(null)

// Try and move modal via a "dragged" click
// starting from inside modal header
await $header.trigger('mousedown', { clientX: 0, clientY: 0 })
await $header.trigger('mousemove', { clientX: 100, clientY: 100 })
await $header.trigger('mouseup')
await $header.trigger('click')
await waitRAF()
await waitRAF()
expect(called).toEqual(false)
expect(trigger).toEqual(null)

// Modal should not be closed
expect($modal.element.style.display).toEqual('block')

// Modal should have been moved away
expect($modal.element.style.top).toEqual('100px')

wrapper.destroy()
})

it('mousedown inside body and mousemove when modal is draggable does not move the modal', async () => {
let trigger = null
let called = false
const wrapper = mount(BModal, {
attachTo: document.body,
propsData: {
static: true,
id: 'test',
visible: true,
draggable: true
},
listeners: {
hide: bvEvent => {
called = true
trigger = bvEvent.trigger
}
}
})

expect(wrapper.vm).toBeDefined()

await waitNT(wrapper.vm)
await waitRAF()
await waitNT(wrapper.vm)
await waitRAF()

const $modal = wrapper.find('div.modal')
expect($modal.exists()).toBe(true)

const $dialog = wrapper.find('div.modal-dialog')
expect($dialog.exists()).toBe(true)

const $footer = wrapper.find('footer.modal-footer')
expect($footer.exists()).toBe(true)

expect($modal.element.style.display).toEqual('block')

expect(wrapper.emitted('hide')).toBeUndefined()
expect(trigger).toEqual(null)

// Try and move modal via a "dragged"
// starting from inside modal body
await $dialog.trigger('mousedown')
await $dialog.trigger('mousemove')
await $modal.trigger('mouseup')
await $modal.trigger('click')
await waitRAF()
await waitRAF()
expect(called).toEqual(false)
expect(trigger).toEqual(null)

// Modal should not be closed
expect($modal.element.style.display).toEqual('block')
console.log('[click in body]', $modal.element.style.top)
// Modal should not have been moved away
expect($modal.element.style.top).toBe('')

wrapper.destroy()
})

it('mousedown inside header and mousemove when modal is not draggable does not move the modal', async () => {
let trigger = null
let called = false
const wrapper = mount(BModal, {
attachTo: document.body,
propsData: {
static: true,
id: 'test',
visible: true,
draggable: false
},
listeners: {
hide: bvEvent => {
called = true
trigger = bvEvent.trigger
}
}
})

expect(wrapper.vm).toBeDefined()

await waitNT(wrapper.vm)
await waitRAF()
await waitNT(wrapper.vm)
await waitRAF()

const $modal = wrapper.find('div.modal')
expect($modal.exists()).toBe(true)

const $header = wrapper.find('.modal-header')
expect($header.exists()).toBe(true)

const $dialog = wrapper.find('div.modal-dialog')
expect($dialog.exists()).toBe(true)

const $footer = wrapper.find('footer.modal-footer')
expect($footer.exists()).toBe(true)

expect($modal.element.style.display).toEqual('block')

expect(wrapper.emitted('hide')).toBeUndefined()
expect(trigger).toEqual(null)

// Try and move modal via a "dragged" click
// starting from inside modal header
await $header.trigger('mousedown', { clientX: 0, clientY: 0 })
await $header.trigger('mousemove', { clientX: 100, clientY: 100 })
await $header.trigger('mouseup')
await $header.trigger('click')
await waitRAF()
await waitRAF()
expect(called).toEqual(false)
expect(trigger).toEqual(null)

// Modal should not be closed
expect($modal.element.style.display).toEqual('block')
console.log('[click not draggable]', $modal.element.style.top)
// Modal should not have been moved away
expect($modal.element.style.top).toBe('')

wrapper.destroy()
})

it('$root bv::show::modal and bv::hide::modal work', async () => {
const wrapper = mount(BModal, {
attachTo: document.body,
Expand Down
4 changes: 4 additions & 0 deletionssrc/components/modal/package.json
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -88,6 +88,10 @@
"prop": "dialogClass",
"description": "CSS class (or classes) to apply to the '.modal-dialog' wrapper element"
},
{
"prop": "draggable",
"description": "Enables dragging of the modal by the header"
},
{
"prop": "footerBgVariant",
"description": "Applies one of the Bootstrap theme color variants to the footer background"
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp