This commit is contained in:
parent
036c9e1914
commit
f86f3d4e1c
|
@ -3,8 +3,10 @@
|
|||
https://github.com/josdejong/jsoneditor
|
||||
|
||||
|
||||
## not yet published, version 8.0.1
|
||||
## not yet published, version 8.1.0
|
||||
|
||||
- Implemented `popupAnchor` allowing to select a custom anchor element.
|
||||
See #869 and #870.
|
||||
- Fixed #502: CSS rule `* { font-family: ... }` resulting in Ace editor (`code`
|
||||
mode) not having a mono-space font anymore.
|
||||
|
||||
|
|
11
docs/api.md
11
docs/api.md
|
@ -567,6 +567,17 @@ Constructs a new JSONEditor.
|
|||
The container element where modals (like for sorting and filtering) are attached: an overlay will be created on top
|
||||
of this container, and the modal will be created in the center of this container.
|
||||
|
||||
- `{HTMLElement} popupAnchor`
|
||||
|
||||
The container element where popups (for example drop down menus, for JSON Schema error
|
||||
tooltips, and color pickers) will be absolutely positioned.
|
||||
By default, this is the root DIV element of the editor itself.
|
||||
|
||||
When the JSONEditor is inside a DIV element which hides overflowing contents
|
||||
(CSS `overflow: auto` or `overflow: hidden`), tooltips will be visible only partly.
|
||||
In this case, a `popupAnchor` outside of the element without hidden overflow will allow
|
||||
the tooltips to be visible when overflowing the DIV element of the JSONEditor.
|
||||
|
||||
- `{boolean} enableSort`
|
||||
|
||||
Enable sorting of arrays and object properties. Only applicable for mode 'tree'. `true` by default.
|
||||
|
|
|
@ -183,7 +183,8 @@ JSONEditor.VALID_OPTIONS = [
|
|||
'timestampTag', 'timestampFormat',
|
||||
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation',
|
||||
'sortObjectKeys', 'navigationBar', 'statusBar', 'mainMenuBar', 'languages', 'language', 'enableSort', 'enableTransform',
|
||||
'maxVisibleChilds', 'onValidationError'
|
||||
'maxVisibleChilds', 'onValidationError',
|
||||
'modalAnchor', 'popupAnchor'
|
||||
]
|
||||
|
||||
/**
|
||||
|
|
|
@ -303,7 +303,7 @@ export class Node {
|
|||
|
||||
const createPopup = (destroyOnMouseOut) => {
|
||||
const frame = this.editor.frame
|
||||
this.dom.popupAnchor = createAbsoluteAnchor(button, frame, onDestroy, destroyOnMouseOut)
|
||||
this.dom.popupAnchor = createAbsoluteAnchor(button, this.editor.getPopupAnchor(), onDestroy, destroyOnMouseOut)
|
||||
|
||||
const popupWidth = 200 // must correspond to what's configured in the CSS
|
||||
const buttonRect = button.getBoundingClientRect()
|
||||
|
@ -3021,7 +3021,7 @@ export class Node {
|
|||
node._deleteDomColor()
|
||||
node.updateDom()
|
||||
|
||||
const colorAnchor = createAbsoluteAnchor(this.dom.color, this.editor.frame)
|
||||
const colorAnchor = createAbsoluteAnchor(this.dom.color, this.editor.getPopupAnchor())
|
||||
|
||||
this.editor.options.onColorPicker(colorAnchor, this.value, function onChange (value) {
|
||||
if (typeof value === 'string' && value !== node.value) {
|
||||
|
@ -3835,7 +3835,7 @@ export class Node {
|
|||
}
|
||||
|
||||
const menu = new ContextMenu(items, { close: onClose })
|
||||
menu.show(anchor, this.editor.frame)
|
||||
menu.show(anchor, this.editor.getPopupAnchor())
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -207,7 +207,7 @@ export function appendNodeFactory (Node) {
|
|||
}
|
||||
|
||||
const menu = new ContextMenu(items, { close: onClose })
|
||||
menu.show(anchor, this.editor.frame)
|
||||
menu.show(anchor, this.editor.getPopupAnchor())
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,13 +14,13 @@ export function createAbsoluteAnchor (anchor, parent, onDestroy, destroyOnMouseO
|
|||
const eventListeners = {}
|
||||
|
||||
const anchorRect = anchor.getBoundingClientRect()
|
||||
const frameRect = parent.getBoundingClientRect()
|
||||
const parentRect = parent.getBoundingClientRect()
|
||||
|
||||
const absoluteAnchor = document.createElement('div')
|
||||
absoluteAnchor.className = 'jsoneditor-anchor'
|
||||
absoluteAnchor.style.position = 'absolute'
|
||||
absoluteAnchor.style.left = (anchorRect.left - frameRect.left) + 'px'
|
||||
absoluteAnchor.style.top = (anchorRect.top - frameRect.top) + 'px'
|
||||
absoluteAnchor.style.left = (anchorRect.left - parentRect.left) + 'px'
|
||||
absoluteAnchor.style.top = (anchorRect.top - parentRect.top) + 'px'
|
||||
absoluteAnchor.style.width = (anchorRect.width - 2) + 'px'
|
||||
absoluteAnchor.style.height = (anchorRect.height - 2) + 'px'
|
||||
absoluteAnchor.style.boxSizing = 'border-box'
|
||||
|
|
|
@ -135,13 +135,12 @@ treemode._setOptions = function (options) {
|
|||
const pickerHeight = 300 // estimated height of the color picker
|
||||
const top = parent.getBoundingClientRect().top
|
||||
const windowHeight = window.innerHeight
|
||||
const showOnTop = ((windowHeight - top) < pickerHeight && top > pickerHeight)
|
||||
|
||||
new VanillaPicker({
|
||||
parent: parent,
|
||||
color: color,
|
||||
popup: ((windowHeight - top) < pickerHeight && top > pickerHeight)
|
||||
? 'top'
|
||||
: 'bottom',
|
||||
popup: showOnTop ? 'top' : 'bottom',
|
||||
onDone: function (color) {
|
||||
const alpha = color.rgba[3]
|
||||
const hex = (alpha === 1)
|
||||
|
@ -1063,7 +1062,7 @@ treemode._createFrame = function () {
|
|||
this.navBar.className = 'jsoneditor-navigation-bar nav-bar-empty'
|
||||
this.frame.appendChild(this.navBar)
|
||||
|
||||
this.treePath = new TreePath(this.navBar, this.frame)
|
||||
this.treePath = new TreePath(this.navBar, this.getPopupAnchor())
|
||||
this.treePath.onSectionSelected(this._onTreePathSectionSelected.bind(this))
|
||||
this.treePath.onContextMenuItemSelected(this._onTreePathMenuItemSelected.bind(this))
|
||||
}
|
||||
|
@ -1681,7 +1680,11 @@ treemode.showContextMenu = function (anchor, onClose) {
|
|||
}
|
||||
|
||||
const menu = new ContextMenu(items, { close: onClose })
|
||||
menu.show(anchor, this.frame)
|
||||
menu.show(anchor, this.getPopupAnchor())
|
||||
}
|
||||
|
||||
treemode.getPopupAnchor = function () {
|
||||
return this.options.popupAnchor || this.frame
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>JSONEditor | JSON schema validation</title>
|
||||
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
<script src="../dist/jsoneditor.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
width: 600px;
|
||||
font: 11pt sans-serif;
|
||||
}
|
||||
|
||||
#anchor {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#jsoneditor {
|
||||
width: 320px;
|
||||
height: 300px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* custom bold styling for non-default JSON schema values */
|
||||
.jsoneditor-is-not-default {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test custom tooltip anchor</h1>
|
||||
<p>
|
||||
The JSON Schema error tooltips and the color picker should have correct placing and overflow the editor, also in combination with scrolling.
|
||||
</p>
|
||||
|
||||
<div id="anchor">
|
||||
<div id="jsoneditor"></div>
|
||||
</div>
|
||||
<div style="height: 2000px"></div>
|
||||
|
||||
<script>
|
||||
const schema = {
|
||||
"title": "Employee",
|
||||
"description": "Object containing employee details",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"firstName": {
|
||||
"title": "First Name",
|
||||
"description": "The given name.",
|
||||
"examples": [
|
||||
"John"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"lastName": {
|
||||
"title": "Last Name",
|
||||
"description": "The family name.",
|
||||
"examples": [
|
||||
"Smith"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"gender": {
|
||||
"title": "Gender",
|
||||
"enum": ["male", "female"]
|
||||
},
|
||||
"availableToHire": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"age": {
|
||||
"description": "Age in years",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"examples": [28, 32]
|
||||
},
|
||||
"job": {
|
||||
"$ref": "job"
|
||||
}
|
||||
},
|
||||
"required": ["firstName", "lastName"]
|
||||
}
|
||||
|
||||
const job = {
|
||||
"title": "Job description",
|
||||
"type": "object",
|
||||
"required": ["address"],
|
||||
"properties": {
|
||||
"company": {
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"ACME",
|
||||
"Dexter Industries"
|
||||
]
|
||||
},
|
||||
"role": {
|
||||
"description": "Job title.",
|
||||
"type": "string",
|
||||
"examples": [
|
||||
"Human Resources Coordinator",
|
||||
"Software Developer"
|
||||
],
|
||||
"default": "Software Developer"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"salary": {
|
||||
"type": "number",
|
||||
"minimum": 120,
|
||||
"examples": [100, 110, 120]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const json = {
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
gender: null,
|
||||
age: "28",
|
||||
availableToHire: true,
|
||||
favoriteColor: 'red',
|
||||
job: {
|
||||
company: 'freelance',
|
||||
role: 'developer',
|
||||
salary: 100
|
||||
}
|
||||
}
|
||||
|
||||
const options = {
|
||||
schema: schema,
|
||||
schemaRefs: {"job": job},
|
||||
mode: 'tree',
|
||||
modes: ['code', 'text', 'tree', 'preview'],
|
||||
popupAnchor: document.getElementById('anchor')
|
||||
}
|
||||
|
||||
// create the editor
|
||||
const container = document.getElementById('jsoneditor')
|
||||
const editor = new JSONEditor(container, options, json)
|
||||
editor.expandAll()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue