import { isFunction, isArray, isObject, isString, isNumber, isUndefined, each, keys, filter } from 'lodash'; import $ from 'jquery'; import './json-view-interactive.less'; function isPrimitive(value) { return (value === null) || (value === false) || (value === true) || (isNumber(value) && isFinite(value)); } function combine(...functions) { functions = filter(functions, isFunction); return (...args) => { each(functions, (fn) => { fn(...args); }); }; } function initToggle(toggle, toggleBlockFn) { if (isFunction(toggleBlockFn)) { let visible = false; const icon = $('').addClass('fa fa-caret-right').appendTo(toggle.empty()); toggleBlockFn(visible); toggle.on('click', () => { visible = !visible; icon.toggleClass('fa-caret-right fa-caret-down'); toggleBlockFn(visible); }); } else { toggle.addClass('hidden'); } } function createRenderNestedBlock(block, ellipsis, values, renderKeys) { return (show) => { if (show) { ellipsis.addClass('hidden'); block.removeClass('hidden').empty(); let firstItem = null; let lastItem = null; each(values, (val, key) => { const nestedBlock = $('').addClass('jvi-item').appendTo(block); firstItem = firstItem || nestedBlock; lastItem = nestedBlock; const toggle = $('').addClass('jvi-toggle').appendTo(nestedBlock); if (renderKeys) { const keyWrapper = $('').addClass('jvi-object-key').appendTo(nestedBlock); // eslint-disable-next-line no-use-before-define renderString(keyWrapper, key); $('').addClass('jvi-punctuation').text(': ').appendTo(nestedBlock); } // eslint-disable-next-line no-use-before-define const toggleBlockFn = renderValue(nestedBlock, val, true); initToggle(toggle, toggleBlockFn); }); if (firstItem) { firstItem.addClass('jvi-nested-first'); } if (lastItem) { lastItem.addClass('jvi-nested-last'); } } else { block.addClass('hidden').empty(); ellipsis.removeClass('hidden'); } }; } function renderComma($element) { return $('').addClass('jvi-punctuation jvi-comma').text(',').appendTo($element); } function renderEllipsis($element) { const result = $('') .addClass('jvi-punctuation jvi-ellipsis') .html('…') .appendTo($element) .on('click', () => { result.parents('.jvi-item').eq(0).find('.jvi-toggle').trigger('click'); }); return result; } function renderPrimitive($element, value, comma) { $('').addClass('jvi-value jvi-primitive').text('' + value).appendTo($element); if (comma) { renderComma($element); } return null; } function renderString($element, value, comma) { $('').addClass('jvi-punctuation jvi-string').text('"').appendTo($element); $('').addClass('jvi-value jvi-string').text(value).appendTo($element); $('').addClass('jvi-punctuation jvi-string').text('"').appendTo($element); if (comma) { renderComma($element); } return null; } function renderComment($element, count) { const text = ' // ' + count + ' ' + (count === 1 ? 'item' : 'items'); const comment = $('').addClass('jvi-comment').text(text).appendTo($element); return (show) => { if (show) { comment.addClass('hidden'); } else { comment.removeClass('hidden'); } }; } function renderBrace($element, isForArray, isOpening) { const openingBrace = isForArray ? '[' : '{'; const closingBrace = isForArray ? ']' : '}'; const brace = isOpening ? openingBrace : closingBrace; return $('').addClass('jvi-punctuation jvi-braces').text(brace).appendTo($element); } function renderWithNested($element, values, comma, valuesIsArray) { const count = valuesIsArray ? values.length : keys(values).length; let result = null; renderBrace($element, valuesIsArray, true); if (count > 0) { const ellipsis = renderEllipsis($element); const block = $('').addClass('jvi-block hidden').appendTo($element); result = createRenderNestedBlock(block, ellipsis, values, !valuesIsArray); } renderBrace($element, valuesIsArray, false); if (comma) { renderComma($element); } if (count > 0) { result = combine(renderComment($element, count), result); } return result; } function renderArray($element, values, comma) { return renderWithNested($element, values, comma, true); } function renderObject($element, value, comma) { return renderWithNested($element, value, comma, false); } function renderValue($element, value, comma) { $element = $('').appendTo($element); if (isPrimitive(value)) { return renderPrimitive($element, value, comma); } else if (isString(value)) { return renderString($element, value, comma); } else if (isArray(value)) { return renderArray($element, value, comma); } else if (isObject(value)) { return renderObject($element, value, comma); } } export default function renderJsonView(container, value) { if ((container instanceof $) && !isUndefined(value) && !isFunction(value)) { const block = $('').addClass('jvi-item').appendTo(container); const toggle = $('').addClass('jvi-toggle').appendTo(block); const toggleBlockFn = renderValue(block, value); initToggle(toggle, toggleBlockFn); } }