UNPKG

ng2-json-editor

Version:

Angular2 component for editing large json documents

252 lines 10.6 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. */ import { Injectable } from '@angular/core'; import { Map, List, fromJS } from 'immutable'; import { ReplaySubject } from 'rxjs/ReplaySubject'; import { Subject } from 'rxjs/Subject'; import { PathUtilService } from './path-util.service'; import { KeysStoreService } from './keys-store.service'; import { SizedStack } from '../classes'; var JsonStoreService = (function () { function JsonStoreService(pathUtilService, keysStoreService) { this.pathUtilService = pathUtilService; this.keysStoreService = keysStoreService; this.patchesByPath$ = new ReplaySubject(1); this.json$ = new Subject(); this.jsonPatches$ = new Subject(); this.patchesByPath = {}; // list of reverse patches for changes this.history = new SizedStack(10); } JsonStoreService.prototype.setIn = function (path, value, allowUndo) { if (allowUndo === void 0) { allowUndo = true; } if (value === '' || value === undefined) { this.removeIn(path); return; } value = this.toImmutable(value); // immutablejs setIn creates Map for keys that don't exist in path // therefore List() should be set manually for some of those keys. this.setEmptyListBeforeEachIndexInPath(path); if (allowUndo) { this.pushRevertPatchToHistory(path, 'replace'); } // set new value this.json = this.json.setIn(path, value); this.keysStoreService.syncKeysForPath(path, this.json); this.json$.next(this.json); }; JsonStoreService.prototype.setEmptyListBeforeEachIndexInPath = function (path) { for (var i = 0; i < path.length - 1; i++) { var currentPath = path.slice(0, i + 1); if (!this.json.hasIn(currentPath) && typeof path[i + 1] === 'number') { this.json = this.json.setIn(currentPath, List()); } } }; JsonStoreService.prototype.getIn = function (path, notSetValue) { return this.json.getIn(path, notSetValue); }; JsonStoreService.prototype.removeIn = function (path) { this.pushRevertPatchToHistory(path, 'add'); this.json = this.json.removeIn(path); this.json$.next(this.json); this.keysStoreService.deletePath(path); }; JsonStoreService.prototype.pushRevertPatchToHistory = function (path, revertOp) { this.history.push({ path: this.pathUtilService.toPathString(path), op: revertOp, value: this.json.getIn(path) }); }; JsonStoreService.prototype.addIn = function (path, value) { var lastPathElement = path[path.length - 1]; var isInsert = typeof lastPathElement === 'number' || lastPathElement === '-'; if (isInsert) { var pathWithoutIndex = path.slice(0, path.length - 1); var list = this.getIn(pathWithoutIndex) || List(); value = this.toImmutable(value); if (lastPathElement === '-') { list = list.push(value); path[path.length - 1] = list.size - 1; } else { list = list.insert(lastPathElement, value); } // allowUndo=false to avoid creating replace history patch when adding an item to a list. this.setIn(pathWithoutIndex, list, false); } else { this.setIn(path, value); } }; JsonStoreService.prototype.toImmutable = function (value) { if (typeof value === 'object' && !(List.isList(value) || Map.isMap(value))) { return fromJS(value); } return value; }; /** * Moves the element at given index UP or DOWN within the list * @param listPath path to a list in json * @param index index of the element that is being moved * @param direction 1 for DOWN, -1 for UP movement * @return new path of the moved element */ JsonStoreService.prototype.moveIn = function (listPath, index, direction) { var list = this.getIn(listPath); var newIndex = index + direction; if (newIndex >= list.size || newIndex < 0) { newIndex = list.size - Math.abs(newIndex); } var temp = list.get(index); list = list .set(index, list.get(newIndex)) .set(newIndex, temp); this.setIn(listPath, list); this.keysStoreService.swapListElementKeys(listPath, index, newIndex); return listPath.concat(newIndex); }; JsonStoreService.prototype.setJson = function (json) { this.json = json; }; JsonStoreService.prototype.setJsonPatches = function (patches) { var _this = this; this.patchesByPath = {}; patches.forEach(function (patch) { var path = _this.getComponentPathForPatch(patch); if (!_this.patchesByPath[path]) { _this.patchesByPath[path] = []; } _this.patchesByPath[path].push(patch); }); this.jsonPatches = patches; this.patchesByPath$.next(this.patchesByPath); }; JsonStoreService.prototype.rollbackLastChange = function () { var lastChangeReversePatch = this.history.pop(); if (lastChangeReversePatch) { this.applyPatch(lastChangeReversePatch, false); return lastChangeReversePatch.path; } else { return undefined; } }; JsonStoreService.prototype.applyPatch = function (patch, allowUndo) { if (allowUndo === void 0) { allowUndo = true; } var path = this.pathUtilService.toPathArray(patch.path); switch (patch.op) { case 'replace': this.setIn(path, patch.value, allowUndo); break; case 'remove': this.removeIn(path); break; case 'add': // custom type for adding a replace patch as new. case 'add-as-new': this.addIn(path, patch.value); break; default: console.warn(patch.op + " is not supported!"); } this.removeJsonPatch(patch); }; JsonStoreService.prototype.rejectPatch = function (patch) { this.removeJsonPatch(patch); }; JsonStoreService.prototype.hasPatch = function (path) { return this.patchesByPath[path] && this.patchesByPath[path].length > 0; }; JsonStoreService.prototype.hasPatchOrChildrenHavePatch = function (path) { if (this.hasPatch(path)) { return true; } if (Object.keys(this.patchesByPath).some(function (patch) { return patch.includes(path); })) { return true; } if (this.jsonPatches) { var childPathPrefix_1 = "" + path + this.pathUtilService.separator; return this.jsonPatches .some(function (patch) { return patch.path.startsWith(childPathPrefix_1); }); } return false; }; JsonStoreService.prototype.removeJsonPatch = function (patch) { var path = this.getComponentPathForPatch(patch); // don't do anything if it's UNDO json-patch. if (this.patchesByPath[path]) { var patchIndex = this.patchesByPath[path].indexOf(patch); if (patchIndex > -1) { // if there is more than one patch in the same path remove all of them when 'remove' if (patch.op === 'remove' && this.patchesByPath[path].length > 1) { this.patchesByPath[path] = []; this.jsonPatches = this.jsonPatches.filter(function (p) { return p.path !== path; }); } else { this.patchesByPath[path].splice(patchIndex, 1); var globalPatchIndex = this.jsonPatches.indexOf(patch); this.jsonPatches.splice(globalPatchIndex, 1); } this.patchesByPath$.next(this.patchesByPath); this.jsonPatches$.next(this.jsonPatches); } } }; JsonStoreService.prototype.getComponentPathForPatch = function (patch) { if (patch.op === 'add') { // add patches handled by parent component return this.getParentPath(patch.path); } return patch.path; }; JsonStoreService.prototype.getParentPath = function (path) { var pathArray = this.pathUtilService.toPathArray(path); var parentPathArray = pathArray.slice(0, -1); return this.pathUtilService.toPathString(parentPathArray); }; JsonStoreService.prototype.getPatchesIncludingPath = function (path) { var _this = this; var pathsWithPatches = Object.keys(this.patchesByPath).filter(function (patch) { return patch.includes(path); }); var patches = pathsWithPatches.map(function (p) { return _this.patchesByPath[p]; }); return [].concat.apply([], patches); }; JsonStoreService.prototype.deletePatchForElement = function (path) { var _this = this; if (this.getPatchesIncludingPath(path)) { this.getPatchesIncludingPath(path).forEach(function (patch) { return _this.removeJsonPatch(patch); }); } }; return JsonStoreService; }()); export { JsonStoreService }; JsonStoreService.decorators = [ { type: Injectable }, ]; /** @nocollapse */ JsonStoreService.ctorParameters = function () { return [ { type: PathUtilService, }, { type: KeysStoreService, }, ]; }; //# sourceMappingURL=json-store.service.js.map