diff --git a/HISTORY.md b/HISTORY.md index 5715e4d..910b054 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -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. diff --git a/docs/api.md b/docs/api.md index 8e16c43..7cd79f3 100644 --- a/docs/api.md +++ b/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. diff --git a/src/js/JSONEditor.js b/src/js/JSONEditor.js index f8fd63e..6fd4482 100644 --- a/src/js/JSONEditor.js +++ b/src/js/JSONEditor.js @@ -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' ] /** diff --git a/src/js/Node.js b/src/js/Node.js index 6345a2e..49f2498 100644 --- a/src/js/Node.js +++ b/src/js/Node.js @@ -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()) } /** diff --git a/src/js/appendNodeFactory.js b/src/js/appendNodeFactory.js index 07cf7f4..a307a06 100644 --- a/src/js/appendNodeFactory.js +++ b/src/js/appendNodeFactory.js @@ -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()) } /** diff --git a/src/js/createAbsoluteAnchor.js b/src/js/createAbsoluteAnchor.js index a6ec62d..3963fb6 100644 --- a/src/js/createAbsoluteAnchor.js +++ b/src/js/createAbsoluteAnchor.js @@ -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' diff --git a/src/js/treemode.js b/src/js/treemode.js index 7cc4c8b..d8329dd 100644 --- a/src/js/treemode.js +++ b/src/js/treemode.js @@ -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 } /** diff --git a/test/test_tooltip_anchor.html b/test/test_tooltip_anchor.html new file mode 100644 index 0000000..08cfd74 --- /dev/null +++ b/test/test_tooltip_anchor.html @@ -0,0 +1,146 @@ + + + + JSONEditor | JSON schema validation + + + + + + + +

Test custom tooltip anchor

+

+ The JSON Schema error tooltips and the color picker should have correct placing and overflow the editor, also in combination with scrolling. +

+ +
+
+
+
+ + + +