Fixed #723: schema error popup not always fully visible
This commit is contained in:
parent
e23eb8f191
commit
83e9e0655c
|
@ -5,6 +5,7 @@ https://github.com/josdejong/jsoneditor
|
|||
|
||||
## not yet published, version 7.0.4
|
||||
|
||||
- Fixed #723: schema error popup not always fully visible.
|
||||
- Fixed wrong text color in search box when using JSONEditor in combination
|
||||
with bootstrap. See #791. Thanks @dmitry-kulikov.
|
||||
- Fixed react examples not working out of the box when cloning or downloading
|
||||
|
|
|
@ -288,32 +288,49 @@ export class Node {
|
|||
this.dom.tdValue.parentNode.appendChild(tdError)
|
||||
}
|
||||
|
||||
const popover = document.createElement('div')
|
||||
popover.className = 'jsoneditor-popover jsoneditor-right'
|
||||
popover.appendChild(document.createTextNode(error.message))
|
||||
|
||||
const button = document.createElement('button')
|
||||
button.type = 'button'
|
||||
button.className = 'jsoneditor-button jsoneditor-schema-error'
|
||||
button.appendChild(popover)
|
||||
|
||||
// update the direction of the popover
|
||||
button.onmouseover = button.onfocus = function updateDirection () {
|
||||
const directions = ['right', 'above', 'below', 'left']
|
||||
for (let i = 0; i < directions.length; i++) {
|
||||
const direction = directions[i]
|
||||
popover.className = 'jsoneditor-popover jsoneditor-' + direction
|
||||
|
||||
const contentRect = this.editor.content.getBoundingClientRect()
|
||||
const popoverRect = popover.getBoundingClientRect()
|
||||
const margin = 20 // account for a scroll bar
|
||||
const fit = insideRect(contentRect, popoverRect, margin)
|
||||
|
||||
if (fit) {
|
||||
break
|
||||
}
|
||||
const destroy = () => {
|
||||
if (this.dom.popupAnchor) {
|
||||
this.dom.popupAnchor.destroy() // this will trigger the onDestroy callback
|
||||
}
|
||||
}.bind(this)
|
||||
}
|
||||
|
||||
const onDestroy = () => {
|
||||
delete this.dom.popupAnchor
|
||||
}
|
||||
|
||||
const createPopup = (destroyOnMouseOut) => {
|
||||
const frame = this.editor.frame
|
||||
this.dom.popupAnchor = createAbsoluteAnchor(button, frame, onDestroy, destroyOnMouseOut)
|
||||
|
||||
const popupWidth = 200; // must correspond to what's configured in the CSS
|
||||
const buttonRect = button.getBoundingClientRect()
|
||||
const frameRect = frame.getBoundingClientRect()
|
||||
const position = (frameRect.width - buttonRect.x > (popupWidth / 2 + 20))
|
||||
? 'jsoneditor-above'
|
||||
: 'jsoneditor-left'
|
||||
|
||||
const popover = document.createElement('div')
|
||||
popover.className = 'jsoneditor-popover ' + position
|
||||
popover.appendChild(document.createTextNode(error.message))
|
||||
this.dom.popupAnchor.appendChild(popover)
|
||||
}
|
||||
|
||||
button.onmouseover = () => {
|
||||
if (!this.dom.popupAnchor) {
|
||||
createPopup(true)
|
||||
}
|
||||
}
|
||||
button.onfocus = () => {
|
||||
destroy()
|
||||
createPopup(false)
|
||||
}
|
||||
button.onblur = () => {
|
||||
destroy()
|
||||
}
|
||||
|
||||
// when clicking the error icon, expand all nodes towards the invalid
|
||||
// child node, and set focus to the child node
|
||||
|
@ -861,6 +878,11 @@ export class Node {
|
|||
if (table) {
|
||||
table.removeChild(tr)
|
||||
}
|
||||
|
||||
if (this.dom.popupAnchor) {
|
||||
this.dom.popupAnchor.destroy()
|
||||
}
|
||||
|
||||
this.hideChilds(options)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,11 @@ import { isChildOf, removeEventListener, addEventListener } from './util'
|
|||
* element.
|
||||
* @param {HTMLElement} anchor
|
||||
* @param {HTMLElement} parent
|
||||
* @param [onDestroy(function(anchor)] Callback when the anchor is destroyed
|
||||
* @param {function(HTMLElement)} [onDestroy] Callback when the anchor is destroyed
|
||||
* @param {boolean} [destroyOnMouseOut=false] If true, anchor will be removed on mouse out
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
export function createAbsoluteAnchor (anchor, parent, onDestroy) {
|
||||
export function createAbsoluteAnchor (anchor, parent, onDestroy, destroyOnMouseOut = false) {
|
||||
const root = getRootNode(anchor)
|
||||
const eventListeners = {}
|
||||
|
||||
|
@ -48,17 +49,34 @@ export function createAbsoluteAnchor (anchor, parent, onDestroy) {
|
|||
}
|
||||
}
|
||||
|
||||
function isOutside (target) {
|
||||
return (target !== absoluteAnchor) && !isChildOf(target, absoluteAnchor)
|
||||
}
|
||||
|
||||
// create and attach event listeners
|
||||
const destroyIfOutside = event => {
|
||||
const target = event.target
|
||||
if ((target !== absoluteAnchor) && !isChildOf(target, absoluteAnchor)) {
|
||||
function destroyIfOutside (event) {
|
||||
if (isOutside(event.target)) {
|
||||
destroy()
|
||||
}
|
||||
}
|
||||
|
||||
eventListeners.mousedown = addEventListener(root, 'mousedown', destroyIfOutside)
|
||||
eventListeners.mousewheel = addEventListener(root, 'mousewheel', destroyIfOutside)
|
||||
// eventListeners.scroll = addEventListener(root, 'scroll', destroyIfOutside);
|
||||
|
||||
if (destroyOnMouseOut) {
|
||||
let destroyTimer = null
|
||||
|
||||
absoluteAnchor.onmouseover = () => {
|
||||
clearTimeout(destroyTimer)
|
||||
destroyTimer = null
|
||||
}
|
||||
|
||||
absoluteAnchor.onmouseout = () => {
|
||||
if (!destroyTimer) {
|
||||
destroyTimer = setTimeout(destroy, 200)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
absoluteAnchor.destroy = destroy
|
||||
|
||||
|
|
|
@ -82,6 +82,8 @@ div {
|
|||
}
|
||||
div {
|
||||
&.jsoneditor-anchor {
|
||||
cursor: pointer;
|
||||
|
||||
.picker_wrapper {
|
||||
&.popup {
|
||||
&.popup_bottom {
|
||||
|
@ -370,12 +372,14 @@ div.jsoneditor-value,
|
|||
div.jsoneditor td,
|
||||
div.jsoneditor th,
|
||||
div.jsoneditor textarea,
|
||||
div.jsoneditor pre.jsoneditor-preview,
|
||||
div.jsoneditor .jsoneditor-schema-error {
|
||||
pre.jsoneditor-preview,
|
||||
.jsoneditor-schema-error,
|
||||
.jsoneditor-popover{
|
||||
font-family: $jse-font-mono;
|
||||
font-size: $jse-font-size;
|
||||
color: $jse-content-color;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error {
|
||||
cursor: default;
|
||||
display: inline-block;
|
||||
|
@ -384,74 +388,76 @@ div.jsoneditor .jsoneditor-schema-error {
|
|||
position: relative;
|
||||
text-align: center;
|
||||
width: 24px;
|
||||
.jsoneditor-popover {
|
||||
background-color: $jse-popover-bg;
|
||||
border-radius: 3px;
|
||||
box-shadow: $jse-box-shadow-sm;
|
||||
color: $jse-white;
|
||||
display: none;
|
||||
padding: 7px 10px;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
z-index: 4;
|
||||
&.jsoneditor-above {
|
||||
bottom: 32px;
|
||||
left: -98px;
|
||||
&:before {
|
||||
border-top: 7px solid $jse-popover-bg;
|
||||
bottom: -7px;
|
||||
}
|
||||
}
|
||||
&.jsoneditor-below {
|
||||
top: 32px;
|
||||
left: -98px;
|
||||
&:before {
|
||||
border-bottom: 7px solid $jse-popover-bg;
|
||||
top: -7px;
|
||||
}
|
||||
}
|
||||
&.jsoneditor-left {
|
||||
top: -7px;
|
||||
right: 32px;
|
||||
&:before {
|
||||
border-left: 7px solid $jse-popover-bg;
|
||||
border-top: 7px solid transparent;
|
||||
border-bottom: 7px solid transparent;
|
||||
content: "";
|
||||
top: 19px;
|
||||
right: -14px;
|
||||
left: inherit;
|
||||
margin-left: inherit;
|
||||
margin-top: -7px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
&.jsoneditor-right {
|
||||
top: -7px;
|
||||
left: 32px;
|
||||
&:before {
|
||||
border-right: 7px solid $jse-popover-bg;
|
||||
border-top: 7px solid transparent;
|
||||
border-bottom: 7px solid transparent;
|
||||
content: "";
|
||||
top: 19px;
|
||||
left: -14px;
|
||||
margin-left: inherit;
|
||||
margin-top: -7px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.jsoneditor-popover {
|
||||
background-color: $jse-popover-bg;
|
||||
border-radius: 3px;
|
||||
box-shadow: $jse-box-shadow-sm;
|
||||
color: $jse-white;
|
||||
padding: 7px 10px;
|
||||
position: absolute;
|
||||
cursor: auto;
|
||||
width: 200px;
|
||||
z-index: 999;
|
||||
&.jsoneditor-above {
|
||||
bottom: 32px;
|
||||
left: -98px;
|
||||
&:before {
|
||||
border-right: 7px solid transparent;
|
||||
border-left: 7px solid transparent;
|
||||
border-top: 7px solid $jse-popover-bg;
|
||||
bottom: -7px;
|
||||
}
|
||||
}
|
||||
&.jsoneditor-below {
|
||||
top: 32px;
|
||||
left: -98px;
|
||||
&:before {
|
||||
border-bottom: 7px solid $jse-popover-bg;
|
||||
top: -7px;
|
||||
}
|
||||
}
|
||||
&.jsoneditor-left {
|
||||
top: -7px;
|
||||
right: 32px;
|
||||
&:before {
|
||||
border-left: 7px solid $jse-popover-bg;
|
||||
border-top: 7px solid transparent;
|
||||
border-bottom: 7px solid transparent;
|
||||
content: "";
|
||||
display: block;
|
||||
left: 50%;
|
||||
margin-left: -7px;
|
||||
top: 19px;
|
||||
right: -14px;
|
||||
left: inherit;
|
||||
margin-left: inherit;
|
||||
margin-top: -7px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
&.jsoneditor-right {
|
||||
top: -7px;
|
||||
left: 32px;
|
||||
&:before {
|
||||
border-right: 7px solid $jse-popover-bg;
|
||||
border-top: 7px solid transparent;
|
||||
border-bottom: 7px solid transparent;
|
||||
content: "";
|
||||
top: 19px;
|
||||
left: -14px;
|
||||
margin-left: inherit;
|
||||
margin-top: -7px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
&:before {
|
||||
border-right: 7px solid transparent;
|
||||
border-left: 7px solid transparent;
|
||||
content: "";
|
||||
display: block;
|
||||
left: 50%;
|
||||
margin-left: -7px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.jsoneditor-text-errors {
|
||||
tr {
|
||||
&.jump-to-line {
|
||||
|
|
|
@ -15,12 +15,19 @@
|
|||
padding-left: 40px;
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
#jsoneditor {
|
||||
width: 600px;
|
||||
max-width: 600px;
|
||||
width: 90%;
|
||||
height: 500px;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue