ng2-json-editor
Version:
Angular2 component for editing large json documents
252 lines • 10.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.
*/
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