ng2-json-editor
Version:
Angular2 component for editing large json documents
273 lines • 17.6 kB
JavaScript
/*
* 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, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { AbstractListFieldComponent } from '../abstract-list-field';
import { AppGlobalsService, JsonStoreService, DomUtilService, PathUtilService, ListPageChangerService, ProblemsService, EmptyValueService, } from '../shared/services';
var ComplexListFieldComponent = (function (_super) {
__extends(ComplexListFieldComponent, _super);
function ComplexListFieldComponent(appGlobalsService, problemsService, jsonStoreService, domUtilService, pathUtilService, changeDetectorRef, emptyValueService, listPageChangerService) {
var _this = _super.call(this, appGlobalsService, problemsService, jsonStoreService, pathUtilService, changeDetectorRef) || this;
_this.appGlobalsService = appGlobalsService;
_this.problemsService = problemsService;
_this.jsonStoreService = jsonStoreService;
_this.domUtilService = domUtilService;
_this.pathUtilService = pathUtilService;
_this.changeDetectorRef = changeDetectorRef;
_this.emptyValueService = emptyValueService;
_this.listPageChangerService = listPageChangerService;
_this.currentFound = 0;
_this.currentPage = 1;
_this._shouldDisplayOnlyEditFormItems = false;
return _this;
}
ComplexListFieldComponent.prototype.ngOnInit = function () {
var _this = this;
_super.prototype.ngOnInit.call(this);
this.navigator = this.schema.longListNavigatorConfig;
this.paginatableItems = this.getPaginatableItems();
this.paginatedItems = this.getPaginatableItemsForPage(this.currentPage);
if (this.navigator) {
this.listPageChangerService
.registerPaginatedList(this.pathString, this.navigator.itemsPerPage)
.skipWhile(function (page) { return page === _this.currentPage; })
.takeUntil(this.isDestroyed)
.subscribe(function (page) { return _this.onPageChange(page); });
}
};
ComplexListFieldComponent.prototype.ngOnChanges = function (changes) {
_super.prototype.ngOnChanges.call(this, changes);
var valuesChange = changes['values'];
if (valuesChange && !valuesChange.isFirstChange()) {
var preSize = valuesChange.previousValue.size;
var curSize = valuesChange.currentValue.size;
if (curSize !== preSize) {
if (this.navigator) {
// check if element added in the end by comparing the last elements
var elementAddedToEnd = valuesChange.previousValue.equals(valuesChange.currentValue.pop());
var lastPage = this.getPageForIndex(curSize - 1);
// change the page if a new element is added in the end and it's not on the last page
if (curSize > preSize && this.currentPage !== lastPage && elementAddedToEnd) {
this.currentPage = lastPage;
}
}
}
this.paginatableItems = this.getPaginatableItems();
this.paginatedItems = this.getPaginatableItemsForPage(this.currentPage);
}
};
ComplexListFieldComponent.prototype.hasProblemOrPatch = function (index) {
var itemPath = this.getPathStringForChild(index);
return this.problemsService.hasProblem(itemPath) || this.jsonStoreService.hasPatchOrChildrenHavePatch(itemPath);
};
Object.defineProperty(ComplexListFieldComponent.prototype, "headerItemTemplate", {
get: function () {
return this.appGlobalsService.templates[this.navigator.headerItemTemplateName];
},
enumerable: true,
configurable: true
});
ComplexListFieldComponent.prototype.onFindClick = function () {
var _this = this;
// clear for new search
this.foundIndices = [];
this.currentFound = 0;
// search to look for the first match
if (this.navigator.findSingle) {
var foundIndex = this.values
.findIndex(function (value) { return _this.navigator.findSingle(value, _this.findExpression); });
if (foundIndex > -1) {
this.foundIndices.push(foundIndex);
}
}
// search to look for all matches
if (this.foundIndices.length === 0 && this.navigator.findMultiple) {
this.values
.forEach(function (value, index) {
if (_this.navigator.findMultiple(value, _this.findExpression)) {
_this.foundIndices.push(index);
}
});
}
// navigate to first search result if found any
if (this.foundIndices.length > 0) {
this.navigateToItem(this.foundIndices[0]);
this.shouldDisplayFoundNavigation = true;
}
else {
this.shouldDisplayFoundNavigation = false;
}
};
ComplexListFieldComponent.prototype.onAddNewElementAtPosition = function (index) {
var _this = this;
var itemSchema = this.schema.items;
var emptyValue = this.emptyValueService.generateEmptyValue(itemSchema);
var values = this.jsonStoreService.getIn(this.path);
var insertIndex;
if (this.navigator) {
insertIndex = index + (this.navigator.itemsPerPage * (this.currentPage - 1));
}
else {
insertIndex = index;
}
var insertPath = this.path.concat(insertIndex);
this.jsonStoreService.addIn(insertPath, emptyValue);
// focus on the new added element
var insertPathString = this.pathUtilService.toPathString(insertPath);
setTimeout(function () {
_this.domUtilService.focusAndSelectFirstEditableChildById(insertPathString);
});
};
ComplexListFieldComponent.prototype.onFindInputKeypress = function (key) {
if (key === 'Enter') {
this.onFindClick();
}
};
ComplexListFieldComponent.prototype.onFoundNavigate = function (direction) {
// No bound checks, since the buttons are disabled in these cases.
this.currentFound += direction;
this.navigateToItem(this.foundIndices[this.currentFound]);
};
ComplexListFieldComponent.prototype.navigateToItem = function (index) {
var _this = this;
var item = this.paginatableItems.get(index);
if (!item.editFormDisplayedByUser) {
item.editFormDisplayedByUser = true;
this.changeDetectorRef.markForCheck();
}
var itemPath = this.path.concat(index);
var itemId = this.pathUtilService.toPathString(itemPath);
setTimeout(function () { return _this.domUtilService.focusAndSelectFirstEditableChildById(itemId); });
};
ComplexListFieldComponent.prototype.onPageChange = function (page) {
this.currentPage = page;
this.paginatedItems = this.getPaginatableItemsForPage(page);
};
ComplexListFieldComponent.prototype.getPaginatableItemsForPage = function (page) {
if (this.navigator) {
var begin = (page - 1) * this.navigator.itemsPerPage;
var end = (page * this.navigator.itemsPerPage);
return this.paginatableItems.slice(begin, end);
}
else {
return this.paginatableItems;
}
};
ComplexListFieldComponent.prototype.getPaginatableItems = function () {
var _this = this;
var viewTemplateConfig = this.schema.viewTemplateConfig;
return this.values
.map(function (value, index) {
var paginatableItem = _this.paginatableItems ? _this.paginatableItems.get(index) : null;
var isNewItem = paginatableItem == null;
var editFormDisplayedByUser = isNewItem ? null : paginatableItem.editFormDisplayedByUser;
var shouldDisplayEditForm = viewTemplateConfig ? viewTemplateConfig.showEditForm(value) : true;
return { index: index, shouldDisplayEditForm: shouldDisplayEditForm, editFormDisplayedByUser: editFormDisplayedByUser };
}).filter(function (item) {
if (_this.shouldDisplayOnlyEditFormItems) {
return item.shouldDisplayEditForm;
}
else {
return true;
}
});
};
ComplexListFieldComponent.prototype.getPageForIndex = function (index) {
return Math.floor((index / this.navigator.itemsPerPage) + 1);
};
Object.defineProperty(ComplexListFieldComponent.prototype, "customTemplate", {
get: function () {
return this.appGlobalsService.templates[this.schema.viewTemplateConfig.itemTemplateName];
},
enumerable: true,
configurable: true
});
Object.defineProperty(ComplexListFieldComponent.prototype, "shouldDisplayViewTemplate", {
get: function () {
return this.schema.viewTemplateConfig !== undefined;
},
enumerable: true,
configurable: true
});
Object.defineProperty(ComplexListFieldComponent.prototype, "sortable", {
get: function () {
return this.schema.sortable && !this.shouldDisplayOnlyEditFormItems;
},
enumerable: true,
configurable: true
});
ComplexListFieldComponent.prototype.shouldDisplayEditableFieldsForItem = function (item) {
// override default display state that is based on viewTemplateConfig.showEditForm(item) with user action
var shouldDisplayEditForm = item.editFormDisplayedByUser != null ? item.editFormDisplayedByUser : item.shouldDisplayEditForm;
return shouldDisplayEditForm || this.hasProblemOrPatch(item.index);
};
Object.defineProperty(ComplexListFieldComponent.prototype, "shouldDisplayOnlyEditFormItems", {
get: function () {
return this._shouldDisplayOnlyEditFormItems;
},
set: function (value) {
this.currentPage = 1;
this._shouldDisplayOnlyEditFormItems = value;
this.paginatableItems = this.getPaginatableItems();
this.paginatedItems = this.getPaginatableItemsForPage(this.currentPage);
},
enumerable: true,
configurable: true
});
return ComplexListFieldComponent;
}(AbstractListFieldComponent));
export { ComplexListFieldComponent };
ComplexListFieldComponent.decorators = [
{ type: Component, args: [{
selector: 'complex-list-field',
styles: [".complex-list-field-wrapper { margin: 10px 15px 15px 10px; padding: 5px; box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.25); } .top-bar-container { width: 100%; position: sticky; top: 46px; z-index: 1; display: flex; align-items: center; justify-content: space-between; padding: 0 15px; background-color: white; box-shadow: 0 0.5px 0 0 #ffffff inset, 0 1px 2px 0 #B3B3B3; } .item-count-label { position: relative; top: -19px; } .transparent { background: transparent; } .borderless { border: none; } .find-button { color: darkslategray; } .find-button .fa-search { opacity: 0.83; } .element-button-container { padding-top: 8px; } .element-button-container .text-right { padding: 0px; } label.btn { color: white !important; } .add-new-element { text-align: right; } "],
template: "<div [id]=\"pathString\"> <!-- Top Bar: Navigator, ToEdit/All switch, custom header item etc. --> <div *ngIf=\"navigator || shouldDisplayViewTemplate\" class=\"top-bar-container\"> <div *ngIf=\"navigator\"> <div class=\"input-group input-group-sm\"> <span class=\"input-group-btn\"> <button type=\"button\" class=\"btn btn-default find-button\" (click)=\"onFindClick()\"> <i class=\"fa fa-search\" aria-hidden=\"true\"></i> </button> </span> <input type=\"search\" class=\"form-control\" [(ngModel)]=\"findExpression\" (keypress)=\"onFindInputKeypress($event.key)\" placeholder=\"Find\" /> <span class=\"input-group-btn\" *ngIf=\"shouldDisplayFoundNavigation\"> <button type=\"button\" class=\"btn btn-default\" [disabled]=\"currentFound <= 0\" (click)=\"onFoundNavigate(-1)\">❮</button> </span> <span class=\"input-group-btn\" *ngIf=\"shouldDisplayFoundNavigation\"> <button type=\"button\" class=\"btn btn-default\" [disabled]=\"currentFound >= foundIndices.length - 1\" (click)=\"onFoundNavigate(1)\">❯</button> </span> <span *ngIf=\"foundIndices\" [ngSwitch]=\"foundIndices.length\" class=\"input-group-addon transparent borderless\"> <span *ngSwitchCase=\"0\"> Nothing found </span> <span *ngSwitchDefault> {{currentFound + 1}} of {{foundIndices.length}} </span> </span> </div> </div> <div *ngIf=\"shouldDisplayViewTemplate\" class=\"btn-group\"> <label class=\"btn btn-switch\" [class.active]=\"!shouldDisplayOnlyEditFormItems\" (click)=\"shouldDisplayOnlyEditFormItems = false\">All</label> <label class=\"btn btn-switch\" [class.active]=\"shouldDisplayOnlyEditFormItems\" (click)=\"shouldDisplayOnlyEditFormItems = true\">To Edit</label> </div> <div *ngIf=\"headerItemTemplate\"> <ng-template [ngTemplateOutlet]=\"headerItemTemplate\"></ng-template> </div> <div *ngIf=\"navigator\"> <label class=\"item-count-label\"> {{paginatableItems.size}} {{path[path.length - 1]}} </label> <br> <pagination [totalItems]=\"paginatableItems.size\" [ngModel]=\"currentPage\" [maxSize]=\"navigator.maxVisiblePageCount\" [itemsPerPage]=\"navigator.itemsPerPage\" class=\"pagination-sm pagination-top\" [boundaryLinks]=\"true\" [rotate]=\"false\" [firstText]=\"'❮❮'\" [previousText]=\"'❮'\" [nextText]=\"'❯'\" [lastText]=\"'❯❯'\" (pageChanged)=\"onPageChange($event.page)\"></pagination> </div> </div> <div [ngClass]=\"redLeftBorderClass\"> <!-- Elements --> <div *ngFor=\"let item of paginatedItems; index as i; trackBy:trackByElement\"> <div class=\"complex-list-field-wrapper\"> <div class=\"add-new-element\"> <a href=\"javascript:void(0)\" (click)=\"onAddNewElementAtPosition(i)\"> Add new element here </a> </div> <span *ngIf=\"shouldDisplayViewTemplate && values.get(item.index).keySeq().size != 0\"> <ng-template [ngTemplateOutlet]=\"customTemplate\" [ngTemplateOutletContext]=\"{item: values.get(item.index)}\"></ng-template> <a href=\"javascript:void(0)\" (click)=\"item.editFormDisplayedByUser = !shouldDisplayEditableFieldsForItem(item)\"> {{shouldDisplayEditableFieldsForItem(item) ? 'Hide Fields' : 'Show Fields'}} </a> </span> <span *ngIf=\"shouldDisplayEditableFieldsForItem(item)\"> <object-field [value]=\"values.get(item.index)\" [schema]=\"schema.items\" [path]=\"getPathForChild(item.index)\" [isComplexListFieldItem]=\"true\"> </object-field> <div class=\"row element-button-container\"> <div class=\"col-md-12 text-right\"> <list-action-group (onMove)=\"moveElement(item.index, $event)\" (onDelete)=\"deleteElement(item.index, values.get(item.index))\" [canMove]=\"sortable\" [isDisabled]=\"disabled || hasPatchOrChildrenHavePatch()\"> </list-action-group> </div> </div> </span> </div> </div> <div class=\"text-right\" *ngIf=\"removeJsonPatch\"> <patch-actions [patch]=\"removeJsonPatch\"></patch-actions> </div> </div> <div *ngFor=\"let patch of addJsonPatches\" class=\"complex-list-field-wrapper\"> <add-or-replace-patch [patch]=\"patch\"></add-or-replace-patch> </div> <div *ngIf=\"replaceJsonPatches && replaceJsonPatches[0]\"> <add-or-replace-patch [patch]=\"replaceJsonPatches[0]\"></add-or-replace-patch> </div> </div> ",
changeDetection: ChangeDetectionStrategy.OnPush
},] },
];
/** @nocollapse */
ComplexListFieldComponent.ctorParameters = function () { return [
{ type: AppGlobalsService, },
{ type: ProblemsService, },
{ type: JsonStoreService, },
{ type: DomUtilService, },
{ type: PathUtilService, },
{ type: ChangeDetectorRef, },
{ type: EmptyValueService, },
{ type: ListPageChangerService, },
]; };
ComplexListFieldComponent.propDecorators = {
'values': [{ type: Input },],
'supportValues': [{ type: Input },],
'schema': [{ type: Input },],
'path': [{ type: Input },],
};
//# sourceMappingURL=complex-list-field.component.js.map