UNPKG

ng2-json-editor

Version:

Angular2 component for editing large json documents

256 lines 25 kB
/* * This file is part of ng2-json-editor. * Copyright (C) 2016 CERN. * * ng2-json-editor is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * ng2-json-editor is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ng2-json-editor; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * In applying this license, CERN does not * waive the privileges and immunities granted to it by virtue of its status * as an Intergovernmental Organization or submit itself to any jurisdiction. */ var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); import { Component, EventEmitter, Input, Output, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core'; import { fromJS } from 'immutable'; import { AbstractSubscriberComponent } from './abstract-subscriber'; import { AppGlobalsService, JsonStoreService, JsonUtilService, JsonSchemaService, KeysStoreService, PathUtilService, RecordFixerService, SchemaFixerService, TabsUtilService, ProblemsService } from './shared/services'; var JsonEditorComponent = (function (_super) { __extends(JsonEditorComponent, _super); function JsonEditorComponent(appGlobalsService, problemsService, jsonStoreService, jsonUtilService, jsonSchemaService, keysStoreService, recordFixerService, schemaFixerService, tabsUtilService, pathUtilService) { var _this = _super.call(this) || this; _this.appGlobalsService = appGlobalsService; _this.problemsService = problemsService; _this.jsonStoreService = jsonStoreService; _this.jsonUtilService = jsonUtilService; _this.jsonSchemaService = jsonSchemaService; _this.keysStoreService = keysStoreService; _this.recordFixerService = recordFixerService; _this.schemaFixerService = schemaFixerService; _this.tabsUtilService = tabsUtilService; _this.pathUtilService = pathUtilService; _this.recordChange = new EventEmitter(); _this.jsonPatchesChange = new EventEmitter(); _this.validationProblems = new EventEmitter(); _this.pathString = ''; _this.isBottomConsoleOpen = false; _this.isPreviewerHidden = false; _this.isSidebarCollapsed = true; _this.bottomConsoleActiveTab = ''; return _this; } JsonEditorComponent.prototype.ngOnInit = function () { var _this = this; this.isPreviewerHidden = this.config.isPreviewerHiddenOnStart; this.appGlobalsService.adminMode$ .takeUntil(this.isDestroyed) .subscribe(function (adminMode) { _this.keysStoreService.buildKeysMap(_this._record, _this.fixedSchema); }); // listen for all changes on json this.jsonStoreService.json$ .skipWhile(function (json) { return json === _this._record; }) .takeUntil(this.isDestroyed) .subscribe(function (json) { _this._record = json; // emit the change as plain JS object _this.lastEmittedRecord = json.toJS(); _this.recordChange.emit(_this.lastEmittedRecord); }); // list for all changes on jsonPatches this.jsonStoreService.jsonPatches$ .takeUntil(this.isDestroyed) .subscribe(function (patches) { _this.jsonPatchesChange.emit(patches); }); this.problemsService.internalProblemMap$ .takeUntil(this.isDestroyed) .subscribe(function (internalProblemMap) { _this.validationProblems.emit(internalProblemMap); }); }; JsonEditorComponent.prototype.ngOnChanges = function (changes) { var _this = this; // throw error if a required input is undefined if (changes['schema'] && !this.schema) { this.throwInputUndefined('schema'); } if (changes['record'] && !this.record) { this.throwInputUndefined('record'); } // warn if an important input is undefined if (changes['config'] && !this.config) { this.config = {}; console.warn("[config] is undefined, make sure that is intended."); } var recordChanged = changes['record'] && this.record !== this.lastEmittedRecord; var schemaChanged = changes['schema'] || changes['config']; if (schemaChanged) { this.fixedSchema = this.schemaFixerService.fixSchema(this.schema, this.config.schemaOptions); this.jsonSchemaService.setSchema(this.fixedSchema); } if (schemaChanged || recordChanged) { this.record = this.recordFixerService.fixRecord(this.record, this.fixedSchema); this.lastEmittedRecord = this.record; this._record = fromJS(this.record); this.jsonStoreService.setJson(this._record); this.keysStoreService.buildKeysMap(this._record, this.fixedSchema); } if (changes['config']) { this.appGlobalsService.config = this.config; if (this.config.tabsConfig) { this.tabNames = this.tabsUtilService.getTabNames(this.config.tabsConfig); this.tabsUtilService.activeTabName$.subscribe(function (tabName) { _this.appGlobalsService.activeTabName = tabName; }); this.appGlobalsService.activeTabName = this.config.tabsConfig.defaultTabName; } this.customShortcutKeys = this.config.shortcuts; } if (recordChanged || changes['config']) { this.extractPreviews(); } if (changes['jsonPatches']) { if (this.jsonPatches) { this.jsonStoreService.setJsonPatches(this.jsonPatches); } } if (changes['problemMap']) { this.problemsService.externalProblems = this.problemMap; } if (changes['templates']) { this.appGlobalsService.templates = this.templates || {}; } }; JsonEditorComponent.prototype.throwInputUndefined = function (inputName) { throw new Error("[" + inputName + "] is undefined!\n if you are fetching " + inputName + " async then please consider using:\n <json-editor *ngIf=\"" + inputName + "\" [" + inputName + "]=\"" + inputName + "\" ...> </json-editor>\n in order to wait for it to be fetched before initializing json-editor"); }; /** * Converts PreviewConfig instances to Preview instances and appends to `previews` array. */ JsonEditorComponent.prototype.extractPreviews = function () { var _this = this; if (!this.isPreviewerDisabled) { // if url is not set directly, populate it this.previews = []; this.config.previews .forEach(function (previewConfig) { var url; if (previewConfig.url) { url = previewConfig.url; } else if (previewConfig.getUrl) { url = previewConfig.getUrl(_this.record); } else if (previewConfig.urlPath) { try { url = _this.jsonUtilService.getValueInPath(_this.record, previewConfig.urlPath); } catch (error) { console.warn("Path " + previewConfig.urlPath + " in preview config is not present in the input record"); } } else { throw new Error('Either url, urlPath or getUrl should be set for a preview'); } if (url) { _this.previews.push({ name: previewConfig.name, type: previewConfig.type, url: url }); } }); } }; Object.defineProperty(JsonEditorComponent.prototype, "keys$", { get: function () { return this.keysStoreService.forPath(this.pathString); }, enumerable: true, configurable: true }); Object.defineProperty(JsonEditorComponent.prototype, "isPreviewerDisabled", { get: function () { return (this.config.previews === undefined || this.config.previews.length === 0); }, enumerable: true, configurable: true }); Object.defineProperty(JsonEditorComponent.prototype, "activeTabName", { set: function (tabName) { this.appGlobalsService.activeTabName = tabName; }, enumerable: true, configurable: true }); JsonEditorComponent.prototype.isActiveTab = function (tabName) { return this.appGlobalsService.activeTabName === tabName; }; Object.defineProperty(JsonEditorComponent.prototype, "shorterEditorContainerClass", { get: function () { return this.isBottomConsoleOpen ? 'shorter-editor-container' : ''; }, enumerable: true, configurable: true }); JsonEditorComponent.prototype.openBottomConsole = function (tabName) { this.isBottomConsoleOpen = true; this.bottomConsoleActiveTab = tabName; }; JsonEditorComponent.prototype.trackByElement = function (index, element) { return element; }; return JsonEditorComponent; }(AbstractSubscriberComponent)); export { JsonEditorComponent }; JsonEditorComponent.decorators = [ { type: Component, args: [{ selector: 'json-editor', encapsulation: ViewEncapsulation.None, styles: ["html, body { height: 100%; background-color: #ecf0f1; overflow-x: hidden; } .editor-container { display: flex; flex-direction: row; height: 100%; width: 100%; margin-right: 0px; margin-left: 0px; } .editor-container .row { margin-left: 0px; margin-right: 0px; } .bs-tooltip-right { width: 120px !important; } .shorter-editor-container { height: 75%; } #ng2-json-editor { /* Styles for tabset */ } #ng2-json-editor .dropdown-menu { max-height: 400px; overflow-y: auto; } #ng2-json-editor .hidden { display: none; } #ng2-json-editor th { font-weight: 400; padding: 1px 0px 1px 6px; background-color: #ecf0f1; color: #8e8e8e; font-weight: bold; } #ng2-json-editor th .dropdown-filter-container { font-weight: initial; } #ng2-json-editor td { background-color: #f9f9f9; border: none; padding: 0; } #ng2-json-editor td > * { vertical-align: middle; } #ng2-json-editor td.label-holder { width: 1%; white-space: nowrap; padding: 3px; background-color: #dae8ef; border-top: 1px solid #bdc3c7; } #ng2-json-editor td.label-holder button { color: #595959; } #ng2-json-editor tr.error td, #ng2-json-editor td.error { color: white; background-color: #e74c3c !important; transition: all .4s; } #ng2-json-editor tbody { border: none; } #ng2-json-editor table { margin-bottom: 0px !important; } #ng2-json-editor .main-container.compact { border-left: none; } #ng2-json-editor .main-container { font-size: 13px; border-left: 1px solid #a5adb5; height: 100%; overflow: auto; } #ng2-json-editor .main-container .tab-container > .nav-tabs { font-size: 14px; } #ng2-json-editor .main-container > add-field-dropdown div.dropdown { width: 100vh; } #ng2-json-editor .main-container > add-field-dropdown ul.dropdown-menu { right: 0px; padding-bottom: 15px; } #ng2-json-editor .main-container > add-field-dropdown button.btn-add-field-dropdown { background: white; padding: 5px; opacity: 0.9; line-height: normal; font-size: 16px; width: 100%; } #ng2-json-editor .main-container > add-field-dropdown button.btn-add-field-dropdown:hover { opacity: 1; color: black; } #ng2-json-editor .add-field-dropdown-container { width: 100%; } #ng2-json-editor .middle.main-container { padding: 0px; } #ng2-json-editor .menu-container { display: flex; flex-direction: column; justify-content: space-between; background-color: #2c3e50; height: 100%; width: 0%; overflow-x: hidden; opacity: 0; visibility: hidden; transition: width 0.1s ease-in; } #ng2-json-editor .menu-container div.dropdown { width: 100vh; } #ng2-json-editor .menu-container ul.dropdown-menu { right: 0px; padding-bottom: 15px; } #ng2-json-editor .menu-container button.btn-add-field-dropdown { background: white; padding: 5px; opacity: 0.9; line-height: normal; font-size: 16px; width: 100%; } #ng2-json-editor .menu-container button.btn-add-field-dropdown:hover { opacity: 1; color: black; } #ng2-json-editor .menu-container.open { opacity: 1; visibility: visible; width: 280px; padding-left: 5px; } #ng2-json-editor .collapsed-menu-container { position: relative; background-color: #1D2D3D; flex: 0 0 50px; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; } #ng2-json-editor .collapsed-menu-container .add-field-button { position: absolute; top: 0px; margin-bottom: 25px; display: flex; flex-wrap: wrap; flex-direction: column; justify-content: center; width: 100%; cursor: pointer; } #ng2-json-editor .collapsed-menu-container .add-field-button .btn-add-field-dropdown { display: flex; justify-content: center; width: 100%; opacity: 1; background-color: transparent; margin-top: 10px; } #ng2-json-editor .collapsed-menu-container .add-field-button .btn-add-field-dropdown:hover, #ng2-json-editor .collapsed-menu-container .add-field-button .btn-add-field-dropdown:focus, #ng2-json-editor .collapsed-menu-container .add-field-button .btn-add-field-dropdown:active { outline: none; } #ng2-json-editor .collapsed-menu-container .add-field-button .btn-add-field-dropdown i { color: #ddd; } #ng2-json-editor .collapsed-menu-container .add-field-button .btn-add-field-dropdown i:hover { color: white; } #ng2-json-editor .collapsed-menu-container .preview-icon { display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; height: 30px; border-radius: 20%; border: 2px solid #ddd; width: 30px; } #ng2-json-editor .collapsed-menu-container .preview-icon .fa { color: #ddd; } #ng2-json-editor .collapsed-menu-container .preview-icon .fa:hover { color: white; } #ng2-json-editor .collapsed-menu-container .open-sidebar-container { cursor: pointer; width: 100%; display: flex; justify-content: center; margin-top: 20px; border-top: 2px solid #283948; border-right: 2px solid #283948; color: #ddd; } #ng2-json-editor .collapsed-menu-container .open-sidebar-container:hover { color: white; text-shadow: 3px 3px 14px #2a5d88; } #ng2-json-editor .collapsed-menu-container .open-sidebar-container .fa-angle-right { transition: all 0.5s ease-in-out; -webkit-transition: all 0.5s ease-in-out; -ms-transition: all 0.5s ease-in-out; } #ng2-json-editor .collapsed-menu-container .open-sidebar-container .fa-angle-right.rotate { transform: rotate(-180deg); -webkit-transform: rotate(-180deg); -ms-transform: rotate(-180deg); } #ng2-json-editor .middle.main-container { flex-basis: 60%; } #ng2-json-editor .middle.main-container.maximizeEditor { flex-grow: 2; } #ng2-json-editor .right.main-container { flex-basis: 40%; flex-shrink: 0; } #ng2-json-editor .right.main-container.minimizePreview { flex-basis: 0%; } #ng2-json-editor .right.main-container .btn-toggle { position: fixed; right: 0; } #ng2-json-editor .editor-btn-delete { font-weight: bold; line-height: 1; text-shadow: 0 1px 0 #fff; opacity: 0.2; background: transparent; border: 0; padding: 0 0 3px 3px; } #ng2-json-editor .editor-btn-delete:hover { color: red; opacity: 0.6; } #ng2-json-editor .editor-btn-delete.editor-btn-delete-text { font-size: 13px; opacity: 0.5; padding: 0px; } #ng2-json-editor .custom-title-dropdown-item button { font-weight: bold; line-height: 1; text-shadow: 0 1px 0 #fff; opacity: 0.2; background: transparent; border: 0; padding: 0 0 3px 3px; font-size: 13px; opacity: 0.5; padding: 0px; } #ng2-json-editor .custom-title-dropdown-item button:hover { color: #337ab7; opacity: 0.6; } #ng2-json-editor .editor-btn-move-down { padding-bottom: 0; } #ng2-json-editor .editor-btn-move-up, #ng2-json-editor .editor-btn-move-down { padding: 0; font-size: 11px; border: 0; background: transparent; opacity: 0.2; } #ng2-json-editor .editor-btn-move-up:hover, #ng2-json-editor .editor-btn-move-down:hover { opacity: 0.6; } #ng2-json-editor ul.pagination-top { margin: -16px 0px 0px 0px; } #ng2-json-editor td.button-holder, #ng2-json-editor th.button-holder { width: 40.33px; text-align: center; vertical-align: middle; } #ng2-json-editor td.button-holder.sortable, #ng2-json-editor th.button-holder.sortable { width: 46px; } #ng2-json-editor th.button-holder .add-field-dropdown-container { width: 100%; } #ng2-json-editor th.button-holder .btn-add-field-dropdown { float: right; } #ng2-json-editor label { color: #c1c1c1; } #ng2-json-editor .highlight { border: 2px solid yellow !important; } #ng2-json-editor table.editable-inner-table { table-layout: fixed; } #ng2-json-editor table.editable-inner-table > tbody > tr { border-bottom: 1px solid white !important; } #ng2-json-editor table.editable-inner-table add-new-element-button .button-container { padding-left: 6px; } #ng2-json-editor table.editable-inner-table label { display: inline; font-weight: initial; padding-left: 5px; } #ng2-json-editor table.editable-inner-table .dropdown-menu { left: inherit; right: 0px; min-width: 100px; } #ng2-json-editor .title-dropdown-item button { width: 100%; text-align: left; padding-left: 20px !important; padding-right: 20px !important; } #ng2-json-editor .title-dropdown-item:hover { background: #f5f5f5; } #ng2-json-editor .tooltip.top .tooltip-arrow { border-top-color: transparent; } #ng2-json-editor .tooltip { width: 90%; } #ng2-json-editor button.btn-toggle { float: right; margin-top: 5px; margin-right: 5px; } #ng2-json-editor .autocomplete-container .dropdown { position: relative !important; top: 0px !important; left: 0px !important; } #ng2-json-editor .autocomplete-container .dropdown-menu { width: min-content; min-width: 100% !important; } #ng2-json-editor div.admin-mode { padding-top: 8px; width: 100%; } #ng2-json-editor label.admin-mode { color: #e0dfdf; font-size: 13px; font-weight: normal; width: 90%; padding-left: 4px; } #ng2-json-editor hr { margin-top: 5px; margin-bottom: 5px; border-top: 1px solid #757575; } #ng2-json-editor .btn.btn-success { background-color: #16a085; border-color: #16a085; color: white; } #ng2-json-editor .btn.btn-success:hover, #ng2-json-editor .btn.btn-success:active, #ng2-json-editor .btn.btn-success:focus { background-color: #19b698 !important; color: white; } #ng2-json-editor .btn .fa { margin-right: 2px; } #ng2-json-editor .nav { margin-bottom: 3px; } #ng2-json-editor .nav-tabs > li.active > a, #ng2-json-editor .nav-tabs > li.active > a:hover, #ng2-json-editor .nav-tabs > li.active > a:focus { border-top: 1px solid #2c3e50; background-color: white; } #ng2-json-editor .nav-tabs > li > a:hover { border-top: 1px solid #2c3e50; border-bottom: 1px solid transparent; border-left: 1px solid transparent; border-right: 1px solid transparent; transition: all .4s; } #ng2-json-editor .nav.nav-tabs { border-bottom: 5px solid white; box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.24); } #ng2-json-editor .nav-tabs > li > a { margin-right: 0px; border-radius: 0px; border-right: 1px solid #e0e2e2; } #ng2-json-editor .disabled { cursor: not-allowed; } #ng2-json-editor .disabled div { pointer-events: none; } #ng2-json-editor .disabled div input, #ng2-json-editor .disabled div button, #ng2-json-editor .disabled div a, #ng2-json-editor .disabled div i, #ng2-json-editor .disabled div string-input > div { opacity: .5; } #ng2-json-editor .disabled button { pointer-events: none; } #ng2-json-editor .pagination > .active > a { background-color: #31617B; border-color: #31617B; } #ng2-json-editor .btn.btn-switch { background-color: #7DA0B3; } #ng2-json-editor .btn.btn-switch.active { background-color: #31617B; } .bottom-console-container { height: 25%; overflow: hidden; } .bottom-console-container .tab-content { height: 90%; overflow: scroll; } .red-left-border { border-left: 9px solid #e74c3c !important; } .max-height-90-vh { max-height: 90vh; } .max-height-70-vh { max-height: 70vh; } complex-list-field add-field-dropdown { display: none; } .nav-tabs { position: sticky; top: 0; background: white; z-index: 1; } typeahead-container a[href='#'] { padding: 0 !important; } "], template: "<div id=\"ng2-json-editor\" class=\"editor-container\" [ngClass]=\"shorterEditorContainerClass\"> <div *ngIf=\"!config.compact\" class=\"collapsed-menu-container\"> <add-field-dropdown [fields]=\"keys$ | async\" [pathString]=\"pathString\" [schema]=\"fixedSchema\" class=\"add-field-button\"> <i class=\"fa fa-plus fa-2x\" tooltip=\"Add Field\" placement=\"right\"></i> </add-field-dropdown> <span id=\"preview-toggle-icon\" tooltip=\"{{isPreviewerHidden ? 'Show Preview' : 'Hide Preview'}}\" placement=\"right\"class=\"preview-icon\" (click)=\"isPreviewerHidden = !isPreviewerHidden\"> <i class=\"fa fa-1x\" [ngClass]=\"!isPreviewerHidden ? 'fa-eye-slash' : 'fa-eye'\"></i> </span> <bottom-console-badges (badgeClick)=\"openBottomConsole($event)\"></bottom-console-badges> <span class=\"open-sidebar-container\" (click)=\"isSidebarCollapsed = !isSidebarCollapsed\"> <i class=\"fa fa-angle-right fa-4x\" [class.rotate]=\"!isSidebarCollapsed\"></i> </span> </div> <div *ngIf=\"!config.compact\" class=\"menu-container\" [ngClass]=\"isSidebarCollapsed ? 'close' : 'open'\"> <tree-menu [record]=\"_record\" [schema]=\"fixedSchema\"></tree-menu> <hr> <div *ngIf=\"config.enableAdminModeSwitch\" class=\"admin-mode\" tooltip=\"Allows editing all fields (use with care)\"> <input id=\"admin-mode-checkbox\" type=\"checkbox\" [(ngModel)]=\"appGlobalsService.adminMode\" /> <label class=\"admin-mode\" for=\"admin-mode-checkbox\">Enable Admin Mode</label> </div> <hr> </div> <div id=\"middle-main-container\" class=\"middle main-container\" [shortcuts]=\"customShortcutKeys\" [ngClass]=\"{ 'maximizeEditor' : isPreviewerHidden, 'compact' : config.compact }\"> <add-field-dropdown *ngIf=\"config.compact\" [fields]=\"keys$ | async\" [pathString]=\"pathString\" [schema]=\"fixedSchema\">Add field</add-field-dropdown> <tabset *ngIf=\"config.tabsConfig\"> <tab *ngFor=\"let tabName of tabNames; trackBy:trackByElement\" [heading]=\"tabName\" (select)=\"activeTabName = tabName\" [active]=\"isActiveTab(tabName)\"> <sub-record [value]=\"_record\" [tabName]=\"tabName\" [schema]=\"fixedSchema\" [keys]=\"keys$ | async\" [pathString]=\"pathString\"></sub-record> </tab> </tabset> <sub-record *ngIf=\"!config.tabsConfig\" [value]=\"_record\" [schema]=\"fixedSchema\" [keys]=\"keys$ | async\" [pathString]=\"pathString\"></sub-record> </div> <div id=\"right-main-container\" *ngIf=\"!isPreviewerDisabled\" class=\"main-container right\" [ngClass]=\"isPreviewerHidden ? 'minimizePreview' : 'maximizePreview' \"> <editor-previewer [hidden]=\"isPreviewerHidden\" [previews]=\"previews\"> </editor-previewer> </div> </div> <bottom-console *ngIf=\"!config.compact\" [activeTab]=\"bottomConsoleActiveTab\" [isOpen]=\"isBottomConsoleOpen\" (onCollapse)=\"isBottomConsoleOpen = $event\"></bottom-console> <!-- Modal View controlled by ModalService --> <modal-view> </modal-view>", changeDetection: ChangeDetectionStrategy.OnPush },] }, ]; /** @nocollapse */ JsonEditorComponent.ctorParameters = function () { return [ { type: AppGlobalsService, }, { type: ProblemsService, }, { type: JsonStoreService, }, { type: JsonUtilService, }, { type: JsonSchemaService, }, { type: KeysStoreService, }, { type: RecordFixerService, }, { type: SchemaFixerService, }, { type: TabsUtilService, }, { type: PathUtilService, }, ]; }; JsonEditorComponent.propDecorators = { 'config': [{ type: Input },], 'record': [{ type: Input },], 'schema': [{ type: Input },], 'problemMap': [{ type: Input },], 'jsonPatches': [{ type: Input },], 'templates': [{ type: Input },], 'recordChange': [{ type: Output },], 'jsonPatchesChange': [{ type: Output },], 'validationProblems': [{ type: Output },], }; //# sourceMappingURL=json-editor.component.js.map