2015-11-19 00:23:18 +03:00
|
|
|
'use strict';
|
|
|
|
|
2017-01-19 00:48:55 +03:00
|
|
|
import { Component,
|
|
|
|
Input,
|
|
|
|
Renderer,
|
|
|
|
ElementRef,
|
|
|
|
OnInit,
|
|
|
|
ChangeDetectionStrategy,
|
|
|
|
ChangeDetectorRef
|
|
|
|
} from '@angular/core';
|
|
|
|
|
|
|
|
import { BaseSearchableComponent, SpecManager } from '../base';
|
|
|
|
import { SchemaNormalizer, SchemaHelper, AppStateService } from '../../services/';
|
|
|
|
import { JsonPointer } from '../../utils/';
|
|
|
|
import { Zippy } from '../../shared/components';
|
|
|
|
import { JsonSchemaLazy } from './json-schema-lazy';
|
2015-11-19 00:23:18 +03:00
|
|
|
|
2016-08-22 12:12:13 +03:00
|
|
|
@Component({
|
2015-11-19 00:23:18 +03:00
|
|
|
selector: 'json-schema',
|
2016-05-25 18:34:31 +03:00
|
|
|
templateUrl: './json-schema.html',
|
2016-08-30 17:07:54 +03:00
|
|
|
styleUrls: ['./json-schema.css'],
|
|
|
|
changeDetection: ChangeDetectionStrategy.OnPush
|
2015-11-19 00:23:18 +03:00
|
|
|
})
|
2017-01-19 00:48:55 +03:00
|
|
|
export class JsonSchema extends BaseSearchableComponent implements OnInit {
|
2016-08-22 12:12:13 +03:00
|
|
|
@Input() pointer: string;
|
2017-01-19 00:48:55 +03:00
|
|
|
@Input() absolutePointer: string;
|
2016-08-22 12:12:13 +03:00
|
|
|
@Input() final: boolean = false;
|
|
|
|
@Input() nestOdd: boolean;
|
|
|
|
@Input() childFor: string;
|
|
|
|
@Input() isRequestSchema: boolean;
|
|
|
|
|
2016-07-26 14:07:25 +03:00
|
|
|
schema: any = {};
|
2016-06-22 21:17:48 +03:00
|
|
|
activeDescendant:any = {};
|
|
|
|
hasDescendants: boolean = false;
|
2016-06-29 19:07:18 +03:00
|
|
|
_hasSubSchemas: boolean = false;
|
2016-06-30 16:42:36 +03:00
|
|
|
properties: any;
|
|
|
|
_isArray: boolean;
|
2016-06-22 21:17:48 +03:00
|
|
|
normalizer: SchemaNormalizer;
|
2016-08-30 13:51:14 +03:00
|
|
|
descendants: any;
|
2016-06-13 20:54:24 +03:00
|
|
|
|
2017-01-19 00:48:55 +03:00
|
|
|
// @ViewChildren(Zippy) childZippies: QueryList<Zippy>;
|
|
|
|
// @ViewChildren(forwardRef(() => JsonSchemaLazy)) childSchemas: QueryList<JsonSchemaLazy>;
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
specMgr:SpecManager,
|
|
|
|
app: AppStateService,
|
|
|
|
private _renderer: Renderer,
|
|
|
|
private cdr: ChangeDetectorRef,
|
|
|
|
private _elementRef: ElementRef) {
|
|
|
|
super(specMgr, app);
|
2016-06-23 17:36:38 +03:00
|
|
|
this.normalizer = new SchemaNormalizer(specMgr);
|
2016-06-13 20:54:24 +03:00
|
|
|
}
|
|
|
|
|
2016-06-22 21:17:48 +03:00
|
|
|
get normPointer() {
|
|
|
|
return this.schema._pointer || this.pointer;
|
2015-11-19 00:23:18 +03:00
|
|
|
}
|
|
|
|
|
2016-06-22 21:17:48 +03:00
|
|
|
selectDescendant(idx) {
|
2016-08-30 13:51:14 +03:00
|
|
|
let activeDescendant = this.descendants[idx];
|
2016-06-22 21:17:48 +03:00
|
|
|
if (!activeDescendant || activeDescendant.active) return;
|
2016-08-30 13:51:14 +03:00
|
|
|
this.descendants.forEach(d => {
|
|
|
|
d.active = false;
|
2016-03-18 16:06:22 +03:00
|
|
|
});
|
2016-06-22 21:17:48 +03:00
|
|
|
activeDescendant.active = true;
|
2016-08-30 13:51:14 +03:00
|
|
|
|
2016-12-28 15:04:57 +03:00
|
|
|
this.schema = this.specMgr.getDescendant(activeDescendant, this.componentSchema);
|
|
|
|
this.pointer = this.schema._pointer || activeDescendant.$ref;
|
2016-09-12 23:40:46 +03:00
|
|
|
this.normalizer.reset();
|
2016-09-01 09:53:42 +03:00
|
|
|
this.schema = this.normalizer.normalize(this.schema, this.normPointer,
|
|
|
|
{resolved: true});
|
2016-08-30 13:51:14 +03:00
|
|
|
this.preprocessSchema();
|
2016-03-27 01:44:11 +03:00
|
|
|
}
|
2015-11-29 13:04:28 +03:00
|
|
|
|
2016-06-22 21:17:48 +03:00
|
|
|
initDescendants() {
|
2016-12-28 15:04:57 +03:00
|
|
|
this.descendants = this.specMgr.findDerivedDefinitions(this.normPointer, this.schema);
|
2016-08-30 21:29:56 +03:00
|
|
|
if (!this.descendants.length) return;
|
2016-08-31 21:58:55 +03:00
|
|
|
this.hasDescendants = true;
|
2016-09-28 09:36:21 +03:00
|
|
|
let discriminator = this.schema.discriminator || this.schema['x-extendedDiscriminator'];
|
2016-12-28 15:04:57 +03:00
|
|
|
let discrProperty = this.schema.properties &&
|
|
|
|
this.schema.properties[discriminator];
|
2016-08-30 21:29:56 +03:00
|
|
|
if (discrProperty && discrProperty.enum) {
|
|
|
|
let enumOrder = {};
|
|
|
|
discrProperty.enum.forEach((enumItem, idx) => {
|
2016-12-28 15:04:57 +03:00
|
|
|
enumOrder[enumItem] = idx;
|
2016-08-30 21:29:56 +03:00
|
|
|
});
|
|
|
|
|
2016-12-28 15:04:57 +03:00
|
|
|
this.descendants = this.descendants
|
|
|
|
.filter(a => {
|
|
|
|
return enumOrder[a.name] != undefined;
|
|
|
|
}).sort((a, b) => {
|
2016-08-30 21:29:56 +03:00
|
|
|
return enumOrder[a.name] > enumOrder[b.name] ? 1 : -1;
|
|
|
|
});
|
|
|
|
}
|
2016-06-22 21:17:48 +03:00
|
|
|
this.selectDescendant(0);
|
2016-04-28 20:17:38 +03:00
|
|
|
}
|
2016-04-27 23:07:06 +03:00
|
|
|
|
2016-07-20 11:07:08 +03:00
|
|
|
init() {
|
2016-07-26 14:07:25 +03:00
|
|
|
if (!this.pointer) return;
|
2017-01-19 00:48:55 +03:00
|
|
|
if (!this.absolutePointer) this.absolutePointer = this.pointer;
|
|
|
|
|
2016-06-25 13:02:13 +03:00
|
|
|
this.schema = this.componentSchema;
|
|
|
|
if (!this.schema) {
|
2016-06-22 21:17:48 +03:00
|
|
|
throw new Error(`Can't load component schema at ${this.pointer}`);
|
2016-04-27 23:07:06 +03:00
|
|
|
}
|
2016-05-16 23:02:23 +03:00
|
|
|
|
2016-08-30 13:51:14 +03:00
|
|
|
this.applyStyling();
|
|
|
|
|
2016-09-01 09:53:42 +03:00
|
|
|
this.schema = this.normalizer.normalize(this.schema, this.normPointer, {resolved: true});
|
2016-06-25 13:02:13 +03:00
|
|
|
this.schema = SchemaHelper.unwrapArray(this.schema, this.normPointer);
|
2016-11-28 21:03:01 +03:00
|
|
|
this._isArray = this.schema._isArray;
|
2017-01-19 00:48:55 +03:00
|
|
|
this.absolutePointer += (this._isArray ? '/items' : '');
|
2016-08-30 18:38:57 +03:00
|
|
|
this.initDescendants();
|
2016-08-30 13:51:14 +03:00
|
|
|
this.preprocessSchema();
|
|
|
|
}
|
|
|
|
|
|
|
|
preprocessSchema() {
|
2016-06-25 13:02:13 +03:00
|
|
|
SchemaHelper.preprocess(this.schema, this.normPointer, this.pointer);
|
2016-05-16 23:02:23 +03:00
|
|
|
|
2016-06-25 13:02:13 +03:00
|
|
|
if (!this.schema.isTrivial) {
|
|
|
|
SchemaHelper.preprocessProperties(this.schema, this.normPointer, {
|
2016-06-30 16:42:36 +03:00
|
|
|
childFor: this.childFor
|
2016-06-22 21:17:48 +03:00
|
|
|
});
|
2016-05-16 23:02:23 +03:00
|
|
|
}
|
2016-06-13 20:54:24 +03:00
|
|
|
|
2016-06-30 16:42:36 +03:00
|
|
|
this.properties = this.schema._properties;
|
|
|
|
if (this.isRequestSchema) {
|
|
|
|
this.properties = this.properties && this.properties.filter(prop => !prop.readOnly);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._hasSubSchemas = this.properties && this.properties.some(
|
|
|
|
propSchema => {
|
|
|
|
if (propSchema.type === 'array') {
|
|
|
|
propSchema = propSchema.items;
|
|
|
|
}
|
|
|
|
return (propSchema && propSchema.type === 'object' && propSchema._pointer);
|
|
|
|
});
|
2016-07-10 14:28:05 +03:00
|
|
|
|
2017-01-19 00:48:55 +03:00
|
|
|
if (this.properties.length === 1) {
|
|
|
|
this.properties[0].expanded = true;
|
|
|
|
}
|
2016-06-13 20:54:24 +03:00
|
|
|
}
|
2016-06-29 18:02:19 +03:00
|
|
|
|
2016-08-30 13:51:14 +03:00
|
|
|
applyStyling() {
|
|
|
|
if (this.nestOdd) {
|
|
|
|
this._renderer.setElementAttribute(this._elementRef.nativeElement, 'nestodd', 'true');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-02 12:59:29 +03:00
|
|
|
trackByName(_: number, item: any): number {
|
2016-09-12 23:40:46 +03:00
|
|
|
return item.name + (item._pointer || '');
|
2016-06-29 18:02:19 +03:00
|
|
|
}
|
2016-08-28 21:46:10 +03:00
|
|
|
|
2017-01-26 17:46:28 +03:00
|
|
|
trackByIdx(idx: number, _: any): number {
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
2017-01-19 00:48:55 +03:00
|
|
|
ensureSearchIsShown(ptr: string) {
|
|
|
|
if (ptr.startsWith(this.absolutePointer)) {
|
|
|
|
let props = this.properties;
|
2017-01-26 17:46:28 +03:00
|
|
|
if (!props) return;
|
2017-01-19 00:48:55 +03:00
|
|
|
let relative = JsonPointer.relative(this.absolutePointer, ptr);
|
|
|
|
let propName;
|
|
|
|
if (relative.length > 1 && relative[0] === 'properties') {
|
|
|
|
propName = relative[1];
|
|
|
|
}
|
|
|
|
let prop = props.find(p => p._name === propName);
|
2017-01-24 00:29:52 +03:00
|
|
|
if (!prop || prop.isTrivial) return;
|
2017-01-19 00:48:55 +03:00
|
|
|
prop.expanded = true;
|
|
|
|
this.cdr.markForCheck();
|
|
|
|
this.cdr.detectChanges();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-28 21:46:10 +03:00
|
|
|
ngOnInit() {
|
|
|
|
this.preinit();
|
|
|
|
}
|
2016-06-13 20:54:24 +03:00
|
|
|
}
|