Files
openmct/platform/core/src/actions/duplicate-action.js
Victor Woeltjen 0fdce798f7 [Core] Bring in core bundle from sandbox
Bring in bundle platform/core from the sandbox
branch, in preparation for clean up, tests, and
integration. WTD-573
2014-11-20 12:58:21 -08:00

235 lines
7.7 KiB
JavaScript

/*global define,Promise*/
/**
* Module defining duplicate action. Created by vwoeltje on 11/5/14.
*/
define(
['core/promises', 'core/action/duplicate-wizard', 'uuid'],
function (promises, DuplicateWizard, uuid) {
"use strict";
/**
* Deep-copy a domain object and its composition.
* @constructor
*/
function DuplicateAction(context, dialogService, persistenceService, spaceName) {
var object = context.selection[0].object;
function makeWizard(parameters) {
return new DuplicateWizard(
object.getModel(),
parameters.type,
parameters.parent
);
}
function getParent() {
return object.getCapability('context').then(function (c) {
return c.getParent();
});
}
function showDialog(wizard) {
return dialogService.getUserInput(
{ sections: wizard.getSections() },
"Duplicate " + object.getModel().name
);
}
function getComposition(object) {
return object.getCapability('composition').then(
function (c) { return c.list(); },
function () { return []; }
);
}
function getModels() {
var models = {};
function populateModelsFor(object) {
var id = object.getId();
// Already stored this object, don't keep going
if (models[id]) {
return models;
}
// Clone to new map
models[id] = JSON.parse(JSON.stringify(object.getModel()));
return getComposition(object).then(function (objs) {
return promises.merge(objs.map(populateModelsFor));
});
}
return populateModelsFor(object).then(function () {
return models;
});
}
function buildIdMap(ids) {
var idMap = {};
ids.forEach(function (id) {
idMap[id] = uuid();
});
return idMap;
}
function rewriteComposition(models, idMap) {
Object.keys(models).forEach(function (id) {
if (models[id].composition) {
models[id].composition = models[id].composition.map(function (childId) {
return idMap[childId] || childId;
});
}
});
return models;
}
function shouldRewrite(state, idMap) {
var keys;
function isId(key) {
return Object.prototype.hasOwnProperty.apply(idMap, [key]);
}
function and(a, b) {
return a && b;
}
keys = Object.keys(state);
return keys.length > 0 && keys.map(isId).reduce(and, true);
}
function rewriteIdentifierKeys(state, idMap) {
if (typeof state !== 'object' || state === null) {
return state;
}
if (shouldRewrite(state, idMap)) {
// Rewrite the keys of a JavaScript object
Object.keys(state).forEach(function (id) {
var newId = idMap[id] || id,
oldState = state[id];
delete state[id];
state[newId] = oldState;
});
}
// Recursively search for model contents which
// look like id maps
Object.keys(state).forEach(function (k) {
state[k] = rewriteIdentifierKeys(state[k], idMap);
});
return state;
}
function rewriteIdentifiers(models, idMap) {
var newModels = {};
Object.keys(models).forEach(function (id) {
var newId = idMap[id] || id;
newModels[newId] = models[id];
});
return newModels;
}
function doPersist(models) {
var ids = Object.keys(models);
return promises.merge(ids.map(function (id) {
return persistenceService.createObject(
spaceName,
id,
models[id]
);
}));
}
function doDuplicate(newModel) {
var idMap;
if (!newModel) {
return undefined;
}
return getModels().then(function (models) {
// Add in the model from user input
models[object.getId()] = newModel;
idMap = buildIdMap(Object.keys(models));
rewriteComposition(models, idMap);
models = rewriteIdentifiers(models, idMap);
return rewriteIdentifierKeys(models, idMap);
}).then(doPersist).then(function () {
// Return the new identifier for the object
return idMap[object.getId()];
});
}
function addToComposition(destination, id) {
function mutator(model) {
if (model.composition) {
model.composition.push(id);
}
}
return destination.getCapability('mutation').then(
function (m) { return m.mutate(mutator); }
).then(function () {
return destination.getCapability('persistence');
}).then(function (p) {
return p.persist();
});
}
function perform() {
var destination, wizard;
// Pop up the create dialog
promises.merge({
type: object.getCapability('type'),
parent: getParent()
}).then(function (params) {
// Record parent, to add to composition later
destination = params.parent;
return params;
}).then(function (params) {
wizard = makeWizard(params);
return wizard;
}).then(showDialog).then(function (formValue) {
// If user picked a different destination, use that
if (formValue && formValue.createParent) {
destination = formValue.createParent;
}
return formValue && wizard.createModel(formValue);
}).then(doDuplicate).then(function (newId) {
return addToComposition(destination, newId);
});
}
function metadata() {
return {
id: 'duplicate-' + object.getId(),
name: "Duplicate...",
category: 'contextual',
glyph: "+",
context: context,
description: "Make a copy of this object, and its contained objects."
};
}
return {
perform: perform,
metadata: metadata
};
}
return DuplicateAction;
}
);