Bring in bundle platform/core from the sandbox branch, in preparation for clean up, tests, and integration. WTD-573
235 lines
7.7 KiB
JavaScript
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;
|
|
}
|
|
); |