mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat: moved json-formatter-js into core grafana to be able to make changes
This commit is contained in:
parent
f7a6c9a1e6
commit
5513d3c9d1
@ -68,7 +68,6 @@
|
|||||||
"grunt-jscs": "3.0.1",
|
"grunt-jscs": "3.0.1",
|
||||||
"grunt-sass-lint": "^0.2.2",
|
"grunt-sass-lint": "^0.2.2",
|
||||||
"grunt-sync": "^0.6.2",
|
"grunt-sync": "^0.6.2",
|
||||||
"json-formatter-js": "^2.2.0",
|
|
||||||
"karma-sinon": "^1.0.5",
|
"karma-sinon": "^1.0.5",
|
||||||
"lodash": "^4.17.2",
|
"lodash": "^4.17.2",
|
||||||
"mousetrap": "^1.6.0",
|
"mousetrap": "^1.6.0",
|
||||||
|
113
public/app/core/components/json_explorer/helpers.ts
Normal file
113
public/app/core/components/json_explorer/helpers.ts
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// Based on work https://github.com/mohsen1/json-formatter-js
|
||||||
|
// Licence MIT, Copyright (c) 2015 Mohsen Azimi
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Escapes `"` charachters from string
|
||||||
|
*/
|
||||||
|
function escapeString(str: string): string {
|
||||||
|
return str.replace('"', '\"');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determines if a value is an object
|
||||||
|
*/
|
||||||
|
export function isObject(value: any): boolean {
|
||||||
|
var type = typeof value;
|
||||||
|
return !!value && (type === 'object');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets constructor name of an object.
|
||||||
|
* From http://stackoverflow.com/a/332429
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function getObjectName(object: Object): string {
|
||||||
|
if (object === undefined) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (object === null) {
|
||||||
|
return 'Object';
|
||||||
|
}
|
||||||
|
if (typeof object === 'object' && !object.constructor) {
|
||||||
|
return 'Object';
|
||||||
|
}
|
||||||
|
|
||||||
|
const funcNameRegex = /function ([^(]*)/;
|
||||||
|
const results = (funcNameRegex).exec((object).constructor.toString());
|
||||||
|
if (results && results.length > 1) {
|
||||||
|
return results[1];
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets type of an object. Returns "null" for null objects
|
||||||
|
*/
|
||||||
|
export function getType(object: Object): string {
|
||||||
|
if (object === null) { return 'null'; }
|
||||||
|
return typeof object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates inline preview for a JavaScript object based on a value
|
||||||
|
*/
|
||||||
|
export function getValuePreview (object: Object, value: string): string {
|
||||||
|
var type = getType(object);
|
||||||
|
|
||||||
|
if (type === 'null' || type === 'undefined') { return type; }
|
||||||
|
|
||||||
|
if (type === 'string') {
|
||||||
|
value = '"' + escapeString(value) + '"';
|
||||||
|
}
|
||||||
|
if (type === 'function'){
|
||||||
|
|
||||||
|
// Remove content of the function
|
||||||
|
return object.toString()
|
||||||
|
.replace(/[\r\n]/g, '')
|
||||||
|
.replace(/\{.*\}/, '') + '{…}';
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates inline preview for a JavaScript object
|
||||||
|
*/
|
||||||
|
export function getPreview(object: string): string {
|
||||||
|
let value = '';
|
||||||
|
if (isObject(object)) {
|
||||||
|
value = getObjectName(object);
|
||||||
|
if (Array.isArray(object)) {
|
||||||
|
value += '[' + object.length + ']';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = getValuePreview(object, object);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates a prefixed CSS class name
|
||||||
|
*/
|
||||||
|
export function cssClass(className: string): string {
|
||||||
|
return `json-formatter-${className}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates a new DOM element wiht given type and class
|
||||||
|
* TODO: move me to helpers
|
||||||
|
*/
|
||||||
|
export function createElement(type: string, className?: string, content?: Element|string): Element {
|
||||||
|
const el = document.createElement(type);
|
||||||
|
if (className) {
|
||||||
|
el.classList.add(cssClass(className));
|
||||||
|
}
|
||||||
|
if (content !== undefined) {
|
||||||
|
if (content instanceof Node) {
|
||||||
|
el.appendChild(content);
|
||||||
|
} else {
|
||||||
|
el.appendChild(document.createTextNode(String(content)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return el;
|
||||||
|
}
|
454
public/app/core/components/json_explorer/json_explorer.ts
Normal file
454
public/app/core/components/json_explorer/json_explorer.ts
Normal file
@ -0,0 +1,454 @@
|
|||||||
|
// Based on work https://github.com/mohsen1/json-formatter-js
|
||||||
|
// Licence MIT, Copyright (c) 2015 Mohsen Azimi
|
||||||
|
|
||||||
|
import {
|
||||||
|
isObject,
|
||||||
|
getObjectName,
|
||||||
|
getType,
|
||||||
|
getValuePreview,
|
||||||
|
getPreview,
|
||||||
|
cssClass,
|
||||||
|
createElement
|
||||||
|
} from './helpers';
|
||||||
|
|
||||||
|
const DATE_STRING_REGEX = /(^\d{1,4}[\.|\\/|-]\d{1,2}[\.|\\/|-]\d{1,4})(\s*(?:0?[1-9]:[0-5]|1(?=[012])\d:[0-5])\d\s*[ap]m)?$/;
|
||||||
|
const PARTIAL_DATE_REGEX = /\d{2}:\d{2}:\d{2} GMT-\d{4}/;
|
||||||
|
const JSON_DATE_REGEX = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/;
|
||||||
|
|
||||||
|
// When toggleing, don't animated removal or addition of more than a few items
|
||||||
|
const MAX_ANIMATED_TOGGLE_ITEMS = 10;
|
||||||
|
|
||||||
|
const requestAnimationFrame = window.requestAnimationFrame || function(cb: ()=>void) { cb(); return 0; };
|
||||||
|
|
||||||
|
export interface JsonExplorerConfig {
|
||||||
|
hoverPreviewEnabled?: boolean;
|
||||||
|
hoverPreviewArrayCount?: number;
|
||||||
|
hoverPreviewFieldCount?: number;
|
||||||
|
animateOpen?: boolean;
|
||||||
|
animateClose?: boolean;
|
||||||
|
theme?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _defaultConfig: JsonExplorerConfig = {
|
||||||
|
hoverPreviewEnabled: false,
|
||||||
|
hoverPreviewArrayCount: 100,
|
||||||
|
hoverPreviewFieldCount: 5,
|
||||||
|
animateOpen: true,
|
||||||
|
animateClose: true,
|
||||||
|
theme: null
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class JsonExplorer
|
||||||
|
*
|
||||||
|
* JsonExplorer allows you to render JSON objects in HTML with a
|
||||||
|
* **collapsible** navigation.
|
||||||
|
*/
|
||||||
|
export default class JsonExplorer {
|
||||||
|
|
||||||
|
// Hold the open state after the toggler is used
|
||||||
|
private _isOpen: boolean = null;
|
||||||
|
|
||||||
|
// A reference to the element that we render to
|
||||||
|
private element: Element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} json The JSON object you want to render. It has to be an
|
||||||
|
* object or array. Do NOT pass raw JSON string.
|
||||||
|
*
|
||||||
|
* @param {number} [open=1] his number indicates up to how many levels the
|
||||||
|
* rendered tree should expand. Set it to `0` to make the whole tree collapsed
|
||||||
|
* or set it to `Infinity` to expand the tree deeply
|
||||||
|
*
|
||||||
|
* @param {object} [config=defaultConfig] -
|
||||||
|
* defaultConfig = {
|
||||||
|
* hoverPreviewEnabled: false,
|
||||||
|
* hoverPreviewArrayCount: 100,
|
||||||
|
* hoverPreviewFieldCount: 5
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Available configurations:
|
||||||
|
* #####Hover Preview
|
||||||
|
* * `hoverPreviewEnabled`: enable preview on hover
|
||||||
|
* * `hoverPreviewArrayCount`: number of array items to show in preview Any
|
||||||
|
* array larger than this number will be shown as `Array[XXX]` where `XXX`
|
||||||
|
* is length of the array.
|
||||||
|
* * `hoverPreviewFieldCount`: number of object properties to show for object
|
||||||
|
* preview. Any object with more properties that thin number will be
|
||||||
|
* truncated.
|
||||||
|
*
|
||||||
|
* @param {string} [key=undefined] The key that this object in it's parent
|
||||||
|
* context
|
||||||
|
*/
|
||||||
|
constructor(public json: any, private open = 1, private config: JsonExplorerConfig = _defaultConfig, private key?: string) {
|
||||||
|
|
||||||
|
// Setting default values for config object
|
||||||
|
if (this.config.hoverPreviewEnabled === undefined) {
|
||||||
|
this.config.hoverPreviewEnabled = _defaultConfig.hoverPreviewEnabled;
|
||||||
|
}
|
||||||
|
if (this.config.hoverPreviewArrayCount === undefined) {
|
||||||
|
this.config.hoverPreviewArrayCount = _defaultConfig.hoverPreviewArrayCount;
|
||||||
|
}
|
||||||
|
if (this.config.hoverPreviewFieldCount === undefined) {
|
||||||
|
this.config.hoverPreviewFieldCount = _defaultConfig.hoverPreviewFieldCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is formatter open?
|
||||||
|
*/
|
||||||
|
private get isOpen(): boolean {
|
||||||
|
if (this._isOpen !== null) {
|
||||||
|
return this._isOpen;
|
||||||
|
} else {
|
||||||
|
return this.open > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set open state (from toggler)
|
||||||
|
*/
|
||||||
|
private set isOpen(value: boolean) {
|
||||||
|
this._isOpen = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is this a date string?
|
||||||
|
*/
|
||||||
|
private get isDate(): boolean {
|
||||||
|
return (this.type === 'string') &&
|
||||||
|
(DATE_STRING_REGEX.test(this.json) ||
|
||||||
|
JSON_DATE_REGEX.test(this.json) ||
|
||||||
|
PARTIAL_DATE_REGEX.test(this.json));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is this a URL string?
|
||||||
|
*/
|
||||||
|
private get isUrl(): boolean {
|
||||||
|
return this.type === 'string' && (this.json.indexOf('http') === 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is this an array?
|
||||||
|
*/
|
||||||
|
private get isArray(): boolean {
|
||||||
|
return Array.isArray(this.json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is this an object?
|
||||||
|
* Note: In this context arrays are object as well
|
||||||
|
*/
|
||||||
|
private get isObject(): boolean {
|
||||||
|
return isObject(this.json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is this an empty object with no properties?
|
||||||
|
*/
|
||||||
|
private get isEmptyObject(): boolean {
|
||||||
|
return !this.keys.length && !this.isArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* is this an empty object or array?
|
||||||
|
*/
|
||||||
|
private get isEmpty(): boolean {
|
||||||
|
return this.isEmptyObject || (this.keys && !this.keys.length && this.isArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* did we recieve a key argument?
|
||||||
|
* This means that the formatter was called as a sub formatter of a parent formatter
|
||||||
|
*/
|
||||||
|
private get hasKey(): boolean {
|
||||||
|
return typeof this.key !== 'undefined';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if this is an object, get constructor function name
|
||||||
|
*/
|
||||||
|
private get constructorName(): string {
|
||||||
|
return getObjectName(this.json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get type of this value
|
||||||
|
* Possible values: all JavaScript primitive types plus "array" and "null"
|
||||||
|
*/
|
||||||
|
private get type(): string {
|
||||||
|
return getType(this.json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get object keys
|
||||||
|
* If there is an empty key we pad it wit quotes to make it visible
|
||||||
|
*/
|
||||||
|
private get keys(): string[] {
|
||||||
|
if (this.isObject) {
|
||||||
|
return Object.keys(this.json).map((key)=> key ? key : '""');
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles `isOpen` state
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
toggleOpen() {
|
||||||
|
this.isOpen = !this.isOpen;
|
||||||
|
|
||||||
|
if (this.element) {
|
||||||
|
if (this.isOpen) {
|
||||||
|
this.appendChildren(this.config.animateOpen);
|
||||||
|
} else{
|
||||||
|
this.removeChildren(this.config.animateClose);
|
||||||
|
}
|
||||||
|
this.element.classList.toggle(cssClass('open'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open all children up to a certain depth.
|
||||||
|
* Allows actions such as expand all/collapse all
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
openAtDepth(depth = 1) {
|
||||||
|
if (depth < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.open = depth;
|
||||||
|
this.isOpen = (depth !== 0);
|
||||||
|
|
||||||
|
if (this.element) {
|
||||||
|
this.removeChildren(false);
|
||||||
|
|
||||||
|
if (depth === 0) {
|
||||||
|
this.element.classList.remove(cssClass('open'));
|
||||||
|
} else {
|
||||||
|
this.appendChildren(this.config.animateOpen);
|
||||||
|
this.element.classList.add(cssClass('open'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates inline preview
|
||||||
|
*
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
getInlinepreview() {
|
||||||
|
if (this.isArray) {
|
||||||
|
|
||||||
|
// if array length is greater then 100 it shows "Array[101]"
|
||||||
|
if (this.json.length > this.config.hoverPreviewArrayCount) {
|
||||||
|
return `Array[${this.json.length}]`;
|
||||||
|
} else {
|
||||||
|
return `[${this.json.map(getPreview).join(', ')}]`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const keys = this.keys;
|
||||||
|
|
||||||
|
// the first five keys (like Chrome Developer Tool)
|
||||||
|
const narrowKeys = keys.slice(0, this.config.hoverPreviewFieldCount);
|
||||||
|
|
||||||
|
// json value schematic information
|
||||||
|
const kvs = narrowKeys.map(key => `${key}:${getPreview(this.json[key])}`);
|
||||||
|
|
||||||
|
// if keys count greater then 5 then show ellipsis
|
||||||
|
const ellipsis = keys.length >= this.config.hoverPreviewFieldCount ? '…' : '';
|
||||||
|
|
||||||
|
return `{${kvs.join(', ')}${ellipsis}}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders an HTML element and installs event listeners
|
||||||
|
*
|
||||||
|
* @returns {HTMLDivElement}
|
||||||
|
*/
|
||||||
|
render(): HTMLDivElement {
|
||||||
|
|
||||||
|
// construct the root element and assign it to this.element
|
||||||
|
this.element = createElement('div', 'row');
|
||||||
|
|
||||||
|
// construct the toggler link
|
||||||
|
const togglerLink = createElement('a', 'toggler-link');
|
||||||
|
|
||||||
|
// if this is an object we need a wrapper span (toggler)
|
||||||
|
if (this.isObject) {
|
||||||
|
togglerLink.appendChild(createElement('span', 'toggler'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this is child of a parent formatter we need to append the key
|
||||||
|
if (this.hasKey) {
|
||||||
|
togglerLink.appendChild(createElement('span', 'key', `${this.key}:`));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value for objects and arrays
|
||||||
|
if (this.isObject) {
|
||||||
|
|
||||||
|
// construct the value holder element
|
||||||
|
const value = createElement('span', 'value');
|
||||||
|
|
||||||
|
// we need a wrapper span for objects
|
||||||
|
const objectWrapperSpan = createElement('span');
|
||||||
|
|
||||||
|
// get constructor name and append it to wrapper span
|
||||||
|
var constructorName = createElement('span', 'constructor-name', this.constructorName);
|
||||||
|
objectWrapperSpan.appendChild(constructorName);
|
||||||
|
|
||||||
|
// if it's an array append the array specific elements like brackets and length
|
||||||
|
if (this.isArray) {
|
||||||
|
const arrayWrapperSpan = createElement('span');
|
||||||
|
arrayWrapperSpan.appendChild(createElement('span', 'bracket', '['));
|
||||||
|
arrayWrapperSpan.appendChild(createElement('span', 'number', (this.json.length)));
|
||||||
|
arrayWrapperSpan.appendChild(createElement('span', 'bracket', ']'));
|
||||||
|
objectWrapperSpan.appendChild(arrayWrapperSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
// append object wrapper span to toggler link
|
||||||
|
value.appendChild(objectWrapperSpan);
|
||||||
|
togglerLink.appendChild(value);
|
||||||
|
|
||||||
|
// Primitive values
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// make a value holder element
|
||||||
|
const value = this.isUrl ? createElement('a') : createElement('span');
|
||||||
|
|
||||||
|
// add type and other type related CSS classes
|
||||||
|
value.classList.add(cssClass(this.type));
|
||||||
|
if (this.isDate) {
|
||||||
|
value.classList.add(cssClass('date'));
|
||||||
|
}
|
||||||
|
if (this.isUrl) {
|
||||||
|
value.classList.add(cssClass('url'));
|
||||||
|
value.setAttribute('href', this.json);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append value content to value element
|
||||||
|
const valuePreview = getValuePreview(this.json, this.json);
|
||||||
|
value.appendChild(document.createTextNode(valuePreview));
|
||||||
|
|
||||||
|
// append the value element to toggler link
|
||||||
|
togglerLink.appendChild(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if hover preview is enabled, append the inline preview element
|
||||||
|
if (this.isObject && this.config.hoverPreviewEnabled) {
|
||||||
|
const preview = createElement('span', 'preview-text');
|
||||||
|
preview.appendChild(document.createTextNode(this.getInlinepreview()));
|
||||||
|
togglerLink.appendChild(preview);
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct a children element
|
||||||
|
const children = createElement('div', 'children');
|
||||||
|
|
||||||
|
// set CSS classes for children
|
||||||
|
if (this.isObject) {
|
||||||
|
children.classList.add(cssClass('object'));
|
||||||
|
}
|
||||||
|
if (this.isArray) {
|
||||||
|
children.classList.add(cssClass('array'));
|
||||||
|
}
|
||||||
|
if (this.isEmpty) {
|
||||||
|
children.classList.add(cssClass('empty'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// set CSS classes for root element
|
||||||
|
if (this.config && this.config.theme) {
|
||||||
|
this.element.classList.add(cssClass(this.config.theme));
|
||||||
|
}
|
||||||
|
if (this.isOpen) {
|
||||||
|
this.element.classList.add(cssClass('open'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// append toggler and children elements to root element
|
||||||
|
this.element.appendChild(togglerLink);
|
||||||
|
this.element.appendChild(children);
|
||||||
|
|
||||||
|
// if formatter is set to be open call appendChildren
|
||||||
|
if (this.isObject && this.isOpen) {
|
||||||
|
this.appendChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add event listener for toggling
|
||||||
|
if (this.isObject) {
|
||||||
|
togglerLink.addEventListener('click', this.toggleOpen.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.element as HTMLDivElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends all the children to children element
|
||||||
|
* Animated option is used when user triggers this via a click
|
||||||
|
*/
|
||||||
|
appendChildren(animated = false) {
|
||||||
|
const children = this.element.querySelector(`div.${cssClass('children')}`);
|
||||||
|
|
||||||
|
if (!children || this.isEmpty) { return; }
|
||||||
|
|
||||||
|
if (animated) {
|
||||||
|
let index = 0;
|
||||||
|
const addAChild = ()=> {
|
||||||
|
const key = this.keys[index];
|
||||||
|
const formatter = new JsonExplorer(this.json[key], this.open - 1, this.config, key);
|
||||||
|
children.appendChild(formatter.render());
|
||||||
|
|
||||||
|
index += 1;
|
||||||
|
|
||||||
|
if (index < this.keys.length) {
|
||||||
|
if (index > MAX_ANIMATED_TOGGLE_ITEMS) {
|
||||||
|
addAChild();
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(addAChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
requestAnimationFrame(addAChild);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.keys.forEach(key => {
|
||||||
|
const formatter = new JsonExplorer(this.json[key], this.open - 1, this.config, key);
|
||||||
|
children.appendChild(formatter.render());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all the children from children element
|
||||||
|
* Animated option is used when user triggers this via a click
|
||||||
|
*/
|
||||||
|
removeChildren(animated = false) {
|
||||||
|
const childrenElement = this.element.querySelector(`div.${cssClass('children')}`) as HTMLDivElement;
|
||||||
|
|
||||||
|
if (animated) {
|
||||||
|
let childrenRemoved = 0;
|
||||||
|
const removeAChild = ()=> {
|
||||||
|
if (childrenElement && childrenElement.children.length) {
|
||||||
|
childrenElement.removeChild(childrenElement.children[0]);
|
||||||
|
childrenRemoved += 1;
|
||||||
|
if (childrenRemoved > MAX_ANIMATED_TOGGLE_ITEMS) {
|
||||||
|
removeAChild();
|
||||||
|
} else {
|
||||||
|
requestAnimationFrame(removeAChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
requestAnimationFrame(removeAChild);
|
||||||
|
} else {
|
||||||
|
if (childrenElement) {
|
||||||
|
childrenElement.innerHTML = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,110 +0,0 @@
|
|||||||
// #<{(|
|
|
||||||
// * Escapes `"` charachters from string
|
|
||||||
// |)}>#
|
|
||||||
// function escapeString(str: string): string {
|
|
||||||
// return str.replace('"', '\"');
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * Determines if a value is an object
|
|
||||||
// |)}>#
|
|
||||||
// export function isObject(value: any): boolean {
|
|
||||||
// var type = typeof value;
|
|
||||||
// return !!value && (type === 'object');
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * Gets constructor name of an object.
|
|
||||||
// * From http://stackoverflow.com/a/332429
|
|
||||||
// *
|
|
||||||
// |)}>#
|
|
||||||
// export function getObjectName(object: Object): string {
|
|
||||||
// if (object === undefined) {
|
|
||||||
// return '';
|
|
||||||
// }
|
|
||||||
// if (object === null) {
|
|
||||||
// return 'Object';
|
|
||||||
// }
|
|
||||||
// if (typeof object === 'object' && !object.constructor) {
|
|
||||||
// return 'Object';
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// const funcNameRegex = /function ([^(]*)/;
|
|
||||||
// const results = (funcNameRegex).exec((object).constructor.toString());
|
|
||||||
// if (results && results.length > 1) {
|
|
||||||
// return results[1];
|
|
||||||
// } else {
|
|
||||||
// return '';
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * Gets type of an object. Returns "null" for null objects
|
|
||||||
// |)}>#
|
|
||||||
// export function getType(object: Object): string {
|
|
||||||
// if (object === null) { return 'null'; }
|
|
||||||
// return typeof object;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * Generates inline preview for a JavaScript object based on a value
|
|
||||||
// |)}>#
|
|
||||||
// export function getValuePreview (object: Object, value: string): string {
|
|
||||||
// var type = getType(object);
|
|
||||||
//
|
|
||||||
// if (type === 'null' || type === 'undefined') { return type; }
|
|
||||||
//
|
|
||||||
// if (type === 'string') {
|
|
||||||
// value = '"' + escapeString(value) + '"';
|
|
||||||
// }
|
|
||||||
// if (type === 'function'){
|
|
||||||
//
|
|
||||||
// // Remove content of the function
|
|
||||||
// return object.toString()
|
|
||||||
// .replace(/[\r\n]/g, '')
|
|
||||||
// .replace(/\{.*\}/, '') + '{…}';
|
|
||||||
// }
|
|
||||||
// return value;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * Generates inline preview for a JavaScript object
|
|
||||||
// |)}>#
|
|
||||||
// export function getPreview(object: string): string {
|
|
||||||
// let value = '';
|
|
||||||
// if (isObject(object)) {
|
|
||||||
// value = getObjectName(object);
|
|
||||||
// if (Array.isArray(object)) {
|
|
||||||
// value += '[' + object.length + ']';
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// value = getValuePreview(object, object);
|
|
||||||
// }
|
|
||||||
// return value;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * Generates a prefixed CSS class name
|
|
||||||
// |)}>#
|
|
||||||
// export function cssClass(className: string): string {
|
|
||||||
// return `json-formatter-${className}`;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * Creates a new DOM element wiht given type and class
|
|
||||||
// * TODO: move me to helpers
|
|
||||||
// |)}>#
|
|
||||||
// export function createElement(type: string, className?: string, content?: Element|string): Element {
|
|
||||||
// const el = document.createElement(type);
|
|
||||||
// if (className) {
|
|
||||||
// el.classList.add(cssClass(className));
|
|
||||||
// }
|
|
||||||
// if (content !== undefined) {
|
|
||||||
// if (content instanceof Node) {
|
|
||||||
// el.appendChild(content);
|
|
||||||
// } else {
|
|
||||||
// el.appendChild(document.createTextNode(String(content)));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return el;
|
|
||||||
// }
|
|
@ -1,453 +0,0 @@
|
|||||||
// import {
|
|
||||||
// isObject,
|
|
||||||
// getObjectName,
|
|
||||||
// getType,
|
|
||||||
// getValuePreview,
|
|
||||||
// getPreview,
|
|
||||||
// cssClass,
|
|
||||||
// createElement
|
|
||||||
// } from './helpers';
|
|
||||||
//
|
|
||||||
// import './style.less';
|
|
||||||
//
|
|
||||||
// const DATE_STRING_REGEX = /(^\d{1,4}[\.|\\/|-]\d{1,2}[\.|\\/|-]\d{1,4})(\s*(?:0?[1-9]:[0-5]|1(?=[012])\d:[0-5])\d\s*[ap]m)?$/;
|
|
||||||
// const PARTIAL_DATE_REGEX = /\d{2}:\d{2}:\d{2} GMT-\d{4}/;
|
|
||||||
// const JSON_DATE_REGEX = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/;
|
|
||||||
//
|
|
||||||
// // When toggleing, don't animated removal or addition of more than a few items
|
|
||||||
// const MAX_ANIMATED_TOGGLE_ITEMS = 10;
|
|
||||||
//
|
|
||||||
// const requestAnimationFrame = window.requestAnimationFrame || function(cb: ()=>void) { cb(); return 0; };
|
|
||||||
//
|
|
||||||
// export interface JSONFormatterConfiguration {
|
|
||||||
// hoverPreviewEnabled?: boolean;
|
|
||||||
// hoverPreviewArrayCount?: number;
|
|
||||||
// hoverPreviewFieldCount?: number;
|
|
||||||
// animateOpen?: boolean;
|
|
||||||
// animateClose?: boolean;
|
|
||||||
// theme?: string;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// const _defaultConfig: JSONFormatterConfiguration = {
|
|
||||||
// hoverPreviewEnabled: false,
|
|
||||||
// hoverPreviewArrayCount: 100,
|
|
||||||
// hoverPreviewFieldCount: 5,
|
|
||||||
// animateOpen: true,
|
|
||||||
// animateClose: true,
|
|
||||||
// theme: null
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// #<{(|*
|
|
||||||
// * @class JSONFormatter
|
|
||||||
// *
|
|
||||||
// * JSONFormatter allows you to render JSON objects in HTML with a
|
|
||||||
// * **collapsible** navigation.
|
|
||||||
// |)}>#
|
|
||||||
// export default class JSONFormatter {
|
|
||||||
//
|
|
||||||
// // Hold the open state after the toggler is used
|
|
||||||
// private _isOpen: boolean = null;
|
|
||||||
//
|
|
||||||
// // A reference to the element that we render to
|
|
||||||
// private element: Element;
|
|
||||||
//
|
|
||||||
// #<{(|*
|
|
||||||
// * @param {object} json The JSON object you want to render. It has to be an
|
|
||||||
// * object or array. Do NOT pass raw JSON string.
|
|
||||||
// *
|
|
||||||
// * @param {number} [open=1] his number indicates up to how many levels the
|
|
||||||
// * rendered tree should expand. Set it to `0` to make the whole tree collapsed
|
|
||||||
// * or set it to `Infinity` to expand the tree deeply
|
|
||||||
// *
|
|
||||||
// * @param {object} [config=defaultConfig] -
|
|
||||||
// * defaultConfig = {
|
|
||||||
// * hoverPreviewEnabled: false,
|
|
||||||
// * hoverPreviewArrayCount: 100,
|
|
||||||
// * hoverPreviewFieldCount: 5
|
|
||||||
// * }
|
|
||||||
// *
|
|
||||||
// * Available configurations:
|
|
||||||
// * #####Hover Preview
|
|
||||||
// * * `hoverPreviewEnabled`: enable preview on hover
|
|
||||||
// * * `hoverPreviewArrayCount`: number of array items to show in preview Any
|
|
||||||
// * array larger than this number will be shown as `Array[XXX]` where `XXX`
|
|
||||||
// * is length of the array.
|
|
||||||
// * * `hoverPreviewFieldCount`: number of object properties to show for object
|
|
||||||
// * preview. Any object with more properties that thin number will be
|
|
||||||
// * truncated.
|
|
||||||
// *
|
|
||||||
// * @param {string} [key=undefined] The key that this object in it's parent
|
|
||||||
// * context
|
|
||||||
// |)}>#
|
|
||||||
// constructor(public json: any, private open = 1, private config: JSONFormatterConfiguration = _defaultConfig, private key?: string) {
|
|
||||||
//
|
|
||||||
// // Setting default values for config object
|
|
||||||
// if (this.config.hoverPreviewEnabled === undefined) {
|
|
||||||
// this.config.hoverPreviewEnabled = _defaultConfig.hoverPreviewEnabled;
|
|
||||||
// }
|
|
||||||
// if (this.config.hoverPreviewArrayCount === undefined) {
|
|
||||||
// this.config.hoverPreviewArrayCount = _defaultConfig.hoverPreviewArrayCount;
|
|
||||||
// }
|
|
||||||
// if (this.config.hoverPreviewFieldCount === undefined) {
|
|
||||||
// this.config.hoverPreviewFieldCount = _defaultConfig.hoverPreviewFieldCount;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * is formatter open?
|
|
||||||
// |)}>#
|
|
||||||
// private get isOpen(): boolean {
|
|
||||||
// if (this._isOpen !== null) {
|
|
||||||
// return this._isOpen;
|
|
||||||
// } else {
|
|
||||||
// return this.open > 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * set open state (from toggler)
|
|
||||||
// |)}>#
|
|
||||||
// private set isOpen(value: boolean) {
|
|
||||||
// this._isOpen = value;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * is this a date string?
|
|
||||||
// |)}>#
|
|
||||||
// private get isDate(): boolean {
|
|
||||||
// return (this.type === 'string') &&
|
|
||||||
// (DATE_STRING_REGEX.test(this.json) ||
|
|
||||||
// JSON_DATE_REGEX.test(this.json) ||
|
|
||||||
// PARTIAL_DATE_REGEX.test(this.json));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * is this a URL string?
|
|
||||||
// |)}>#
|
|
||||||
// private get isUrl(): boolean {
|
|
||||||
// return this.type === 'string' && (this.json.indexOf('http') === 0);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * is this an array?
|
|
||||||
// |)}>#
|
|
||||||
// private get isArray(): boolean {
|
|
||||||
// return Array.isArray(this.json);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * is this an object?
|
|
||||||
// * Note: In this context arrays are object as well
|
|
||||||
// |)}>#
|
|
||||||
// private get isObject(): boolean {
|
|
||||||
// return isObject(this.json);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * is this an empty object with no properties?
|
|
||||||
// |)}>#
|
|
||||||
// private get isEmptyObject(): boolean {
|
|
||||||
// return !this.keys.length && !this.isArray;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * is this an empty object or array?
|
|
||||||
// |)}>#
|
|
||||||
// private get isEmpty(): boolean {
|
|
||||||
// return this.isEmptyObject || (this.keys && !this.keys.length && this.isArray);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * did we recieve a key argument?
|
|
||||||
// * This means that the formatter was called as a sub formatter of a parent formatter
|
|
||||||
// |)}>#
|
|
||||||
// private get hasKey(): boolean {
|
|
||||||
// return typeof this.key !== 'undefined';
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * if this is an object, get constructor function name
|
|
||||||
// |)}>#
|
|
||||||
// private get constructorName(): string {
|
|
||||||
// return getObjectName(this.json);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * get type of this value
|
|
||||||
// * Possible values: all JavaScript primitive types plus "array" and "null"
|
|
||||||
// |)}>#
|
|
||||||
// private get type(): string {
|
|
||||||
// return getType(this.json);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|
|
|
||||||
// * get object keys
|
|
||||||
// * If there is an empty key we pad it wit quotes to make it visible
|
|
||||||
// |)}>#
|
|
||||||
// private get keys(): string[] {
|
|
||||||
// if (this.isObject) {
|
|
||||||
// return Object.keys(this.json).map((key)=> key ? key : '""');
|
|
||||||
// } else {
|
|
||||||
// return [];
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|*
|
|
||||||
// * Toggles `isOpen` state
|
|
||||||
// *
|
|
||||||
// |)}>#
|
|
||||||
// toggleOpen() {
|
|
||||||
// this.isOpen = !this.isOpen;
|
|
||||||
//
|
|
||||||
// if (this.element) {
|
|
||||||
// if (this.isOpen) {
|
|
||||||
// this.appendChildren(this.config.animateOpen);
|
|
||||||
// } else{
|
|
||||||
// this.removeChildren(this.config.animateClose);
|
|
||||||
// }
|
|
||||||
// this.element.classList.toggle(cssClass('open'));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|*
|
|
||||||
// * Open all children up to a certain depth.
|
|
||||||
// * Allows actions such as expand all/collapse all
|
|
||||||
// *
|
|
||||||
// |)}>#
|
|
||||||
// openAtDepth(depth = 1) {
|
|
||||||
// if (depth < 0) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// this.open = depth;
|
|
||||||
// this.isOpen = (depth !== 0);
|
|
||||||
//
|
|
||||||
// if (this.element) {
|
|
||||||
// this.removeChildren(false);
|
|
||||||
//
|
|
||||||
// if (depth === 0) {
|
|
||||||
// this.element.classList.remove(cssClass('open'));
|
|
||||||
// } else {
|
|
||||||
// this.appendChildren(this.config.animateOpen);
|
|
||||||
// this.element.classList.add(cssClass('open'));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|*
|
|
||||||
// * Generates inline preview
|
|
||||||
// *
|
|
||||||
// * @returns {string}
|
|
||||||
// |)}>#
|
|
||||||
// getInlinepreview() {
|
|
||||||
// if (this.isArray) {
|
|
||||||
//
|
|
||||||
// // if array length is greater then 100 it shows "Array[101]"
|
|
||||||
// if (this.json.length > this.config.hoverPreviewArrayCount) {
|
|
||||||
// return `Array[${this.json.length}]`;
|
|
||||||
// } else {
|
|
||||||
// return `[${this.json.map(getPreview).join(', ')}]`;
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
//
|
|
||||||
// const keys = this.keys;
|
|
||||||
//
|
|
||||||
// // the first five keys (like Chrome Developer Tool)
|
|
||||||
// const narrowKeys = keys.slice(0, this.config.hoverPreviewFieldCount);
|
|
||||||
//
|
|
||||||
// // json value schematic information
|
|
||||||
// const kvs = narrowKeys.map(key => `${key}:${getPreview(this.json[key])}`);
|
|
||||||
//
|
|
||||||
// // if keys count greater then 5 then show ellipsis
|
|
||||||
// const ellipsis = keys.length >= this.config.hoverPreviewFieldCount ? '…' : '';
|
|
||||||
//
|
|
||||||
// return `{${kvs.join(', ')}${ellipsis}}`;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// #<{(|*
|
|
||||||
// * Renders an HTML element and installs event listeners
|
|
||||||
// *
|
|
||||||
// * @returns {HTMLDivElement}
|
|
||||||
// |)}>#
|
|
||||||
// render(): HTMLDivElement {
|
|
||||||
//
|
|
||||||
// // construct the root element and assign it to this.element
|
|
||||||
// this.element = createElement('div', 'row');
|
|
||||||
//
|
|
||||||
// // construct the toggler link
|
|
||||||
// const togglerLink = createElement('a', 'toggler-link');
|
|
||||||
//
|
|
||||||
// // if this is an object we need a wrapper span (toggler)
|
|
||||||
// if (this.isObject) {
|
|
||||||
// togglerLink.appendChild(createElement('span', 'toggler'));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // if this is child of a parent formatter we need to append the key
|
|
||||||
// if (this.hasKey) {
|
|
||||||
// togglerLink.appendChild(createElement('span', 'key', `${this.key}:`));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Value for objects and arrays
|
|
||||||
// if (this.isObject) {
|
|
||||||
//
|
|
||||||
// // construct the value holder element
|
|
||||||
// const value = createElement('span', 'value');
|
|
||||||
//
|
|
||||||
// // we need a wrapper span for objects
|
|
||||||
// const objectWrapperSpan = createElement('span');
|
|
||||||
//
|
|
||||||
// // get constructor name and append it to wrapper span
|
|
||||||
// var constructorName = createElement('span', 'constructor-name', this.constructorName);
|
|
||||||
// objectWrapperSpan.appendChild(constructorName);
|
|
||||||
//
|
|
||||||
// // if it's an array append the array specific elements like brackets and length
|
|
||||||
// if (this.isArray) {
|
|
||||||
// const arrayWrapperSpan = createElement('span');
|
|
||||||
// arrayWrapperSpan.appendChild(createElement('span', 'bracket', '['));
|
|
||||||
// arrayWrapperSpan.appendChild(createElement('span', 'number', (this.json.length)));
|
|
||||||
// arrayWrapperSpan.appendChild(createElement('span', 'bracket', ']'));
|
|
||||||
// objectWrapperSpan.appendChild(arrayWrapperSpan);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // append object wrapper span to toggler link
|
|
||||||
// value.appendChild(objectWrapperSpan);
|
|
||||||
// togglerLink.appendChild(value);
|
|
||||||
//
|
|
||||||
// // Primitive values
|
|
||||||
// } else {
|
|
||||||
//
|
|
||||||
// // make a value holder element
|
|
||||||
// const value = this.isUrl ? createElement('a') : createElement('span');
|
|
||||||
//
|
|
||||||
// // add type and other type related CSS classes
|
|
||||||
// value.classList.add(cssClass(this.type));
|
|
||||||
// if (this.isDate) {
|
|
||||||
// value.classList.add(cssClass('date'));
|
|
||||||
// }
|
|
||||||
// if (this.isUrl) {
|
|
||||||
// value.classList.add(cssClass('url'));
|
|
||||||
// value.setAttribute('href', this.json);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Append value content to value element
|
|
||||||
// const valuePreview = getValuePreview(this.json, this.json);
|
|
||||||
// value.appendChild(document.createTextNode(valuePreview));
|
|
||||||
//
|
|
||||||
// // append the value element to toggler link
|
|
||||||
// togglerLink.appendChild(value);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // if hover preview is enabled, append the inline preview element
|
|
||||||
// if (this.isObject && this.config.hoverPreviewEnabled) {
|
|
||||||
// const preview = createElement('span', 'preview-text');
|
|
||||||
// preview.appendChild(document.createTextNode(this.getInlinepreview()));
|
|
||||||
// togglerLink.appendChild(preview);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // construct a children element
|
|
||||||
// const children = createElement('div', 'children');
|
|
||||||
//
|
|
||||||
// // set CSS classes for children
|
|
||||||
// if (this.isObject) {
|
|
||||||
// children.classList.add(cssClass('object'));
|
|
||||||
// }
|
|
||||||
// if (this.isArray) {
|
|
||||||
// children.classList.add(cssClass('array'));
|
|
||||||
// }
|
|
||||||
// if (this.isEmpty) {
|
|
||||||
// children.classList.add(cssClass('empty'));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // set CSS classes for root element
|
|
||||||
// if (this.config && this.config.theme) {
|
|
||||||
// this.element.classList.add(cssClass(this.config.theme));
|
|
||||||
// }
|
|
||||||
// if (this.isOpen) {
|
|
||||||
// this.element.classList.add(cssClass('open'));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // append toggler and children elements to root element
|
|
||||||
// this.element.appendChild(togglerLink);
|
|
||||||
// this.element.appendChild(children);
|
|
||||||
//
|
|
||||||
// // if formatter is set to be open call appendChildren
|
|
||||||
// if (this.isObject && this.isOpen) {
|
|
||||||
// this.appendChildren();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // add event listener for toggling
|
|
||||||
// if (this.isObject) {
|
|
||||||
// togglerLink.addEventListener('click', this.toggleOpen.bind(this));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return this.element as HTMLDivElement;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|*
|
|
||||||
// * Appends all the children to children element
|
|
||||||
// * Animated option is used when user triggers this via a click
|
|
||||||
// |)}>#
|
|
||||||
// appendChildren(animated = false) {
|
|
||||||
// const children = this.element.querySelector(`div.${cssClass('children')}`);
|
|
||||||
//
|
|
||||||
// if (!children || this.isEmpty) { return; }
|
|
||||||
//
|
|
||||||
// if (animated) {
|
|
||||||
// let index = 0;
|
|
||||||
// const addAChild = ()=> {
|
|
||||||
// const key = this.keys[index];
|
|
||||||
// const formatter = new JSONFormatter(this.json[key], this.open - 1, this.config, key);
|
|
||||||
// children.appendChild(formatter.render());
|
|
||||||
//
|
|
||||||
// index += 1;
|
|
||||||
//
|
|
||||||
// if (index < this.keys.length) {
|
|
||||||
// if (index > MAX_ANIMATED_TOGGLE_ITEMS) {
|
|
||||||
// addAChild();
|
|
||||||
// } else {
|
|
||||||
// requestAnimationFrame(addAChild);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// requestAnimationFrame(addAChild);
|
|
||||||
//
|
|
||||||
// } else {
|
|
||||||
// this.keys.forEach(key => {
|
|
||||||
// const formatter = new JSONFormatter(this.json[key], this.open - 1, this.config, key);
|
|
||||||
// children.appendChild(formatter.render());
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #<{(|*
|
|
||||||
// * Removes all the children from children element
|
|
||||||
// * Animated option is used when user triggers this via a click
|
|
||||||
// |)}>#
|
|
||||||
// removeChildren(animated = false) {
|
|
||||||
// const childrenElement = this.element.querySelector(`div.${cssClass('children')}`) as HTMLDivElement;
|
|
||||||
//
|
|
||||||
// if (animated) {
|
|
||||||
// let childrenRemoved = 0;
|
|
||||||
// const removeAChild = ()=> {
|
|
||||||
// if (childrenElement && childrenElement.children.length) {
|
|
||||||
// childrenElement.removeChild(childrenElement.children[0]);
|
|
||||||
// childrenRemoved += 1;
|
|
||||||
// if (childrenRemoved > MAX_ANIMATED_TOGGLE_ITEMS) {
|
|
||||||
// removeAChild();
|
|
||||||
// } else {
|
|
||||||
// requestAnimationFrame(removeAChild);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// requestAnimationFrame(removeAChild);
|
|
||||||
// } else {
|
|
||||||
// if (childrenElement) {
|
|
||||||
// childrenElement.innerHTML = '';
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -1,7 +1,7 @@
|
|||||||
///<reference path="../../headers/common.d.ts" />
|
///<reference path="../../headers/common.d.ts" />
|
||||||
|
|
||||||
import coreModule from 'app/core/core_module';
|
import coreModule from 'app/core/core_module';
|
||||||
import JsonFormatter from 'json-formatter-js';
|
import JsonExplorer from './json_explorer/json_explorer';
|
||||||
|
|
||||||
|
|
||||||
const template = `
|
const template = `
|
||||||
@ -48,7 +48,7 @@ export function responseViewer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const formatter = new JsonFormatter(scope.response, 2, {
|
const formatter = new JsonExplorer(scope.response, 2, {
|
||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ System.config({
|
|||||||
"jquery.flot.gauge": "vendor/flot/jquery.flot.gauge",
|
"jquery.flot.gauge": "vendor/flot/jquery.flot.gauge",
|
||||||
"d3": "vendor/d3/d3.js",
|
"d3": "vendor/d3/d3.js",
|
||||||
"jquery.flot.dashes": "vendor/flot/jquery.flot.dashes",
|
"jquery.flot.dashes": "vendor/flot/jquery.flot.dashes",
|
||||||
"json-formatter-js": "vendor/npm/json-formatter-js/dist/json-formatter"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
packages: {
|
packages: {
|
||||||
|
@ -76,6 +76,7 @@
|
|||||||
@import "components/edit_sidemenu.scss";
|
@import "components/edit_sidemenu.scss";
|
||||||
@import "components/row.scss";
|
@import "components/row.scss";
|
||||||
@import "components/response_viewer.scss";
|
@import "components/response_viewer.scss";
|
||||||
|
@import "components/json_explorer.scss";
|
||||||
|
|
||||||
// PAGES
|
// PAGES
|
||||||
@import "pages/login";
|
@import "pages/login";
|
||||||
|
128
public/sass/components/_json_explorer.scss
Normal file
128
public/sass/components/_json_explorer.scss
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
@mixin json-explorer-theme(
|
||||||
|
$default-color: black,
|
||||||
|
$string-color: green,
|
||||||
|
$number-color: blue,
|
||||||
|
$boolean-color: red,
|
||||||
|
$null-color: #855A00,
|
||||||
|
$undefined-color: rgb(202, 11, 105),
|
||||||
|
$function-color: #FF20ED,
|
||||||
|
$rotate-time: 100ms,
|
||||||
|
$toggler-opacity: 0.6,
|
||||||
|
$toggler-color: #45376F,
|
||||||
|
$bracket-color: blue,
|
||||||
|
$key-color: #00008B,
|
||||||
|
$url-color: blue) {
|
||||||
|
|
||||||
|
font-family: monospace;
|
||||||
|
&, a, a:hover {
|
||||||
|
color: $default-color;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-formatter-row {
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-formatter-children {
|
||||||
|
&.json-formatter-empty {
|
||||||
|
opacity: 0.5;
|
||||||
|
margin-left: 1rem;
|
||||||
|
|
||||||
|
&::after { display: none; }
|
||||||
|
&.json-formatter-object::after { content: "No properties"; }
|
||||||
|
&.json-formatter-array::after { content: "[]"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-formatter-string {
|
||||||
|
color: $string-color;
|
||||||
|
white-space: pre;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
.json-formatter-number { color: $number-color; }
|
||||||
|
.json-formatter-boolean { color: $boolean-color; }
|
||||||
|
.json-formatter-null { color: $null-color; }
|
||||||
|
.json-formatter-undefined { color: $undefined-color; }
|
||||||
|
.json-formatter-function { color: $function-color; }
|
||||||
|
.json-formatter-date { background-color: fade($default-color, 5%); }
|
||||||
|
.json-formatter-url {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: $url-color;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-formatter-bracket { color: $bracket-color; }
|
||||||
|
.json-formatter-key {
|
||||||
|
color: $key-color;
|
||||||
|
cursor: pointer;
|
||||||
|
padding-right: 0.2rem;
|
||||||
|
}
|
||||||
|
.json-formatter-constructor-name {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.json-formatter-toggler {
|
||||||
|
line-height: 1.2rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
opacity: $toggler-opacity;
|
||||||
|
cursor: pointer;
|
||||||
|
padding-right: 0.2rem;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
display: inline-block;
|
||||||
|
transition: transform $rotate-time ease-in;
|
||||||
|
content: "►";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inline preview on hover (optional)
|
||||||
|
> a > .json-formatter-preview-text {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity .15s ease-in;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover > a > .json-formatter-preview-text {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open state
|
||||||
|
&.json-formatter-open {
|
||||||
|
> .json-formatter-toggler-link .json-formatter-toggler::after{
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
> .json-formatter-children::after {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
> a > .json-formatter-preview-text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.json-formatter-empty::after {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.json-formatter-row {
|
||||||
|
@include json-explorer-theme();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dark theme
|
||||||
|
.json-formatter-dark.json-formatter-row {
|
||||||
|
@include json-explorer-theme(
|
||||||
|
$default-color: white,
|
||||||
|
$string-color: #31F031,
|
||||||
|
$number-color: #66C2FF,
|
||||||
|
$boolean-color: #EC4242,
|
||||||
|
$null-color: #EEC97D,
|
||||||
|
$undefined-color: rgb(239, 143, 190),
|
||||||
|
$function-color: #FD48CB,
|
||||||
|
$rotate-time: 100ms,
|
||||||
|
$toggler-opacity: 0.6,
|
||||||
|
$toggler-color: #45376F,
|
||||||
|
$bracket-color: #9494FF,
|
||||||
|
$key-color: #23A0DB,
|
||||||
|
$url-color: #027BFF);
|
||||||
|
}
|
@ -41,7 +41,6 @@
|
|||||||
"jquery.flot.gauge": "vendor/flot/jquery.flot.gauge",
|
"jquery.flot.gauge": "vendor/flot/jquery.flot.gauge",
|
||||||
"d3": "vendor/d3/d3.js",
|
"d3": "vendor/d3/d3.js",
|
||||||
"jquery.flot.dashes": "vendor/flot/jquery.flot.dashes",
|
"jquery.flot.dashes": "vendor/flot/jquery.flot.dashes",
|
||||||
"json-formatter-js": "vendor/npm/json-formatter-js/dist/json-formatter"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
packages: {
|
packages: {
|
||||||
|
@ -34,7 +34,6 @@ module.exports = function(config) {
|
|||||||
'remarkable/dist/*',
|
'remarkable/dist/*',
|
||||||
'virtual-scroll/**/*',
|
'virtual-scroll/**/*',
|
||||||
'mousetrap/**/*',
|
'mousetrap/**/*',
|
||||||
'json-formatter-js/dist/*.js',
|
|
||||||
],
|
],
|
||||||
dest: '<%= srcDir %>/vendor/npm'
|
dest: '<%= srcDir %>/vendor/npm'
|
||||||
}
|
}
|
||||||
|
@ -2561,10 +2561,6 @@ jshint@~2.9.4:
|
|||||||
shelljs "0.3.x"
|
shelljs "0.3.x"
|
||||||
strip-json-comments "1.0.x"
|
strip-json-comments "1.0.x"
|
||||||
|
|
||||||
json-formatter-js@^2.2.0:
|
|
||||||
version "2.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/json-formatter-js/-/json-formatter-js-2.2.0.tgz#1ed987223ef2f1d945304597faae78b580a8212b"
|
|
||||||
|
|
||||||
json-schema@0.2.3:
|
json-schema@0.2.3:
|
||||||
version "0.2.3"
|
version "0.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
||||||
|
Loading…
Reference in New Issue
Block a user