redoc/lib/components/JsonSchema/json-schema.ts

199 lines
5.8 KiB
TypeScript
Raw Normal View History

2015-11-19 00:23:18 +03:00
'use strict';
import { Component,
Input,
Renderer,
ElementRef,
OnInit,
ChangeDetectionStrategy,
ChangeDetectorRef
} from '@angular/core';
import { BaseSearchableComponent, SpecManager } from '../base';
import { SchemaNormalizer, SchemaHelper, AppStateService } from '../../services/';
2017-01-26 19:21:24 +03:00
import { JsonPointer, DescendantInfo } 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',
templateUrl: './json-schema.html',
styleUrls: ['./json-schema.css'],
changeDetection: ChangeDetectionStrategy.OnPush
2015-11-19 00:23:18 +03:00
})
export class JsonSchema extends BaseSearchableComponent implements OnInit {
2016-08-22 12:12:13 +03:00
@Input() pointer: string;
@Input() absolutePointer: string;
2016-08-22 12:12:13 +03:00
@Input() final: boolean = false;
@Input() nestOdd: boolean;
@Input() childFor: string;
@Input() isRequestSchema: boolean;
schema: any = {};
2016-06-22 21:17:48 +03:00
activeDescendant:any = {};
discriminator: string = null;
_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;
2017-01-26 19:21:24 +03:00
descendants: DescendantInfo[];
constructor(
specMgr:SpecManager,
app: AppStateService,
private _renderer: Renderer,
private cdr: ChangeDetectorRef,
private _elementRef: ElementRef) {
super(specMgr, app);
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
}
2017-01-26 19:21:24 +03:00
selectDescendantByIdx(idx) {
this.selectDescendant(this.descendants[idx]);
}
selectDescendant(activeDescendant: DescendantInfo) {
2016-06-22 21:17:48 +03:00
if (!activeDescendant || activeDescendant.active) return;
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;
this.schema = this.specMgr.getDescendant(activeDescendant, this.componentSchema);
this.pointer = this.schema._pointer || activeDescendant.$ref;
this.normalizer.reset();
2016-09-01 09:53:42 +03:00
this.schema = this.normalizer.normalize(this.schema, this.normPointer,
{resolved: true});
this.preprocessSchema();
2017-01-26 19:21:24 +03:00
this.activeDescendant = activeDescendant;
}
2016-06-22 21:17:48 +03:00
initDescendants() {
this.descendants = this.specMgr.findDerivedDefinitions(this.normPointer, this.schema);
if (!this.descendants.length) return;
let discriminator = this.discriminator = this.schema.discriminator || this.schema['x-extendedDiscriminator'];
let discrProperty = this.schema.properties &&
this.schema.properties[discriminator];
if (discrProperty && discrProperty.enum) {
let enumOrder = {};
discrProperty.enum.forEach((enumItem, idx) => {
enumOrder[enumItem] = idx;
});
this.descendants = this.descendants
.filter(a => {
return enumOrder[a.name] != undefined;
}).sort((a, b) => {
return enumOrder[a.name] > enumOrder[b.name] ? 1 : -1;
});
this.descendants.forEach((d, idx) => d.idx = idx);
}
2017-01-26 19:21:24 +03:00
this.selectDescendantByIdx(0);
}
2016-04-27 23:07:06 +03:00
init() {
if (!this.pointer) return;
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
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;
this.absolutePointer += (this._isArray ? '/items' : '');
this.initDescendants();
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, {
childFor: this.childFor,
discriminator: this.discriminator
2016-06-22 21:17:48 +03:00
});
2016-05-16 23:02:23 +03:00
}
2016-06-13 20:54:24 +03:00
this.properties = this.schema._properties || [];
2016-06-30 16:42:36 +03:00
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
if (this.properties.length === 1) {
this.properties[0].expanded = true;
}
2016-06-13 20:54:24 +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 {
return item.name + (item._pointer || '');
}
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-26 19:21:24 +03:00
findDescendantWithField(fieldName: string): DescendantInfo {
let res: DescendantInfo;
for (let descendantInfo of this.descendants) {
let schema = this.specMgr.getDescendant(descendantInfo, this.schema);
this.normalizer.reset();
schema = this.normalizer.normalize(schema, this.normPointer,
{resolved: true});
if (schema.properties && schema.properties[fieldName]) {
res = descendantInfo;
break;
};
};
return res;
}
ensureSearchIsShown(ptr: string) {
if (ptr.startsWith(this.absolutePointer)) {
let props = this.properties;
2017-01-26 17:46:28 +03:00
if (!props) return;
let relative = JsonPointer.relative(this.absolutePointer, ptr);
let propName;
if (relative.length > 1 && relative[0] === 'properties') {
propName = relative[1];
}
2017-01-30 17:11:14 +03:00
let prop = props.find(p => p.name === propName);
2017-01-26 19:21:24 +03:00
if (!prop) {
let d = this.findDescendantWithField(propName);
this.selectDescendant(d);
2017-01-30 17:11:14 +03:00
prop = this.properties.find(p => p.name === propName);
2017-01-26 19:21:24 +03:00
}
if (prop && !prop.isTrivial) 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
}