Enable changing Task structure
Provide unit-tests for verifying that Task structure depends both on parent Workflow type and on Task type. This commits also depends on a change made to Barricade.js library: now it passes the parameters of a parent container to the children containers, which add new elements to it via prototype inheritance. Closes-Bug: #1446230 Implements: blueprint merlin-unittests Change-Id: Ic4c0539297d6df9a0b1450a824eeca4749455cfd
This commit is contained in:
parent
05f4f22b9e
commit
0b92f674a4
|
@ -21,7 +21,7 @@
|
|||
function getWorkbookNextIDSuffix(base) {
|
||||
var containerName = base + 's',
|
||||
regexp = /(workflow|action)([0-9]+)/,
|
||||
container = workbook.get(containerName);
|
||||
container = $scope.workbook.get(containerName);
|
||||
if ( !container ) {
|
||||
throw 'Base should be either "action" or "workflow"!';
|
||||
}
|
||||
|
@ -33,13 +33,15 @@
|
|||
$scope.addAction = function() {
|
||||
var nextSuffix = getWorkbookNextIDSuffix(baseActionId),
|
||||
newID = baseActionId + nextSuffix;
|
||||
workbook.get('actions').push({name: 'Action ' + nextSuffix}, {id: newID});
|
||||
$scope.workbook.get('actions').push(
|
||||
{name: 'Action ' + nextSuffix}, {id: newID});
|
||||
};
|
||||
|
||||
$scope.addWorkflow = function() {
|
||||
var nextSuffix = getWorkbookNextIDSuffix(baseWorkflowId),
|
||||
newID = baseWorkflowId + nextSuffix;
|
||||
workbook.get('workflows').push({name: 'Workflow ' + nextSuffix}, {id: newID});
|
||||
$scope.workbook.get('workflows').push(
|
||||
{name: 'Workflow ' + nextSuffix}, {id: newID});
|
||||
};
|
||||
|
||||
}])
|
||||
|
|
|
@ -197,6 +197,15 @@
|
|||
});
|
||||
|
||||
models.Task = fields.frozendict.extend({
|
||||
create: function(json, parameters) {
|
||||
var self = fields.frozendict.create.call(this, json, parameters);
|
||||
self.on('childChange', function(child, op) {
|
||||
if ( child === self.get('type') && op !== 'id' ) {
|
||||
self.emit('change', 'taskType');
|
||||
}
|
||||
});
|
||||
return self;
|
||||
},
|
||||
_getPrettyJSON: function() {
|
||||
var json = fields.frozendict._getPrettyJSON.apply(this, arguments);
|
||||
delete json.name;
|
||||
|
@ -219,32 +228,27 @@
|
|||
},
|
||||
'type': {
|
||||
'@class': fields.string.extend({}, {
|
||||
'@enum': ['Action-based', 'Workflow-based'],
|
||||
'@enum': [{
|
||||
value: 'action', label: 'Action-based'
|
||||
}, {
|
||||
value: 'workflow', label: 'Workflow-based'
|
||||
}],
|
||||
'@default': 'action',
|
||||
'@meta': {
|
||||
'index': 1,
|
||||
'row': 0
|
||||
}
|
||||
})
|
||||
},
|
||||
'action': {
|
||||
'@class': fields.string.extend({}, {
|
||||
'description': {
|
||||
'@class': fields.text.extend({}, {
|
||||
'@meta': {
|
||||
'index': 2,
|
||||
'index': 1,
|
||||
'row': 1
|
||||
}
|
||||
})
|
||||
},
|
||||
'input': {
|
||||
'@class': fields.dictionary.extend({}, {
|
||||
'@meta': {
|
||||
'index': 3
|
||||
},
|
||||
'?': {
|
||||
'@class': fields.string
|
||||
}
|
||||
})
|
||||
},
|
||||
'publish': {
|
||||
'@class': fields.dictionary.extend({}, {
|
||||
'@meta': {
|
||||
'index': 4
|
||||
|
@ -254,35 +258,12 @@
|
|||
}
|
||||
})
|
||||
},
|
||||
'on-error': {
|
||||
'@class': fields.list.extend({}, {
|
||||
'publish': {
|
||||
'@class': fields.dictionary.extend({}, {
|
||||
'@meta': {
|
||||
'title': 'On error',
|
||||
'index': 5
|
||||
},
|
||||
'*': {
|
||||
'@class': fields.string
|
||||
}
|
||||
})
|
||||
},
|
||||
'on-success': {
|
||||
'@class': fields.list.extend({}, {
|
||||
'@meta': {
|
||||
'title': 'On success',
|
||||
'index': 6
|
||||
},
|
||||
'*': {
|
||||
'@class': fields.string
|
||||
}
|
||||
})
|
||||
},
|
||||
'on-complete': {
|
||||
'@class': fields.list.extend({}, {
|
||||
'@meta': {
|
||||
'title': 'On complete',
|
||||
'index': 7
|
||||
},
|
||||
'*': {
|
||||
'?': {
|
||||
'@class': fields.string
|
||||
}
|
||||
})
|
||||
|
@ -300,7 +281,7 @@
|
|||
}
|
||||
}, {
|
||||
'@meta': {
|
||||
'index': 8
|
||||
'index': 9
|
||||
},
|
||||
'@required': false,
|
||||
'wait-before': {
|
||||
|
@ -366,6 +347,94 @@
|
|||
}
|
||||
});
|
||||
|
||||
models.ReverseWFTask = models.Task.extend({}, {
|
||||
'requires': {
|
||||
'@class': fields.string.extend({}, {
|
||||
'@meta': {
|
||||
'row': 2,
|
||||
'index': 3
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
models.DirectWFTask = models.Task.extend({}, {
|
||||
'on-error': {
|
||||
'@class': fields.list.extend({}, {
|
||||
'@meta': {
|
||||
'title': 'On error',
|
||||
'index': 6
|
||||
},
|
||||
'*': {
|
||||
'@class': fields.string
|
||||
}
|
||||
})
|
||||
},
|
||||
'on-success': {
|
||||
'@class': fields.list.extend({}, {
|
||||
'@meta': {
|
||||
'title': 'On success',
|
||||
'index': 7
|
||||
},
|
||||
'*': {
|
||||
'@class': fields.string
|
||||
}
|
||||
})
|
||||
},
|
||||
'on-complete': {
|
||||
'@class': fields.list.extend({}, {
|
||||
'@meta': {
|
||||
'title': 'On complete',
|
||||
'index': 8
|
||||
},
|
||||
'*': {
|
||||
'@class': fields.string
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
models.ActionTaskMixin = Barricade.Blueprint.create(function() {
|
||||
return this.extend({}, {
|
||||
'action': {
|
||||
'@class': fields.string.extend({}, {
|
||||
'@meta': {
|
||||
'row': 1,
|
||||
'index': 2
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
models.WorkflowTaskMixin = Barricade.Blueprint.create(function() {
|
||||
return this.extend({}, {
|
||||
'workflow': {
|
||||
'@class': fields.string.extend({}, {
|
||||
'@meta': {
|
||||
'row': 1,
|
||||
'index': 2
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var taskTypes = {
|
||||
'direct': models.DirectWFTask,
|
||||
'reverse': models.ReverseWFTask,
|
||||
'action': models.ActionTaskMixin,
|
||||
'workflow': models.WorkflowTaskMixin
|
||||
};
|
||||
|
||||
function TaskFactory(json, parameters) {
|
||||
var type = json.type || 'action',
|
||||
baseClass = taskTypes[parameters.wfType],
|
||||
mixinClass = taskTypes[type],
|
||||
taskClass = mixinClass.call(baseClass);
|
||||
return taskClass.create(json, parameters);
|
||||
}
|
||||
|
||||
models.Workflow = fields.frozendict.extend({
|
||||
create: function(json, parameters) {
|
||||
var self = fields.frozendict.create.call(this, json, parameters);
|
||||
|
@ -423,13 +492,29 @@
|
|||
})
|
||||
},
|
||||
'tasks': {
|
||||
'@class': fields.dictionary.extend({}, {
|
||||
'@class': fields.dictionary.extend({
|
||||
create: function(json, parameters) {
|
||||
var self = fields.dictionary.create.call(this, json, parameters);
|
||||
self.on('childChange', function(child, op) {
|
||||
if ( op === 'taskType' ) {
|
||||
var taskId = child.getID(),
|
||||
params = child._parameters,
|
||||
taskPos = self.getPosByID(taskId),
|
||||
taskData = child.toJSON();
|
||||
params.id = taskId;
|
||||
self.set(taskPos, TaskFactory(taskData, params));
|
||||
}
|
||||
});
|
||||
return self;
|
||||
}
|
||||
}, {
|
||||
'@meta': {
|
||||
'index': 5,
|
||||
'group': true
|
||||
},
|
||||
'?': {
|
||||
'@class': models.Task
|
||||
'@class': models.Task,
|
||||
'@factory': TaskFactory
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -481,6 +566,7 @@
|
|||
|
||||
function workflowFactory(json, parameters) {
|
||||
var type = json.type || 'direct';
|
||||
parameters.wfType = type;
|
||||
return workflowTypes[type].create(json, parameters);
|
||||
}
|
||||
|
||||
|
@ -539,11 +625,11 @@
|
|||
if ( op === 'workflowType' ) {
|
||||
var workflowId = child.getID(),
|
||||
workflowPos = self.getPosByID(workflowId),
|
||||
workflowData = child.toJSON(),
|
||||
newType = child.get('type').get(),
|
||||
newWorkflow = workflowTypes[newType].create(
|
||||
workflowData, {id: workflowId});
|
||||
self.set(workflowPos, newWorkflow);
|
||||
params = child._parameters,
|
||||
workflowData = child.toJSON();
|
||||
params.wfType = child.type;
|
||||
params.id = workflowId;
|
||||
self.set(workflowPos, workflowFactory(workflowData, params));
|
||||
}
|
||||
});
|
||||
return self;
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
|
||||
/* Copyright (c) 2014 Mirantis, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
not use this file except in compliance with the License. You may obtain
|
||||
a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
describe('workbook model logic', function() {
|
||||
var models, utils, workbook;
|
||||
|
||||
beforeEach(function() {
|
||||
module('mistral');
|
||||
inject(function($injector) {
|
||||
models = $injector.get('mistral.workbook.models');
|
||||
utils = $injector.get('merlin.utils');
|
||||
});
|
||||
workbook = models.Workbook.create();
|
||||
});
|
||||
|
||||
function getWorkflow(workflowID) {
|
||||
return workbook.get('workflows').getByID(workflowID);
|
||||
}
|
||||
|
||||
describe('defines workflow structure transformations:', function() {
|
||||
var workflowID = 'workflow1';
|
||||
|
||||
beforeEach(function() {
|
||||
workbook.get('workflows').push({name: 'Workflow 1'}, {id: workflowID});
|
||||
});
|
||||
|
||||
it("new workflow starts as a 'direct' workflow and has proper structure", function() {
|
||||
var workflow = getWorkflow(workflowID);
|
||||
|
||||
expect(workflow.get('type').get()).toEqual('direct');
|
||||
expect(workflow.instanceof(models.DirectWorkflow)).toBe(true);
|
||||
});
|
||||
|
||||
it("after setting type to 'reverse' the workflow structure changes to the proper one", function() {
|
||||
getWorkflow(workflowID).get('type').set('reverse');
|
||||
|
||||
expect(getWorkflow(workflowID).instanceof(models.ReverseWorkflow)).toBe(true);
|
||||
});
|
||||
|
||||
it("changing 'reverse' type to 'direct' again causes workflow structure to properly change", function() {
|
||||
getWorkflow(workflowID).get('type').set('reverse');
|
||||
getWorkflow(workflowID).get('type').set('direct');
|
||||
|
||||
expect(getWorkflow(workflowID).instanceof(models.DirectWorkflow)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('defines task structure transformations', function() {
|
||||
var workflowID = 'workflow1',
|
||||
taskID = 'task1';
|
||||
|
||||
function getTask(taskID) {
|
||||
return getWorkflow(workflowID).get('tasks').getByID(taskID);
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
workbook.get('workflows').push({name: 'Workflow 1'}, {id: workflowID});
|
||||
});
|
||||
|
||||
describe("which start with the 'direct' workflow:", function() {
|
||||
beforeEach(function() {
|
||||
var workflow = getWorkflow(workflowID),
|
||||
params = workflow._parameters;
|
||||
workflow.get('tasks').push({name: 'Task 1'}, utils.extend(params, {id: taskID}));
|
||||
});
|
||||
|
||||
it("new task starts as an 'action'-based one and has proper structure", function() {
|
||||
expect(getTask(taskID).get('type').get()).toEqual('action');
|
||||
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||
});
|
||||
|
||||
it("changing task type from 'action' to 'workflow' causes proper structure changes", function() {
|
||||
getTask(taskID).get('type').set('workflow');
|
||||
|
||||
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||
});
|
||||
|
||||
it("changing workflow type to 'reverse' causes the proper changes to its tasks", function() {
|
||||
getWorkflow(workflowID).get('type').set('reverse');
|
||||
|
||||
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||
|
||||
getTask(taskID).get('type').set('workflow');
|
||||
|
||||
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||
});
|
||||
|
||||
it("changing workflow type from 'reverse' to 'direct' causes the proper changes to its tasks", function() {
|
||||
getWorkflow(workflowID).get('type').set('reverse');
|
||||
getWorkflow(workflowID).get('type').set('direct');
|
||||
|
||||
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||
|
||||
getTask(taskID).get('type').set('workflow');
|
||||
|
||||
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("which start with the 'reverse' workflow:", function() {
|
||||
beforeEach(function() {
|
||||
var workflow;
|
||||
getWorkflow(workflowID).get('type').set('reverse');
|
||||
workflow = getWorkflow(workflowID);
|
||||
workflow.get('tasks').push(
|
||||
{name: 'Task 1'}, utils.extend(workflow._parameters, {id: taskID}));
|
||||
});
|
||||
|
||||
it("new task starts as an 'action'-based one and has proper structure", function() {
|
||||
expect(getTask(taskID).get('type').get()).toEqual('action');
|
||||
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||
});
|
||||
|
||||
it("changing task type from 'action' to 'workflow' causes proper structure changes", function() {
|
||||
getTask(taskID).get('type').set('workflow');
|
||||
|
||||
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||
});
|
||||
|
||||
it("changing workflow type to 'direct' causes the proper changes to its tasks", function() {
|
||||
getWorkflow(workflowID).get('type').set('direct');
|
||||
|
||||
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||
|
||||
getTask(taskID).get('type').set('workflow');
|
||||
|
||||
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.DirectWFTask)).toBe(true);
|
||||
});
|
||||
|
||||
it("changing workflow type from 'direct' to 'reverse' causes the proper changes to its tasks", function() {
|
||||
getWorkflow(workflowID).get('type').set('direct');
|
||||
getWorkflow(workflowID).get('type').set('reverse');
|
||||
|
||||
expect(getTask(taskID).instanceof(models.ActionTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||
|
||||
getTask(taskID).get('type').set('workflow');
|
||||
|
||||
expect(getTask(taskID).instanceof(models.WorkflowTaskMixin)).toBe(true);
|
||||
expect(getTask(taskID).instanceof(models.ReverseWFTask)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('defines top-level actions available to user:', function() {
|
||||
var $scope;
|
||||
|
||||
beforeEach(inject(function(_$controller_) {
|
||||
var $controller = _$controller_;
|
||||
$scope = {};
|
||||
$controller('workbookCtrl', {$scope: $scope});
|
||||
$scope.workbook = workbook;
|
||||
}));
|
||||
|
||||
describe("'Add Action' action", function() {
|
||||
it('adds a new Action', function() {
|
||||
$scope.addAction();
|
||||
|
||||
expect(workbook.get('actions').get(0)).toBeDefined();
|
||||
});
|
||||
|
||||
it('creates action with predefined name', function() {
|
||||
$scope.addAction();
|
||||
|
||||
expect(workbook.get('actions').get(0).get('name').get()).toBeGreaterThan('');
|
||||
});
|
||||
|
||||
it('creates actions with different names on 2 successive calls', function() {
|
||||
$scope.addAction();
|
||||
$scope.addAction();
|
||||
|
||||
expect(workbook.get('actions').get(0).get('name').get()).not.toEqual(
|
||||
workbook.get('actions').get(1).get('name').get())
|
||||
});
|
||||
});
|
||||
|
||||
describe("'Add Workflow' action", function() {
|
||||
it('adds a new Workflow', function() {
|
||||
$scope.addWorkflow();
|
||||
|
||||
expect(workbook.get('workflows').get(0)).toBeDefined();
|
||||
});
|
||||
|
||||
it('creates workflow with predefined name', function() {
|
||||
$scope.addWorkflow();
|
||||
|
||||
expect(workbook.get('workflows').get(0).get('name').get()).toBeGreaterThan('');
|
||||
});
|
||||
|
||||
it('creates workflows with different names on 2 successive calls', function() {
|
||||
$scope.addWorkflow();
|
||||
$scope.addWorkflow();
|
||||
|
||||
expect(workbook.get('workflows').get(0).get('name').get()).not.toEqual(
|
||||
workbook.get('workflows').get(1).get('name').get())
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
});
|
|
@ -33,22 +33,27 @@ module.exports = function (config) {
|
|||
],
|
||||
|
||||
files: [
|
||||
'./bower_components/angular/angular.js',
|
||||
'./bower_components/angular-mocks/angular-mocks.js',
|
||||
'./merlin/static/merlin/js/lib/underscore-min.js',
|
||||
'./merlin/static/merlin/js/merlin.init.js',
|
||||
'./merlin/static/merlin/js/merlin.templates.js',
|
||||
'./merlin/static/merlin/js/merlin.directives.js',
|
||||
'./merlin/static/merlin/js/merlin.filters.js',
|
||||
'./merlin/static/merlin/js/merlin.field.models.js',
|
||||
'./merlin/static/merlin/js/merlin.panel.models.js',
|
||||
'./merlin/static/merlin/js/merlin.utils.js',
|
||||
'./merlin/static/merlin/js/lib/angular-filter.js',
|
||||
'./merlin/static/merlin/js/lib/barricade.js',
|
||||
'./merlin/static/merlin/js/lib/js-yaml.js',
|
||||
'bower_components/angular/angular.js',
|
||||
'bower_components/angular-mocks/angular-mocks.js',
|
||||
'merlin/static/merlin/js/lib/underscore-min.js',
|
||||
'merlin/static/merlin/js/merlin.init.js',
|
||||
'merlin/static/merlin/js/merlin.templates.js',
|
||||
'merlin/static/merlin/js/merlin.directives.js',
|
||||
'merlin/static/merlin/js/merlin.filters.js',
|
||||
'merlin/static/merlin/js/merlin.field.models.js',
|
||||
'merlin/static/merlin/js/merlin.panel.models.js',
|
||||
'merlin/static/merlin/js/merlin.utils.js',
|
||||
'merlin/static/merlin/js/lib/angular-filter.js',
|
||||
'merlin/static/merlin/js/lib/barricade.js',
|
||||
'merlin/static/merlin/js/lib/js-yaml.js',
|
||||
'merlin/test/js/utilsSpec.js',
|
||||
'merlin/test/js/templatesSpec.js',
|
||||
'merlin/test/js/filtersSpec.js'
|
||||
'merlin/test/js/filtersSpec.js',
|
||||
|
||||
'extensions/mistral/static/mistral/js/mistral.init.js',
|
||||
'extensions/mistral/static/mistral/js/mistral.workbook.models.js',
|
||||
'extensions/mistral/static/mistral/js/mistral.workbook.controllers.js',
|
||||
'extensions/mistral/test/js/workbookSpec.js'
|
||||
],
|
||||
|
||||
exclude: [
|
||||
|
|
|
@ -47,11 +47,12 @@ var Barricade = (function () {
|
|||
*/
|
||||
create: function (f) {
|
||||
return function g() {
|
||||
if (!Object.prototype.hasOwnProperty.call(this, '_parents')) {
|
||||
Object.defineProperty(this, '_parents', {value: []});
|
||||
var result = f.apply(this, arguments) || this;
|
||||
if (!Object.prototype.hasOwnProperty.call(result, '_parents')) {
|
||||
Object.defineProperty(result, '_parents', {value: []});
|
||||
}
|
||||
this._parents.push(g);
|
||||
return f.apply(this, arguments);
|
||||
result._parents.push(g);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -547,7 +548,7 @@ var Barricade = (function () {
|
|||
create: function (json, parameters) {
|
||||
var self = this.extend({}),
|
||||
schema = self._schema,
|
||||
isUsed;
|
||||
isUsed, id;
|
||||
|
||||
self._parameters = parameters = parameters || {};
|
||||
|
||||
|
@ -570,7 +571,10 @@ var Barricade = (function () {
|
|||
Enumerated.call(self, schema['@enum']);
|
||||
}
|
||||
|
||||
Identifiable.call(self, parameters.id);
|
||||
if ( Object.hasOwnProperty.call(parameters, 'id') ) {
|
||||
id = parameters.id;
|
||||
}
|
||||
Identifiable.call(self, id);
|
||||
|
||||
return self;
|
||||
},
|
||||
|
@ -871,10 +875,10 @@ var Barricade = (function () {
|
|||
* @memberof Barricade.Arraylike
|
||||
* @private
|
||||
*/
|
||||
_sift: function (json) {
|
||||
_sift: function (json, parameters) {
|
||||
return json.map(function (el) {
|
||||
return this._keyClassCreate(
|
||||
this._elSymbol, this._elementClass, el);
|
||||
this._elSymbol, this._elementClass, el, parameters);
|
||||
}, this);
|
||||
},
|
||||
|
||||
|
@ -1030,11 +1034,11 @@ var Barricade = (function () {
|
|||
* @memberof Barricade.ImmutableObject
|
||||
* @private
|
||||
*/
|
||||
_sift: function (json) {
|
||||
_sift: function (json, parameters) {
|
||||
var self = this;
|
||||
return this.getKeys().reduce(function (objOut, key) {
|
||||
objOut[key] =
|
||||
self._keyClassCreate(key, self._keyClasses[key], json[key]);
|
||||
objOut[key] = self._keyClassCreate(
|
||||
key, self._keyClasses[key], json[key], parameters);
|
||||
return objOut;
|
||||
}, {});
|
||||
},
|
||||
|
@ -1171,10 +1175,12 @@ var Barricade = (function () {
|
|||
* @memberof Barricade.MutableObject
|
||||
* @private
|
||||
*/
|
||||
_sift: function (json) {
|
||||
_sift: function (json, parameters) {
|
||||
return Object.keys(json).map(function (key) {
|
||||
return this._keyClassCreate(this._elSymbol, this._elementClass,
|
||||
json[key], {id: key});
|
||||
var params = Object.create(parameters);
|
||||
params.id = key;
|
||||
return this._keyClassCreate(
|
||||
this._elSymbol, this._elementClass, json[key], params);
|
||||
}, this);
|
||||
},
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@
|
|||
modelMixin.call(self, 'list');
|
||||
|
||||
self.add = function() {
|
||||
self.push();
|
||||
self.push(undefined, parameters);
|
||||
};
|
||||
self.getValues = function() {
|
||||
return self.toArray();
|
||||
|
@ -181,7 +181,7 @@
|
|||
} else { // usually, it's either frozendict inside or string
|
||||
newValue = '';
|
||||
}
|
||||
self.push(newValue, {id: newID});
|
||||
self.push(newValue, utils.extend(self._parameters, {id: newID}));
|
||||
_items[newID] = self.getByID(newID);
|
||||
};
|
||||
self.getValues = function() {
|
||||
|
|
|
@ -82,6 +82,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
function extend(proto, extension) {
|
||||
var newObj;
|
||||
proto = (proto !== undefined ? proto : null);
|
||||
newObj = Object.create(proto);
|
||||
Object.keys(extension).forEach(function(key) {
|
||||
newObj[key] = extension[key];
|
||||
});
|
||||
return newObj;
|
||||
}
|
||||
|
||||
return {
|
||||
getMeta: getMeta,
|
||||
getNewId: getNewId,
|
||||
|
@ -89,6 +99,7 @@
|
|||
makeTitle: makeTitle,
|
||||
getNextIDSuffix: getNextIDSuffix,
|
||||
enhanceItemWithID: enhanceItemWithID,
|
||||
extend: extend,
|
||||
pop: pop
|
||||
}
|
||||
})
|
||||
|
|
|
@ -27,7 +27,41 @@ describe('merlin.utils', function() {
|
|||
expect(array.condense()).toEqual([1, 0, 15, 7, 8]);
|
||||
});
|
||||
});
|
||||
function extend(proto, extension) {
|
||||
var newObj;
|
||||
proto = (proto !== undefined ? proto : null);
|
||||
newObj = Object.create(proto);
|
||||
Object.keys(extension).forEach(function(key) {
|
||||
newObj[key] = extension[key];
|
||||
});
|
||||
return newObj;
|
||||
}
|
||||
describe('extend function', function() {
|
||||
var obj;
|
||||
|
||||
beforeEach(function() {
|
||||
obj = {
|
||||
'key1': 10,
|
||||
'key2': 20
|
||||
};
|
||||
});
|
||||
|
||||
it("doesn't remove existing keys from the resulting object", function() {
|
||||
var newObj = extend(obj, {'key3': 30});
|
||||
expect(newObj.key1).toBe(10);
|
||||
expect(newObj.key3).toBe(30);
|
||||
});
|
||||
|
||||
it('overrides keys with the same names as the ones in extension', function() {
|
||||
var newObj = extend(obj, {'key2': 40});
|
||||
expect(newObj.key2).toBe(40);
|
||||
});
|
||||
|
||||
it("doesn't touch the original object, even the keys with the same names", function() {
|
||||
var newObj = extend(obj, {'key2': 40, 'key4': 50});
|
||||
expect(obj.key1).toBe(10);
|
||||
expect(obj.key2).toBe(20);
|
||||
});
|
||||
})
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue