fix: clicking outside image closes modal (#1312)

fixes #862
This commit is contained in:
Nolan Lawson 2019-07-07 14:51:08 -07:00 committed by GitHub
parent 9fd5c8f6d2
commit 8f6681ad7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 91 additions and 16 deletions

View file

@ -3,15 +3,16 @@
{label}
background="var(--muted-modal-bg)"
muted="true"
clickHeaderToClose={true}
className="media-modal-dialog"
on:show="onShow()"
>
<div class="media-container">
<ul class="media-scroll" ref:scroller>
<ul class="media-scroll" ref:scroller on:click="onImageClick(event)">
{#each mediaItems as media (media.id)}
<li class="media-scroll-item">
<div class="media-scroll-item-inner">
<div class="media-scroll-item-inner-inner">
<div class="media-scroll-item-image-area">
{#if canPinchZoom && pinchZoomMode}
<PinchZoomable className='media-pinch-zoom' >
<MediaInDialog {media} />
@ -24,10 +25,11 @@
</li>
{/each}
</ul>
<div class="media-controls-outside">
<div class="media-controls-outside" on:click="onMediaControlsClick(event)">
{#if canPinchZoom}
<IconButton
className="media-control-button media-control-button-dummy-spacer"
svgClassName="media-control-button-svg"
href="#fa-search"
label=""
ariaHidden={true}
@ -37,6 +39,7 @@
<div class="media-controls">
<IconButton
className="media-control-button"
svgClassName="media-control-button-svg"
disabled={scrolledItem === 0}
label="Show previous media"
href="#fa-angle-left"
@ -45,16 +48,18 @@
{#each dots as dot, i (dot.i)}
<IconButton
className="media-control-button"
svgClassName="media-control-button-svg"
pressable={true}
label="Show {nth(i)} media"
pressed={i === scrolledItem}
href={i === scrolledItem ? '#fa-circle' : '#fa-circle-o'}
sameColorWhenPressed={true}
on:click="onClick(i)"
on:click="onButtonClick(i)"
/>
{/each}
<IconButton
className="media-control-button"
svgClassName="media-control-button-svg"
disabled={scrolledItem === length - 1}
label="Show next media"
href="#fa-angle-right"
@ -65,6 +70,7 @@
{#if canPinchZoom}
<IconButton
className="media-control-button"
svgClassName="media-control-button-svg"
pressable={true}
pressed={pinchZoomMode}
label={pinchZoomMode ? 'Disable pinch-zoom mode' : 'Enable pinch-zoom mode'}
@ -85,7 +91,6 @@
.media-container {
height: calc(100% - 64px); /* 44px X button height + 20px padding */
width: calc(100vw);
padding-top: 10px;
display: flex;
flex-direction: column;
}
@ -118,16 +123,16 @@
height: 100%;
overflow: hidden;
}
.media-scroll-item-inner-inner {
height: calc(100% - 10px);
width: calc(100% - 10px);
padding: 5px;
.media-scroll-item-image-area {
height: calc(100% - 20px); /* 15px padding top + 5px padding bottom */
width: calc(100% - 10px); /* 5px padding left + 5px padding right */
padding: 15px 5px 5px 5px;
}
.media-controls-outside {
display: flex;
justify-content: space-between;
margin: 10px;
padding: 10px;
}
.media-controls {
@ -148,6 +153,11 @@
margin: 0 5px;
}
:global(.media-control-button-svg) {
/* ensure that click events do not fall on these svgs */
pointer-events: none;
}
@media (max-width: 767px) {
:global(.icon-button.media-control-button) {
margin: 0;
@ -197,10 +207,21 @@
import PinchZoomable from './PinchZoomable.html'
import { show } from '../helpers/showDialog'
import { oncreate as onCreateDialog } from '../helpers/onCreateDialog'
import { close } from '../helpers/closeDialog'
import debounce from 'lodash-es/debounce'
import times from 'lodash-es/times'
import { smoothScroll, hasNativeSmoothScroll } from '../../../_utils/smoothScroll'
import { store } from '../../../_store/store'
import { intrinsicScale } from '../../../_thirdparty/intrinsic-scale/intrinsicScale'
import { get } from '../../../_utils/lodash-lite'
// padding for .media-scroll-item-image-area
const IMAGE_AREA_PADDING = {
top: 15,
left: 5,
right: 5,
bottom: 5
}
export default {
oncreate () {
@ -217,7 +238,10 @@
computed: {
length: ({ mediaItems }) => mediaItems.length,
dots: ({ length }) => times(length, i => ({ i })),
canPinchZoom: ({ mediaItems }) => !mediaItems.some(media => ['video', 'audio'].includes(media.type))
canPinchZoom: ({ mediaItems }) => !mediaItems.some(media => ['video', 'audio'].includes(media.type)),
mediaItem: ({ mediaItems, scrolledItem }) => mediaItems[scrolledItem],
nativeWidth: ({ mediaItem }) => get(mediaItem, ['meta', 'original', 'width'], 300), // TODO: Pleroma placeholder
nativeHeight: ({ mediaItem }) => get(mediaItem, ['meta', 'original', 'height'], 200) // TODO: Pleroma placeholder
},
components: {
ModalDialog,
@ -242,6 +266,7 @@
},
methods: {
show,
close,
setupScroll () {
this.refs.scroller.addEventListener('scroll', this.onScroll)
},
@ -258,7 +283,7 @@
let scrolledItem = Math.round((scrollLeft / scrollWidth) * length)
this.set({ scrolledItem })
},
onClick (i) {
onButtonClick (i) {
let { scrolledItem } = this.get()
if (scrolledItem !== i) {
this.scrollToItem(i, true)
@ -308,6 +333,44 @@
},
togglePinchZoomMode () {
this.set({ pinchZoomMode: !this.get().pinchZoomMode })
},
onImageClick (e) {
let { nativeWidth, nativeHeight, pinchZoomMode } = this.get()
if (pinchZoomMode) {
return
}
let rect = this.refs.scroller.getBoundingClientRect()
// apply padding
rect = {
width: rect.width - IMAGE_AREA_PADDING.left - IMAGE_AREA_PADDING.right,
height: rect.height - IMAGE_AREA_PADDING.top - IMAGE_AREA_PADDING.bottom,
left: rect.left + IMAGE_AREA_PADDING.left,
top: rect.top + IMAGE_AREA_PADDING.top
}
let scale = intrinsicScale(rect.width, rect.height, nativeWidth, nativeHeight)
let x = e.clientX - rect.left
let y = e.clientY - rect.top
let insideImage = x >= scale.x && x <= (scale.x + scale.width) && y >= scale.y && y <= (scale.y + scale.height)
if (!insideImage) {
// close dialog when clicking outside of image
e.preventDefault()
e.stopPropagation()
this.close()
}
},
onMediaControlsClick (e) {
let { pinchZoomMode } = this.get()
if (pinchZoomMode) {
return
}
let { target } = e
if (target.tagName !== 'BUTTON' && !target.classList.contains('media-controls')) {
e.preventDefault()
e.stopPropagation()
// close dialog when clicking on the controls but not on a button inside the controls,
// or between the buttons
this.close()
}
}
}
}

View file

@ -223,8 +223,12 @@
focusX: ({ mediaItem }) => get(mediaItem, ['focusX'], 0),
focusY: ({ mediaItem }) => get(mediaItem, ['focusY'], 0),
previewSrc: ({ mediaItem }) => mediaItem.data.preview_url,
nativeWidth: ({ mediaItem }) => get(mediaItem, ['data', 'meta', 'original', 'width'], 300),
nativeHeight: ({ mediaItem }) => get(mediaItem, ['data', 'meta', 'original', 'height'], 200),
nativeWidth: ({ mediaItem }) => (
get(mediaItem, ['data', 'meta', 'original', 'width'], 300) // TODO: Pleroma placeholder
),
nativeHeight: ({ mediaItem }) => (
get(mediaItem, ['data', 'meta', 'original', 'height'], 200) // TODO: Pleroma placeholder
),
shortName: ({ mediaItem }) => (
// sometimes we no longer have the file, e.g. in a delete and redraft situation,
// so fall back to the description if it was provided

View file

@ -8,7 +8,7 @@
ref:node
>
<div class="modal-dialog-document" role="document" style="background: {background || '#000'};">
<div class="modal-dialog-header">
<div class="modal-dialog-header" on:click="onClickHeader(event)">
{#if title}
<h1 class="modal-dialog-title">{title}</h1>
{/if}
@ -190,7 +190,8 @@
muted: false,
className: void 0,
title: void 0,
shrinkWidthToFit: false
shrinkWidthToFit: false,
clickHeaderToClose: false
}),
computed: {
backdropClass: ({ fadedIn, shouldAnimate }) => {
@ -246,6 +247,13 @@
return
}
this._a11yDialog.hide()
},
onClickHeader (e) {
if (this.get().clickHeaderToClose) {
e.preventDefault()
e.stopPropagation()
this._a11yDialog.hide()
}
}
}
}