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
|
## 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
|
- Fixed wrong text color in search box when using JSONEditor in combination
|
||||||
with bootstrap. See #791. Thanks @dmitry-kulikov.
|
with bootstrap. See #791. Thanks @dmitry-kulikov.
|
||||||
- Fixed react examples not working out of the box when cloning or downloading
|
- 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)
|
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')
|
const button = document.createElement('button')
|
||||||
button.type = 'button'
|
button.type = 'button'
|
||||||
button.className = 'jsoneditor-button jsoneditor-schema-error'
|
button.className = 'jsoneditor-button jsoneditor-schema-error'
|
||||||
button.appendChild(popover)
|
|
||||||
|
|
||||||
// update the direction of the popover
|
const destroy = () => {
|
||||||
button.onmouseover = button.onfocus = function updateDirection () {
|
if (this.dom.popupAnchor) {
|
||||||
const directions = ['right', 'above', 'below', 'left']
|
this.dom.popupAnchor.destroy() // this will trigger the onDestroy callback
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}.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
|
// when clicking the error icon, expand all nodes towards the invalid
|
||||||
// child node, and set focus to the child node
|
// child node, and set focus to the child node
|
||||||
|
@ -861,6 +878,11 @@ export class Node {
|
||||||
if (table) {
|
if (table) {
|
||||||
table.removeChild(tr)
|
table.removeChild(tr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.dom.popupAnchor) {
|
||||||
|
this.dom.popupAnchor.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
this.hideChilds(options)
|
this.hideChilds(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,11 @@ import { isChildOf, removeEventListener, addEventListener } from './util'
|
||||||
* element.
|
* element.
|
||||||
* @param {HTMLElement} anchor
|
* @param {HTMLElement} anchor
|
||||||
* @param {HTMLElement} parent
|
* @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}
|
* @returns {HTMLElement}
|
||||||
*/
|
*/
|
||||||
export function createAbsoluteAnchor (anchor, parent, onDestroy) {
|
export function createAbsoluteAnchor (anchor, parent, onDestroy, destroyOnMouseOut = false) {
|
||||||
const root = getRootNode(anchor)
|
const root = getRootNode(anchor)
|
||||||
const eventListeners = {}
|
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
|
// create and attach event listeners
|
||||||
const destroyIfOutside = event => {
|
function destroyIfOutside (event) {
|
||||||
const target = event.target
|
if (isOutside(event.target)) {
|
||||||
if ((target !== absoluteAnchor) && !isChildOf(target, absoluteAnchor)) {
|
|
||||||
destroy()
|
destroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eventListeners.mousedown = addEventListener(root, 'mousedown', destroyIfOutside)
|
eventListeners.mousedown = addEventListener(root, 'mousedown', destroyIfOutside)
|
||||||
eventListeners.mousewheel = addEventListener(root, 'mousewheel', 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
|
absoluteAnchor.destroy = destroy
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,8 @@ div {
|
||||||
}
|
}
|
||||||
div {
|
div {
|
||||||
&.jsoneditor-anchor {
|
&.jsoneditor-anchor {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
.picker_wrapper {
|
.picker_wrapper {
|
||||||
&.popup {
|
&.popup {
|
||||||
&.popup_bottom {
|
&.popup_bottom {
|
||||||
|
@ -370,12 +372,14 @@ div.jsoneditor-value,
|
||||||
div.jsoneditor td,
|
div.jsoneditor td,
|
||||||
div.jsoneditor th,
|
div.jsoneditor th,
|
||||||
div.jsoneditor textarea,
|
div.jsoneditor textarea,
|
||||||
div.jsoneditor pre.jsoneditor-preview,
|
pre.jsoneditor-preview,
|
||||||
div.jsoneditor .jsoneditor-schema-error {
|
.jsoneditor-schema-error,
|
||||||
|
.jsoneditor-popover{
|
||||||
font-family: $jse-font-mono;
|
font-family: $jse-font-mono;
|
||||||
font-size: $jse-font-size;
|
font-size: $jse-font-size;
|
||||||
color: $jse-content-color;
|
color: $jse-content-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.jsoneditor-schema-error {
|
.jsoneditor-schema-error {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -384,74 +388,76 @@ div.jsoneditor .jsoneditor-schema-error {
|
||||||
position: relative;
|
position: relative;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
.jsoneditor-popover {
|
}
|
||||||
background-color: $jse-popover-bg;
|
|
||||||
border-radius: 3px;
|
.jsoneditor-popover {
|
||||||
box-shadow: $jse-box-shadow-sm;
|
background-color: $jse-popover-bg;
|
||||||
color: $jse-white;
|
border-radius: 3px;
|
||||||
display: none;
|
box-shadow: $jse-box-shadow-sm;
|
||||||
padding: 7px 10px;
|
color: $jse-white;
|
||||||
position: absolute;
|
padding: 7px 10px;
|
||||||
width: 200px;
|
position: absolute;
|
||||||
z-index: 4;
|
cursor: auto;
|
||||||
&.jsoneditor-above {
|
width: 200px;
|
||||||
bottom: 32px;
|
z-index: 999;
|
||||||
left: -98px;
|
&.jsoneditor-above {
|
||||||
&:before {
|
bottom: 32px;
|
||||||
border-top: 7px solid $jse-popover-bg;
|
left: -98px;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&:before {
|
&:before {
|
||||||
border-right: 7px solid transparent;
|
border-top: 7px solid $jse-popover-bg;
|
||||||
border-left: 7px solid transparent;
|
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: "";
|
content: "";
|
||||||
display: block;
|
top: 19px;
|
||||||
left: 50%;
|
right: -14px;
|
||||||
margin-left: -7px;
|
left: inherit;
|
||||||
|
margin-left: inherit;
|
||||||
|
margin-top: -7px;
|
||||||
position: absolute;
|
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 {
|
.jsoneditor-text-errors {
|
||||||
tr {
|
tr {
|
||||||
&.jump-to-line {
|
&.jump-to-line {
|
||||||
|
|
|
@ -15,12 +15,19 @@
|
||||||
padding-left: 40px;
|
padding-left: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
#jsoneditor {
|
#jsoneditor {
|
||||||
width: 600px;
|
max-width: 600px;
|
||||||
|
width: 90%;
|
||||||
height: 500px;
|
height: 500px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue