// 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 = ''; // } // } // } // }