mirror of
https://github.com/nasa/openmct.git
synced 2025-06-17 14:48:13 +00:00
Merge remote-tracking branch 'origin/open879' into open-master
Conflicts: platform/commonUI/edit/res/templates/edit-object.html
This commit is contained in:
@ -15,6 +15,8 @@ view's scope.) These additional properties are:
|
|||||||
then that function is assumed to be an accessor-mutator function
|
then that function is assumed to be an accessor-mutator function
|
||||||
(that is, it will be called with no arguments to get, and with
|
(that is, it will be called with no arguments to get, and with
|
||||||
an argument to set.)
|
an argument to set.)
|
||||||
|
* `method`: Name of a method to invoke upon a selected object when
|
||||||
|
a control is activated, e.g. on a button click.
|
||||||
* `inclusive`: Optional; true if this control should be considered
|
* `inclusive`: Optional; true if this control should be considered
|
||||||
applicable whenever at least one element in the selection has
|
applicable whenever at least one element in the selection has
|
||||||
the associated property. Otherwise, all members of the current
|
the associated property. Otherwise, all members of the current
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<div class='holder abs object-holder'>
|
<div class='holder abs object-holder'>
|
||||||
<mct-representation key="representation.selected.key"
|
<mct-representation key="representation.selected.key"
|
||||||
toolbar="toolbar"
|
toolbar="toolbar"
|
||||||
mct-object="domainObject">
|
mct-object="representation.selected.key && domainObject">
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,9 +17,10 @@ define(
|
|||||||
*
|
*
|
||||||
* @param structure toolbar structure, as provided by view definition
|
* @param structure toolbar structure, as provided by view definition
|
||||||
* @param {Array} selection the current selection state
|
* @param {Array} selection the current selection state
|
||||||
|
* @param {Function} commit callback to invoke after changes
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function EditToolbar(structure, selection) {
|
function EditToolbar(structure, selection, commit) {
|
||||||
var toolbarStructure = Object.create(structure || {}),
|
var toolbarStructure = Object.create(structure || {}),
|
||||||
toolbarState,
|
toolbarState,
|
||||||
properties = [];
|
properties = [];
|
||||||
@ -106,23 +107,46 @@ define(
|
|||||||
// to the current selection.
|
// to the current selection.
|
||||||
function isApplicable(item) {
|
function isApplicable(item) {
|
||||||
var property = (item || {}).property,
|
var property = (item || {}).property,
|
||||||
|
method = (item || {}).method,
|
||||||
exclusive = !(item || {}).inclusive;
|
exclusive = !(item || {}).inclusive;
|
||||||
|
|
||||||
// Check if a selected item defines this property
|
// Check if a selected item defines this property
|
||||||
function hasProperty(selected) {
|
function hasProperty(selected) {
|
||||||
return selected[property] !== undefined;
|
return (property && (selected[property] !== undefined)) ||
|
||||||
|
(method && (typeof selected[method] === 'function'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return property && selection.map(hasProperty).reduce(
|
return selection.map(hasProperty).reduce(
|
||||||
exclusive ? and : or,
|
exclusive ? and : or,
|
||||||
exclusive
|
exclusive
|
||||||
) && isConsistent(property);
|
) && isConsistent(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invoke all functions in selections with the given name
|
||||||
|
function invoke(method, value) {
|
||||||
|
if (method) {
|
||||||
|
// Make the change in the selection
|
||||||
|
selection.forEach(function (selected) {
|
||||||
|
if (typeof selected[method] === 'function') {
|
||||||
|
selected[method](value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// ...and commit!
|
||||||
|
commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare a toolbar item based on current selection
|
// Prepare a toolbar item based on current selection
|
||||||
function convertItem(item) {
|
function convertItem(item) {
|
||||||
var converted = Object.create(item || {});
|
var converted = Object.create(item || {});
|
||||||
converted.key = addKey(item.property);
|
if (item.property) {
|
||||||
|
converted.key = addKey(item.property);
|
||||||
|
}
|
||||||
|
if (item.method) {
|
||||||
|
converted.click = function (v) {
|
||||||
|
invoke(item.method, v);
|
||||||
|
};
|
||||||
|
}
|
||||||
return converted;
|
return converted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,13 @@ define(
|
|||||||
toolbar,
|
toolbar,
|
||||||
toolbarObject = {};
|
toolbarObject = {};
|
||||||
|
|
||||||
|
// Mark changes as ready to persist
|
||||||
|
function commit(message) {
|
||||||
|
if (scope.commit) {
|
||||||
|
scope.commit(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle changes to the current selection
|
// Handle changes to the current selection
|
||||||
function updateSelection(selection) {
|
function updateSelection(selection) {
|
||||||
// Make sure selection is array-like
|
// Make sure selection is array-like
|
||||||
@ -28,7 +35,7 @@ define(
|
|||||||
(selection ? [selection] : []);
|
(selection ? [selection] : []);
|
||||||
|
|
||||||
// Instantiate a new toolbar...
|
// Instantiate a new toolbar...
|
||||||
toolbar = new EditToolbar(definition, selection);
|
toolbar = new EditToolbar(definition, selection, commit);
|
||||||
|
|
||||||
// ...and expose its structure/state
|
// ...and expose its structure/state
|
||||||
toolbarObject.structure = toolbar.getStructure();
|
toolbarObject.structure = toolbar.getStructure();
|
||||||
@ -37,9 +44,12 @@ define(
|
|||||||
|
|
||||||
// Update selection models to match changed toolbar state
|
// Update selection models to match changed toolbar state
|
||||||
function updateState(state) {
|
function updateState(state) {
|
||||||
|
// Update underlying state based on toolbar changes
|
||||||
state.forEach(function (value, index) {
|
state.forEach(function (value, index) {
|
||||||
toolbar.updateState(index, value);
|
toolbar.updateState(index, value);
|
||||||
});
|
});
|
||||||
|
// Commit the changes.
|
||||||
|
commit("Changes from toolbar.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represent a domain object using this definition
|
// Represent a domain object using this definition
|
||||||
|
@ -15,7 +15,7 @@ define(
|
|||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
mockScope = jasmine.createSpyObj(
|
mockScope = jasmine.createSpyObj(
|
||||||
'$scope',
|
'$scope',
|
||||||
[ '$on', '$watch', '$watchCollection' ]
|
[ '$on', '$watch', '$watchCollection', "commit" ]
|
||||||
);
|
);
|
||||||
mockElement = {};
|
mockElement = {};
|
||||||
testAttrs = { toolbar: 'testToolbar' };
|
testAttrs = { toolbar: 'testToolbar' };
|
||||||
|
@ -11,7 +11,8 @@ define(
|
|||||||
testABC,
|
testABC,
|
||||||
testABC2,
|
testABC2,
|
||||||
testABCXYZ,
|
testABCXYZ,
|
||||||
testABCYZ;
|
testABCYZ,
|
||||||
|
testM;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
testStructure = {
|
testStructure = {
|
||||||
@ -29,6 +30,11 @@ define(
|
|||||||
{ name: "Y", property: "y" },
|
{ name: "Y", property: "y" },
|
||||||
{ name: "Z", property: "z" }
|
{ name: "Z", property: "z" }
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{ name: "M", method: "m" }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@ -37,6 +43,7 @@ define(
|
|||||||
testABC2 = { a: 4, b: 1, c: 2 }; // For inconsistent-state checking
|
testABC2 = { a: 4, b: 1, c: 2 }; // For inconsistent-state checking
|
||||||
testABCXYZ = { a: 0, b: 1, c: 2, x: 'X!', y: 'Y!', z: 'Z!' };
|
testABCXYZ = { a: 0, b: 1, c: 2, x: 'X!', y: 'Y!', z: 'Z!' };
|
||||||
testABCYZ = { a: 0, b: 1, c: 2, y: 'Y!', z: 'Z!' };
|
testABCYZ = { a: 0, b: 1, c: 2, y: 'Y!', z: 'Z!' };
|
||||||
|
testM = { m: jasmine.createSpy("method") };
|
||||||
});
|
});
|
||||||
|
|
||||||
it("provides properties from the original structure", function () {
|
it("provides properties from the original structure", function () {
|
||||||
@ -182,6 +189,19 @@ define(
|
|||||||
.length
|
.length
|
||||||
).toEqual(2);
|
).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("adds click functions when a method is specified", function () {
|
||||||
|
var testCommit = jasmine.createSpy('commit'),
|
||||||
|
toolbar = new EditToolbar(testStructure, [ testM ], testCommit);
|
||||||
|
// Verify precondition
|
||||||
|
expect(testM.m).not.toHaveBeenCalled();
|
||||||
|
// Click!
|
||||||
|
toolbar.getStructure().sections[0].items[0].click();
|
||||||
|
// Should have called the underlying function
|
||||||
|
expect(testM.m).toHaveBeenCalled();
|
||||||
|
// Should also have committed the change
|
||||||
|
expect(testCommit).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -19,7 +19,31 @@
|
|||||||
"type": "telemetry.panel",
|
"type": "telemetry.panel",
|
||||||
"templateUrl": "templates/fixed.html",
|
"templateUrl": "templates/fixed.html",
|
||||||
"uses": [ "composition" ],
|
"uses": [ "composition" ],
|
||||||
"gestures": [ "drop" ]
|
"gestures": [ "drop" ],
|
||||||
|
"toolbar": {
|
||||||
|
"sections": [
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"method": "add",
|
||||||
|
"control": "button",
|
||||||
|
"text": "Add",
|
||||||
|
"inclusive": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"method": "remove",
|
||||||
|
"control": "button",
|
||||||
|
"text": "Remove",
|
||||||
|
"inclusive": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"representations": [
|
"representations": [
|
||||||
@ -40,6 +64,12 @@
|
|||||||
"depends": [ "$scope", "telemetrySubscriber", "telemetryFormatter" ]
|
"depends": [ "$scope", "telemetrySubscriber", "telemetryFormatter" ]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"templates": [
|
||||||
|
{
|
||||||
|
"key": "fixed.telemetry",
|
||||||
|
"templateUrl": "templates/elements/telemetry.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"types": [
|
"types": [
|
||||||
{
|
{
|
||||||
"key": "layout",
|
"key": "layout",
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
<div style="background: #444;">
|
||||||
|
<div style="position: absolute; left: 0px; top: 0px; bottom: 0px; width: 50%; overflow: hidden;">
|
||||||
|
{{ngModel.name}}
|
||||||
|
</div>
|
||||||
|
<div style="position: absolute; right: 0px; top: 0px; bottom: 0px; width: 50%; overflow: hidden;">
|
||||||
|
{{ngModel.value}}
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,36 +1,25 @@
|
|||||||
|
|
||||||
|
|
||||||
<div style="width: 100%; height: 100%; position: absolute; left: 0px; top: 0px;"
|
<div style="width: 100%; height: 100%; position: absolute; left: 0px; top: 0px;"
|
||||||
ng-controller="FixedController as controller"
|
ng-controller="FixedController as controller"
|
||||||
mct-resize="controller.setBounds(bounds)">
|
mct-resize="controller.setBounds(bounds)">
|
||||||
|
|
||||||
<!-- Background grid -->
|
<!-- Background grid -->
|
||||||
<div ng-repeat="cell in controller.getCellStyles()"
|
<span ng-click="controller.clearSelection()">
|
||||||
style="position: absolute; border: 1px gray solid; background: black;"
|
<div ng-repeat="cell in controller.getCellStyles()"
|
||||||
ng-style="cell">
|
style="position: absolute; border: 1px gray solid; background: black;"
|
||||||
</div>
|
ng-style="cell">
|
||||||
|
|
||||||
<!-- Telemetry elements -->
|
|
||||||
<div ng-repeat="childObject in composition"
|
|
||||||
style="position: absolute; background: #444;"
|
|
||||||
ng-style="controller.getStyle(childObject.getId())">
|
|
||||||
|
|
||||||
<div style="position: absolute; left: 0px; top: 0px; bottom: 0px; width: 50%; overflow: hidden;">
|
|
||||||
{{childObject.getModel().name}}
|
|
||||||
</div>
|
|
||||||
<div style="position: absolute; right: 0px; top: 0px; bottom: 0px; width: 50%; overflow: hidden;">
|
|
||||||
{{controller.getValue(childObject.getId())}}
|
|
||||||
</div>
|
</div>
|
||||||
|
</span>
|
||||||
|
|
||||||
<!-- Drag handles -->
|
<!-- Fixed position elements -->
|
||||||
<span ng-show="domainObject.hasCapability('editor')">
|
<mct-include ng-repeat="element in controller.getElements()"
|
||||||
<span style="position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; cursor: move;"
|
style="position: absolute;"
|
||||||
mct-drag-down="controller.startDrag(childObject.getId(), [1,1], [0,0])"
|
key="element.template"
|
||||||
mct-drag="controller.continueDrag(delta)"
|
ng-class="{ test: controller.selected(element) }"
|
||||||
mct-drag-up="controller.endDrag()">
|
ng-style="element.style"
|
||||||
</span>
|
ng-click="controller.select(element)"
|
||||||
</span>
|
ng-model="element"
|
||||||
|
mct-drag-down="controller.startDrag(element); controller.select(element)"
|
||||||
</div>
|
mct-drag="controller.continueDrag(delta)"
|
||||||
|
mct-drag-up="controller.endDrag()">
|
||||||
|
</mct-include>
|
||||||
</div>
|
</div>
|
@ -1,8 +1,8 @@
|
|||||||
/*global define*/
|
/*global define*/
|
||||||
|
|
||||||
define(
|
define(
|
||||||
['./LayoutDrag'],
|
['./LayoutDrag', './LayoutSelection', './FixedProxy', './elements/ElementProxies'],
|
||||||
function (LayoutDrag) {
|
function (LayoutDrag, LayoutSelection, FixedProxy, ElementProxies) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var DEFAULT_DIMENSIONS = [ 2, 1 ],
|
var DEFAULT_DIMENSIONS = [ 2, 1 ],
|
||||||
@ -20,31 +20,23 @@ define(
|
|||||||
function FixedController($scope, telemetrySubscriber, telemetryFormatter) {
|
function FixedController($scope, telemetrySubscriber, telemetryFormatter) {
|
||||||
var gridSize = DEFAULT_GRID_SIZE,
|
var gridSize = DEFAULT_GRID_SIZE,
|
||||||
gridExtent = DEFAULT_GRID_EXTENT,
|
gridExtent = DEFAULT_GRID_EXTENT,
|
||||||
activeDrag,
|
dragging,
|
||||||
activeDragId,
|
|
||||||
subscription,
|
subscription,
|
||||||
values = {},
|
|
||||||
cellStyles = [],
|
cellStyles = [],
|
||||||
rawPositions = {},
|
elementProxies = [],
|
||||||
positions = {};
|
elementProxiesById = {},
|
||||||
|
selection;
|
||||||
// Utility function to copy raw positions from configuration,
|
|
||||||
// without writing directly to configuration (to avoid triggering
|
|
||||||
// persistence from watchers during drags).
|
|
||||||
function shallowCopy(obj, keys) {
|
|
||||||
var copy = {};
|
|
||||||
keys.forEach(function (k) {
|
|
||||||
copy[k] = obj[k];
|
|
||||||
});
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh cell styles (e.g. because grid extent changed)
|
// Refresh cell styles (e.g. because grid extent changed)
|
||||||
function refreshCellStyles() {
|
function refreshCellStyles() {
|
||||||
var x, y;
|
var x, y;
|
||||||
|
|
||||||
|
// Clear previous styles
|
||||||
cellStyles = [];
|
cellStyles = [];
|
||||||
|
|
||||||
|
// Update grid size from model
|
||||||
|
gridSize = ($scope.model || {}).layoutGrid || gridSize;
|
||||||
|
|
||||||
for (x = 0; x < gridExtent[0]; x += 1) {
|
for (x = 0; x < gridExtent[0]; x += 1) {
|
||||||
for (y = 0; y < gridExtent[1]; y += 1) {
|
for (y = 0; y < gridExtent[1]; y += 1) {
|
||||||
// Position blocks; subtract out border size from w/h
|
// Position blocks; subtract out border size from w/h
|
||||||
@ -58,62 +50,28 @@ define(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert from { positions: ..., dimensions: ... } to an
|
// Convert from element x/y/width/height to an
|
||||||
// apropriate ng-style argument, to position frames.
|
// apropriate ng-style argument, to position elements.
|
||||||
function convertPosition(raw) {
|
function convertPosition(raw) {
|
||||||
// Multiply position/dimensions by grid size
|
// Multiply position/dimensions by grid size
|
||||||
return {
|
return {
|
||||||
left: (gridSize[0] * raw.position[0]) + 'px',
|
left: (gridSize[0] * raw.x) + 'px',
|
||||||
top: (gridSize[1] * raw.position[1]) + 'px',
|
top: (gridSize[1] * raw.y) + 'px',
|
||||||
width: (gridSize[0] * raw.dimensions[0]) + 'px',
|
width: (gridSize[0] * raw.width) + 'px',
|
||||||
height: (gridSize[1] * raw.dimensions[1]) + 'px'
|
height: (gridSize[1] * raw.height) + 'px'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a default position (in its raw format) for a frame.
|
|
||||||
// Use an index to ensure that default positions are unique.
|
|
||||||
function defaultPosition(index) {
|
|
||||||
return {
|
|
||||||
position: [index, index],
|
|
||||||
dimensions: DEFAULT_DIMENSIONS
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store a computed position for a contained frame by its
|
|
||||||
// domain object id. Called in a forEach loop, so arguments
|
|
||||||
// are as expected there.
|
|
||||||
function populatePosition(id, index) {
|
|
||||||
rawPositions[id] =
|
|
||||||
rawPositions[id] || defaultPosition(index || 0);
|
|
||||||
positions[id] =
|
|
||||||
convertPosition(rawPositions[id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute panel positions based on the layout's object model
|
|
||||||
function lookupPanels(ids) {
|
|
||||||
var configuration = $scope.configuration || {};
|
|
||||||
ids = ids || [];
|
|
||||||
|
|
||||||
// Pull panel positions from configuration
|
|
||||||
rawPositions = shallowCopy(configuration.elements || {}, ids);
|
|
||||||
|
|
||||||
// Clear prior computed positions
|
|
||||||
positions = {};
|
|
||||||
|
|
||||||
// Update width/height that we are tracking
|
|
||||||
gridSize = ($scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE;
|
|
||||||
|
|
||||||
// Compute positions and add defaults where needed
|
|
||||||
ids.forEach(populatePosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the displayed value for this object
|
// Update the displayed value for this object
|
||||||
function updateValue(telemetryObject) {
|
function updateValue(telemetryObject) {
|
||||||
var id = telemetryObject && telemetryObject.getId();
|
var id = telemetryObject && telemetryObject.getId();
|
||||||
if (id) {
|
if (id) {
|
||||||
values[id] = telemetryFormatter.formatRangeValue(
|
(elementProxiesById[id] || []).forEach(function (element) {
|
||||||
subscription.getRangeValue(telemetryObject)
|
element.name = telemetryObject.getModel().name;
|
||||||
);
|
element.value = telemetryFormatter.formatRangeValue(
|
||||||
|
subscription.getRangeValue(telemetryObject)
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +82,59 @@ define(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decorate an element for display
|
||||||
|
function makeProxyElement(element, index, elements) {
|
||||||
|
var ElementProxy = ElementProxies[element.type],
|
||||||
|
e = ElementProxy && new ElementProxy(element, index, elements);
|
||||||
|
|
||||||
|
if (e) {
|
||||||
|
// Provide a displayable position (convert from grid to px)
|
||||||
|
e.style = convertPosition(element);
|
||||||
|
// Template names are same as type names, presently
|
||||||
|
e.template = element.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decorate elements in the current configuration
|
||||||
|
function refreshElements() {
|
||||||
|
// Cache selection; we are instantiating new proxies
|
||||||
|
// so we may want to restore this.
|
||||||
|
var selected = selection && selection.get(),
|
||||||
|
elements = (($scope.configuration || {}).elements || []),
|
||||||
|
index = -1; // Start with a 'not-found' value
|
||||||
|
|
||||||
|
// Find the selection in the new array
|
||||||
|
if (selected !== undefined) {
|
||||||
|
index = elements.indexOf(selected.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the new proxies...
|
||||||
|
elementProxies = elements.map(makeProxyElement);
|
||||||
|
|
||||||
|
// Clear old selection, and restore if appropriate
|
||||||
|
if (selection) {
|
||||||
|
selection.deselect();
|
||||||
|
if (index > -1) {
|
||||||
|
selection.select(elementProxies[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, rebuild lists of elements by id to
|
||||||
|
// facilitate faster update when new telemetry comes in.
|
||||||
|
elementProxiesById = {};
|
||||||
|
elementProxies.forEach(function (elementProxy) {
|
||||||
|
var id = elementProxy.id;
|
||||||
|
if (elementProxy.element.type === 'fixed.telemetry') {
|
||||||
|
elementProxiesById[id] = elementProxiesById[id] || [];
|
||||||
|
elementProxiesById[id].push(elementProxy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Ensure elements for all domain objects?
|
||||||
|
}
|
||||||
|
|
||||||
// Free up subscription to telemetry
|
// Free up subscription to telemetry
|
||||||
function releaseSubscription() {
|
function releaseSubscription() {
|
||||||
if (subscription) {
|
if (subscription) {
|
||||||
@ -134,9 +145,6 @@ define(
|
|||||||
|
|
||||||
// Subscribe to telemetry updates for this domain object
|
// Subscribe to telemetry updates for this domain object
|
||||||
function subscribe(domainObject) {
|
function subscribe(domainObject) {
|
||||||
// Clear any old values
|
|
||||||
values = {};
|
|
||||||
|
|
||||||
// Release existing subscription (if any)
|
// Release existing subscription (if any)
|
||||||
if (subscription) {
|
if (subscription) {
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
@ -150,7 +158,7 @@ define(
|
|||||||
// Handle changes in the object's composition
|
// Handle changes in the object's composition
|
||||||
function updateComposition(ids) {
|
function updateComposition(ids) {
|
||||||
// Populate panel positions
|
// Populate panel positions
|
||||||
lookupPanels(ids);
|
// TODO: Ensure defaults here
|
||||||
// Resubscribe - objects in view have changed
|
// Resubscribe - objects in view have changed
|
||||||
subscribe($scope.domainObject);
|
subscribe($scope.domainObject);
|
||||||
}
|
}
|
||||||
@ -162,23 +170,33 @@ define(
|
|||||||
// Make sure there is a "elements" field in the
|
// Make sure there is a "elements" field in the
|
||||||
// view configuration.
|
// view configuration.
|
||||||
$scope.configuration.elements =
|
$scope.configuration.elements =
|
||||||
$scope.configuration.elements || {};
|
$scope.configuration.elements || [];
|
||||||
// Store the position of this element.
|
// Store the position of this element.
|
||||||
$scope.configuration.elements[id] = {
|
$scope.configuration.elements.push({
|
||||||
position: [
|
type: "fixed.telemetry",
|
||||||
Math.floor(position.x / gridSize[0]),
|
x: Math.floor(position.x / gridSize[0]),
|
||||||
Math.floor(position.y / gridSize[1])
|
y: Math.floor(position.y / gridSize[1]),
|
||||||
],
|
id: id,
|
||||||
dimensions: DEFAULT_DIMENSIONS
|
width: DEFAULT_DIMENSIONS[0],
|
||||||
};
|
height: DEFAULT_DIMENSIONS[1]
|
||||||
|
});
|
||||||
// Mark change as persistable
|
// Mark change as persistable
|
||||||
if ($scope.commit) {
|
if ($scope.commit) {
|
||||||
$scope.commit("Dropped a frame.");
|
$scope.commit("Dropped an element.");
|
||||||
}
|
}
|
||||||
// Populate template-facing position for this id
|
|
||||||
populatePosition(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track current selection state
|
||||||
|
if (Array.isArray($scope.selection)) {
|
||||||
|
selection = new LayoutSelection(
|
||||||
|
$scope.selection,
|
||||||
|
new FixedProxy($scope.configuration)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh list of elements whenever model changes
|
||||||
|
$scope.$watch("model.modified", refreshElements);
|
||||||
|
|
||||||
// Position panes when the model field changes
|
// Position panes when the model field changes
|
||||||
$scope.$watch("model.composition", updateComposition);
|
$scope.$watch("model.composition", updateComposition);
|
||||||
|
|
||||||
@ -204,15 +222,6 @@ define(
|
|||||||
getCellStyles: function () {
|
getCellStyles: function () {
|
||||||
return cellStyles;
|
return cellStyles;
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* Get the current data value for the specified domain object.
|
|
||||||
* @memberof FixedController#
|
|
||||||
* @param {string} id the domain object identifier
|
|
||||||
* @returns {string} the displayable data value
|
|
||||||
*/
|
|
||||||
getValue: function (id) {
|
|
||||||
return values[id];
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* Set the size of the viewable fixed position area.
|
* Set the size of the viewable fixed position area.
|
||||||
* @memberof FixedController#
|
* @memberof FixedController#
|
||||||
@ -227,17 +236,36 @@ define(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Get a style object for a frame with the specified domain
|
* Get an array of elements in this panel; these are
|
||||||
* object identifier, suitable for use in an `ng-style`
|
* decorated proxies for both selection and display.
|
||||||
* directive to position a frame as configured for this layout.
|
* @returns {Array} elements in this panel
|
||||||
* @param {string} id the object identifier
|
|
||||||
* @returns {Object.<string, string>} an object with
|
|
||||||
* appropriate left, width, etc fields for positioning
|
|
||||||
*/
|
*/
|
||||||
getStyle: function (id) {
|
getElements: function () {
|
||||||
// Called in a loop, so just look up; the "positions"
|
return elementProxies;
|
||||||
// object is kept up to date by a watch.
|
},
|
||||||
return positions[id];
|
/**
|
||||||
|
* Check if the element is currently selected.
|
||||||
|
* @returns {boolean} true if selected
|
||||||
|
*/
|
||||||
|
selected: function (element) {
|
||||||
|
return selection && selection.selected(element);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Set the active user selection in this view.
|
||||||
|
* @param element the element to select
|
||||||
|
*/
|
||||||
|
select: function (element) {
|
||||||
|
if (selection) {
|
||||||
|
selection.select(element);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Clear the current user selection.
|
||||||
|
*/
|
||||||
|
clearSelection: function () {
|
||||||
|
if (selection) {
|
||||||
|
selection.deselect();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Start a drag gesture to move/resize a frame.
|
* Start a drag gesture to move/resize a frame.
|
||||||
@ -254,19 +282,18 @@ define(
|
|||||||
* with the mouse while the horizontal dimensions shrink in
|
* with the mouse while the horizontal dimensions shrink in
|
||||||
* kind (and vertical properties remain unmodified.)
|
* kind (and vertical properties remain unmodified.)
|
||||||
*
|
*
|
||||||
* @param {string} id the identifier of the domain object
|
* @param element the raw (undecorated) element to drag
|
||||||
* in the frame being manipulated
|
|
||||||
* @param {number[]} posFactor the position factor
|
|
||||||
* @param {number[]} dimFactor the dimensions factor
|
|
||||||
*/
|
*/
|
||||||
startDrag: function (id, posFactor, dimFactor) {
|
startDrag: function (element) {
|
||||||
activeDragId = id;
|
// Only allow dragging in edit mode
|
||||||
activeDrag = new LayoutDrag(
|
if ($scope.domainObject &&
|
||||||
rawPositions[id],
|
$scope.domainObject.hasCapability('editor')) {
|
||||||
posFactor,
|
dragging = {
|
||||||
dimFactor,
|
element: element,
|
||||||
gridSize
|
x: element.x(),
|
||||||
);
|
y: element.y()
|
||||||
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Continue an active drag gesture.
|
* Continue an active drag gesture.
|
||||||
@ -275,10 +302,10 @@ define(
|
|||||||
* to its position when the drag started
|
* to its position when the drag started
|
||||||
*/
|
*/
|
||||||
continueDrag: function (delta) {
|
continueDrag: function (delta) {
|
||||||
if (activeDrag) {
|
if (dragging) {
|
||||||
rawPositions[activeDragId] =
|
dragging.element.x(dragging.x + Math.round(delta[0] / gridSize[0]));
|
||||||
activeDrag.getAdjustedPosition(delta);
|
dragging.element.y(dragging.y + Math.round(delta[1] / gridSize[1]));
|
||||||
populatePosition(activeDragId);
|
dragging.element.style = convertPosition(dragging.element.element);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -286,19 +313,9 @@ define(
|
|||||||
* view configuration.
|
* view configuration.
|
||||||
*/
|
*/
|
||||||
endDrag: function () {
|
endDrag: function () {
|
||||||
// Write to configuration; this is watched and
|
|
||||||
// saved by the EditRepresenter.
|
|
||||||
$scope.configuration =
|
|
||||||
$scope.configuration || {};
|
|
||||||
// Make sure there is a "panels" field in the
|
|
||||||
// view configuration.
|
|
||||||
$scope.configuration.elements =
|
|
||||||
$scope.configuration.elements || {};
|
|
||||||
// Store the position of this panel.
|
|
||||||
$scope.configuration.elements[activeDragId] =
|
|
||||||
rawPositions[activeDragId];
|
|
||||||
// Mark this object as dirty to encourage persistence
|
// Mark this object as dirty to encourage persistence
|
||||||
if ($scope.commit) {
|
if (dragging && $scope.commit) {
|
||||||
|
dragging = undefined;
|
||||||
$scope.commit("Moved element.");
|
$scope.commit("Moved element.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
platform/features/layout/src/FixedProxy.js
Normal file
26
platform/features/layout/src/FixedProxy.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*global define,window*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy for configuring a fixed position view via the toolbar.
|
||||||
|
* @constructor
|
||||||
|
* @param configuration the view configuration object
|
||||||
|
*/
|
||||||
|
function FixedProxy(configuration) {
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* Add a new visual element to this view.
|
||||||
|
*/
|
||||||
|
add: function (type) {
|
||||||
|
window.alert("Placeholder. Should add a " + type + ".");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return FixedProxy;
|
||||||
|
}
|
||||||
|
);
|
126
platform/features/layout/src/LayoutSelection.js
Normal file
126
platform/features/layout/src/LayoutSelection.js
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks selection state for Layout and Fixed Position views.
|
||||||
|
* This manages and mutates the provided selection array in-place,
|
||||||
|
* and takes care to only modify the array elements it manages
|
||||||
|
* (the view's proxy, and the single selection); selections may be
|
||||||
|
* added or removed elsewhere provided that similar care is taken
|
||||||
|
* elsewhere.
|
||||||
|
*
|
||||||
|
* @param {Array} selection the selection array from the view's scope
|
||||||
|
* @param [proxy] an object which represents the selection of the view
|
||||||
|
* itself (which handles view-level toolbar behavior)
|
||||||
|
*/
|
||||||
|
function LayoutSelection(selection, proxy) {
|
||||||
|
var selecting = false,
|
||||||
|
selected;
|
||||||
|
|
||||||
|
// Find the proxy in the array; our selected objects will be
|
||||||
|
// positioned next to that
|
||||||
|
function proxyIndex() {
|
||||||
|
return selection.indexOf(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the currently-selected object
|
||||||
|
function deselect() {
|
||||||
|
// Nothing to do if we don't have a selected object
|
||||||
|
if (selecting) {
|
||||||
|
// Clear state tracking
|
||||||
|
selecting = false;
|
||||||
|
selected = undefined;
|
||||||
|
|
||||||
|
// Remove the selection
|
||||||
|
selection.splice(proxyIndex() + 1, 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select an object
|
||||||
|
function select(obj) {
|
||||||
|
// We want this selection to end up near the proxy
|
||||||
|
var index = proxyIndex() + 1;
|
||||||
|
|
||||||
|
// Proxy is always selected
|
||||||
|
if (obj === proxy) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear any existing selection
|
||||||
|
deselect();
|
||||||
|
|
||||||
|
// Note the current selection state
|
||||||
|
selected = obj;
|
||||||
|
selecting = true;
|
||||||
|
|
||||||
|
// Are we at the end of the array?
|
||||||
|
if (selection.length === index) {
|
||||||
|
// Add it to the end
|
||||||
|
selection.push(obj);
|
||||||
|
} else {
|
||||||
|
// Splice it into the array
|
||||||
|
selection.splice(index, 0, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any selected object, and the proxy itself
|
||||||
|
function destroy() {
|
||||||
|
deselect();
|
||||||
|
selection.splice(proxyIndex(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if an object is selected
|
||||||
|
function isSelected(obj) {
|
||||||
|
return (obj === selected) || (obj === proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getter for current selection
|
||||||
|
function get() {
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with the proxy selected
|
||||||
|
selection.push(proxy);
|
||||||
|
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* Check if an object is currently selected.
|
||||||
|
* @returns true if selected, otherwise false
|
||||||
|
*/
|
||||||
|
selected: isSelected,
|
||||||
|
/**
|
||||||
|
* Select an object.
|
||||||
|
* @param obj the object to select
|
||||||
|
* @returns {boolean} true if selection changed
|
||||||
|
*/
|
||||||
|
select: select,
|
||||||
|
/**
|
||||||
|
* Clear the current selection.
|
||||||
|
* @returns {boolean} true if selection changed
|
||||||
|
*/
|
||||||
|
deselect: deselect,
|
||||||
|
/**
|
||||||
|
* Get the currently-selected object.
|
||||||
|
* @returns the currently selected object
|
||||||
|
*/
|
||||||
|
get: get,
|
||||||
|
/**
|
||||||
|
* Clear the selection, including the proxy, and dispose
|
||||||
|
* of this selection scope. No other calls to methods on
|
||||||
|
* this object are expected after `destroy` has been
|
||||||
|
* called; their behavior will be undefined.
|
||||||
|
*/
|
||||||
|
destroy: destroy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return LayoutSelection;
|
||||||
|
}
|
||||||
|
);
|
26
platform/features/layout/src/elements/AccessorMutator.js
Normal file
26
platform/features/layout/src/elements/AccessorMutator.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function for creating getter-setter functions,
|
||||||
|
* since these are frequently useful for element proxies.
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} object the object to get/set values upon
|
||||||
|
* @param {string} key the property to get/set
|
||||||
|
*/
|
||||||
|
function AccessorMutator(object, key) {
|
||||||
|
return function (value) {
|
||||||
|
if (arguments.length > 0) {
|
||||||
|
object[key] = value;
|
||||||
|
}
|
||||||
|
return object[key];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccessorMutator;
|
||||||
|
}
|
||||||
|
);
|
12
platform/features/layout/src/elements/ElementProxies.js
Normal file
12
platform/features/layout/src/elements/ElementProxies.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['./TelemetryProxy'],
|
||||||
|
function (TelemetryProxy) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
return {
|
||||||
|
"fixed.telemetry": TelemetryProxy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
36
platform/features/layout/src/elements/ElementProxy.js
Normal file
36
platform/features/layout/src/elements/ElementProxy.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['./AccessorMutator'],
|
||||||
|
function (AccessorMutator) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract superclass for other classes which provide useful
|
||||||
|
* interfaces upon an elements in a fixed position view.
|
||||||
|
* This handles the generic operations (e.g. remove) so that
|
||||||
|
* subclasses only need to implement element-specific behaviors.
|
||||||
|
* @constructor
|
||||||
|
* @param element the telemetry element
|
||||||
|
* @param index the element's index within its array
|
||||||
|
* @param {Array} elements the full array of elements
|
||||||
|
*/
|
||||||
|
function ElementProxy(element, index, elements) {
|
||||||
|
return {
|
||||||
|
element: element,
|
||||||
|
x: new AccessorMutator(element, 'x'),
|
||||||
|
y: new AccessorMutator(element, 'y'),
|
||||||
|
z: new AccessorMutator(element, 'z'),
|
||||||
|
width: new AccessorMutator(element, 'width'),
|
||||||
|
height: new AccessorMutator(element, 'height'),
|
||||||
|
remove: function () {
|
||||||
|
if (elements[index] === element) {
|
||||||
|
elements.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ElementProxy;
|
||||||
|
}
|
||||||
|
);
|
21
platform/features/layout/src/elements/TelemetryProxy.js
Normal file
21
platform/features/layout/src/elements/TelemetryProxy.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*global define*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['./ElementProxy'],
|
||||||
|
function (ElementProxy) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function TelemetryProxy(element, index, elements) {
|
||||||
|
var proxy = new ElementProxy(element, index, elements);
|
||||||
|
|
||||||
|
proxy.id = element.id;
|
||||||
|
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TelemetryProxy;
|
||||||
|
}
|
||||||
|
);
|
@ -1,4 +1,4 @@
|
|||||||
/*global define,describe,it,expect,beforeEach,jasmine*/
|
/*global define,describe,it,expect,beforeEach,jasmine,xit*/
|
||||||
|
|
||||||
define(
|
define(
|
||||||
["../src/FixedController"],
|
["../src/FixedController"],
|
||||||
@ -14,6 +14,7 @@ define(
|
|||||||
testGrid,
|
testGrid,
|
||||||
testModel,
|
testModel,
|
||||||
testValues,
|
testValues,
|
||||||
|
testConfiguration,
|
||||||
controller;
|
controller;
|
||||||
|
|
||||||
// Utility function; find a watch for a given expression
|
// Utility function; find a watch for a given expression
|
||||||
@ -41,9 +42,10 @@ define(
|
|||||||
function makeMockDomainObject(id) {
|
function makeMockDomainObject(id) {
|
||||||
var mockObject = jasmine.createSpyObj(
|
var mockObject = jasmine.createSpyObj(
|
||||||
'domainObject-' + id,
|
'domainObject-' + id,
|
||||||
[ 'getId' ]
|
[ 'getId', 'getModel' ]
|
||||||
);
|
);
|
||||||
mockObject.getId.andReturn(id);
|
mockObject.getId.andReturn(id);
|
||||||
|
mockObject.getModel.andReturn({ name: "Point " + id});
|
||||||
return mockObject;
|
return mockObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +77,11 @@ define(
|
|||||||
layoutGrid: testGrid
|
layoutGrid: testGrid
|
||||||
};
|
};
|
||||||
testValues = { a: 10, b: 42, c: 31.42 };
|
testValues = { a: 10, b: 42, c: 31.42 };
|
||||||
|
testConfiguration = { elements: [
|
||||||
|
{ type: "fixed.telemetry", id: 'a', x: 1, y: 1 },
|
||||||
|
{ type: "fixed.telemetry", id: 'b', x: 1, y: 1 },
|
||||||
|
{ type: "fixed.telemetry", id: 'c', x: 1, y: 1 }
|
||||||
|
]};
|
||||||
|
|
||||||
mockSubscriber.subscribe.andReturn(mockSubscription);
|
mockSubscriber.subscribe.andReturn(mockSubscription);
|
||||||
mockSubscription.getTelemetryObjects.andReturn(
|
mockSubscription.getTelemetryObjects.andReturn(
|
||||||
@ -86,6 +93,9 @@ define(
|
|||||||
mockFormatter.formatRangeValue.andCallFake(function (v) {
|
mockFormatter.formatRangeValue.andCallFake(function (v) {
|
||||||
return "Formatted " + v;
|
return "Formatted " + v;
|
||||||
});
|
});
|
||||||
|
mockScope.model = testModel;
|
||||||
|
mockScope.configuration = testConfiguration;
|
||||||
|
mockScope.selection = []; // Act like edit mode
|
||||||
|
|
||||||
controller = new FixedController(
|
controller = new FixedController(
|
||||||
mockScope,
|
mockScope,
|
||||||
@ -122,30 +132,85 @@ define(
|
|||||||
expect(mockSubscriber.subscribe.calls.length).toEqual(2);
|
expect(mockSubscriber.subscribe.calls.length).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("configures view based on model", function () {
|
it("exposes visible elements based on configuration", function () {
|
||||||
|
var elements;
|
||||||
|
|
||||||
mockScope.model = testModel;
|
mockScope.model = testModel;
|
||||||
findWatch("model.composition")(mockScope.model.composition);
|
testModel.modified = 1;
|
||||||
// Should have styles for all elements of composition
|
findWatch("model.modified")(testModel.modified);
|
||||||
expect(controller.getStyle('a')).toBeDefined();
|
|
||||||
expect(controller.getStyle('b')).toBeDefined();
|
elements = controller.getElements();
|
||||||
expect(controller.getStyle('c')).toBeDefined();
|
expect(elements.length).toEqual(3);
|
||||||
expect(controller.getStyle('d')).not.toBeDefined();
|
expect(elements[0].id).toEqual('a');
|
||||||
|
expect(elements[1].id).toEqual('b');
|
||||||
|
expect(elements[2].id).toEqual('c');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows elements to be selected", function () {
|
||||||
|
var elements;
|
||||||
|
|
||||||
|
testModel.modified = 1;
|
||||||
|
findWatch("model.modified")(testModel.modified);
|
||||||
|
|
||||||
|
elements = controller.getElements();
|
||||||
|
controller.select(elements[1]);
|
||||||
|
expect(controller.selected(elements[0])).toBeFalsy();
|
||||||
|
expect(controller.selected(elements[1])).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows selections to be cleared", function () {
|
||||||
|
var elements;
|
||||||
|
|
||||||
|
testModel.modified = 1;
|
||||||
|
findWatch("model.modified")(testModel.modified);
|
||||||
|
|
||||||
|
elements = controller.getElements();
|
||||||
|
controller.select(elements[1]);
|
||||||
|
controller.clearSelection();
|
||||||
|
expect(controller.selected(elements[1])).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("retains selections during refresh", function () {
|
||||||
|
// Get elements; remove one of them; trigger refresh.
|
||||||
|
// Same element (at least by index) should still be selected.
|
||||||
|
var elements;
|
||||||
|
|
||||||
|
testModel.modified = 1;
|
||||||
|
findWatch("model.modified")(testModel.modified);
|
||||||
|
|
||||||
|
elements = controller.getElements();
|
||||||
|
controller.select(elements[1]);
|
||||||
|
|
||||||
|
elements[2].remove();
|
||||||
|
testModel.modified = 2;
|
||||||
|
findWatch("model.modified")(testModel.modified);
|
||||||
|
|
||||||
|
elements = controller.getElements();
|
||||||
|
// Verify removal, as test assumes this
|
||||||
|
expect(elements.length).toEqual(2);
|
||||||
|
|
||||||
|
expect(controller.selected(elements[1])).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("provides values for telemetry elements", function () {
|
it("provides values for telemetry elements", function () {
|
||||||
|
var elements;
|
||||||
// Initialize
|
// Initialize
|
||||||
mockScope.domainObject = mockDomainObject;
|
mockScope.domainObject = mockDomainObject;
|
||||||
mockScope.model = testModel;
|
mockScope.model = testModel;
|
||||||
findWatch("domainObject")(mockDomainObject);
|
findWatch("domainObject")(mockDomainObject);
|
||||||
|
findWatch("model.modified")(1);
|
||||||
findWatch("model.composition")(mockScope.model.composition);
|
findWatch("model.composition")(mockScope.model.composition);
|
||||||
|
|
||||||
// Invoke the subscription callback
|
// Invoke the subscription callback
|
||||||
mockSubscriber.subscribe.mostRecentCall.args[1]();
|
mockSubscriber.subscribe.mostRecentCall.args[1]();
|
||||||
|
|
||||||
|
// Get elements that controller is now exposing
|
||||||
|
elements = controller.getElements();
|
||||||
|
|
||||||
// Formatted values should be available
|
// Formatted values should be available
|
||||||
expect(controller.getValue('a')).toEqual("Formatted 10");
|
expect(elements[0].value).toEqual("Formatted 10");
|
||||||
expect(controller.getValue('b')).toEqual("Formatted 42");
|
expect(elements[1].value).toEqual("Formatted 42");
|
||||||
expect(controller.getValue('c')).toEqual("Formatted 31.42");
|
expect(elements[2].value).toEqual("Formatted 31.42");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("adds grid cells to fill boundaries", function () {
|
it("adds grid cells to fill boundaries", function () {
|
||||||
@ -179,7 +244,7 @@ define(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Verify precondition
|
// Verify precondition
|
||||||
expect(controller.getStyle('d')).not.toBeDefined();
|
expect(testConfiguration.elements.length).toEqual(3);
|
||||||
|
|
||||||
// Notify that a drop occurred
|
// Notify that a drop occurred
|
||||||
testModel.composition.push('d');
|
testModel.composition.push('d');
|
||||||
@ -188,13 +253,28 @@ define(
|
|||||||
'd',
|
'd',
|
||||||
{ x: 300, y: 100 }
|
{ x: 300, y: 100 }
|
||||||
);
|
);
|
||||||
expect(controller.getStyle('d')).toBeDefined();
|
|
||||||
|
// Should have added an element
|
||||||
|
expect(testConfiguration.elements.length).toEqual(4);
|
||||||
|
|
||||||
// Should have triggered commit (provided by
|
// Should have triggered commit (provided by
|
||||||
// EditRepresenter) with some message.
|
// EditRepresenter) with some message.
|
||||||
expect(mockScope.commit)
|
expect(mockScope.commit)
|
||||||
.toHaveBeenCalledWith(jasmine.any(String));
|
.toHaveBeenCalledWith(jasmine.any(String));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
it("unsubscribes when destroyed", function () {
|
||||||
|
// Make an object available
|
||||||
|
findWatch('domainObject')(mockDomainObject);
|
||||||
|
// Also verify precondition
|
||||||
|
expect(mockSubscription.unsubscribe).not.toHaveBeenCalled();
|
||||||
|
// Destroy the scope
|
||||||
|
findOn('$destroy')();
|
||||||
|
// Should have unsubscribed
|
||||||
|
expect(mockSubscription.unsubscribe).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
18
platform/features/layout/test/FixedProxySpec.js
Normal file
18
platform/features/layout/test/FixedProxySpec.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*global define,describe,it,expect,beforeEach,jasmine,xit*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['../src/FixedProxy'],
|
||||||
|
function (FixedProxy) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("Fixed Position view's selection proxy", function () {
|
||||||
|
it("has a placeholder message when clicked", function () {
|
||||||
|
var oldAlert = window.alert;
|
||||||
|
window.alert = jasmine.createSpy('alert');
|
||||||
|
new FixedProxy({}).add('');
|
||||||
|
expect(window.alert).toHaveBeenCalledWith(jasmine.any(String));
|
||||||
|
window.alert = oldAlert;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
85
platform/features/layout/test/LayoutSelectionSpec.js
Normal file
85
platform/features/layout/test/LayoutSelectionSpec.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*global define,describe,it,expect,beforeEach,jasmine,xit*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['../src/LayoutSelection'],
|
||||||
|
function (LayoutSelection) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("Layout/fixed position selection manager", function () {
|
||||||
|
var testSelection,
|
||||||
|
testProxy,
|
||||||
|
testElement,
|
||||||
|
otherElement,
|
||||||
|
selection;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
testSelection = [];
|
||||||
|
testProxy = { someKey: "some value" };
|
||||||
|
testElement = { someOtherKey: "some other value" };
|
||||||
|
otherElement = { yetAnotherKey: 42 };
|
||||||
|
selection = new LayoutSelection(testSelection, testProxy);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adds the proxy to the selection array", function () {
|
||||||
|
expect(testSelection).toEqual([testProxy]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("includes selected objects alongside the proxy", function () {
|
||||||
|
selection.select(testElement);
|
||||||
|
expect(testSelection).toEqual([testProxy, testElement]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows elements to be deselected", function () {
|
||||||
|
selection.select(testElement);
|
||||||
|
selection.deselect();
|
||||||
|
expect(testSelection).toEqual([testProxy]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("replaces old selections with new ones", function () {
|
||||||
|
selection.select(testElement);
|
||||||
|
selection.select(otherElement);
|
||||||
|
expect(testSelection).toEqual([testProxy, otherElement]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows retrieval of the current selection", function () {
|
||||||
|
selection.select(testElement);
|
||||||
|
expect(selection.get()).toBe(testElement);
|
||||||
|
selection.select(otherElement);
|
||||||
|
expect(selection.get()).toBe(otherElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can check if an element is selected", function () {
|
||||||
|
selection.select(testElement);
|
||||||
|
expect(selection.selected(testElement)).toBeTruthy();
|
||||||
|
expect(selection.selected(otherElement)).toBeFalsy();
|
||||||
|
selection.select(otherElement);
|
||||||
|
expect(selection.selected(testElement)).toBeFalsy();
|
||||||
|
expect(selection.selected(otherElement)).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("cleans up the selection on destroy", function () {
|
||||||
|
selection.destroy();
|
||||||
|
expect(testSelection).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves other elements in the array", function () {
|
||||||
|
testSelection.push(42);
|
||||||
|
selection.select(testElement);
|
||||||
|
expect(testSelection).toEqual([testProxy, testElement, 42]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("considers the proxy to be selected", function () {
|
||||||
|
expect(selection.selected(testProxy)).toBeTruthy();
|
||||||
|
selection.select(testElement);
|
||||||
|
// Even when something else is selected...
|
||||||
|
expect(selection.selected(testProxy)).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("treats selection of the proxy as a no-op", function () {
|
||||||
|
selection.select(testProxy);
|
||||||
|
expect(testSelection).toEqual([testProxy]);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
@ -0,0 +1,31 @@
|
|||||||
|
/*global define,describe,it,expect,beforeEach,jasmine*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['../../src/elements/AccessorMutator'],
|
||||||
|
function (AccessorMutator) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("An accessor-mutator", function () {
|
||||||
|
var testObject,
|
||||||
|
am;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
testObject = { t: 42, other: 100 };
|
||||||
|
am = new AccessorMutator(testObject, 't');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows access to a property", function () {
|
||||||
|
expect(am()).toEqual(42);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows mutation of a property", function () {
|
||||||
|
expect(am("some other value")).toEqual("some other value");
|
||||||
|
expect(testObject).toEqual({
|
||||||
|
t: "some other value",
|
||||||
|
other: 100
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
27
platform/features/layout/test/elements/ElementProxiesSpec.js
Normal file
27
platform/features/layout/test/elements/ElementProxiesSpec.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*global define,describe,it,expect,beforeEach,jasmine*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['../../src/elements/ElementProxies'],
|
||||||
|
function (ElementProxies) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var ELEMENT_TYPES = [
|
||||||
|
"fixed.telemetry"
|
||||||
|
];
|
||||||
|
|
||||||
|
// Verify that the set of proxies exposed matches the specific
|
||||||
|
// list above.
|
||||||
|
describe("The set of element proxies", function () {
|
||||||
|
ELEMENT_TYPES.forEach(function (t) {
|
||||||
|
it("exposes a proxy wrapper for " + t + " elements", function () {
|
||||||
|
expect(typeof ElementProxies[t]).toEqual('function');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("exposes no additional wrappers", function () {
|
||||||
|
expect(Object.keys(ElementProxies).length)
|
||||||
|
.toEqual(ELEMENT_TYPES.length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
41
platform/features/layout/test/elements/ElementProxySpec.js
Normal file
41
platform/features/layout/test/elements/ElementProxySpec.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*global define,describe,it,expect,beforeEach,jasmine*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['../../src/elements/ElementProxy'],
|
||||||
|
function (ElementProxy) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("A fixed position element proxy", function () {
|
||||||
|
var testElement,
|
||||||
|
testElements,
|
||||||
|
proxy;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
testElement = {
|
||||||
|
x: 1,
|
||||||
|
y: 2,
|
||||||
|
z: 3,
|
||||||
|
width: 42,
|
||||||
|
height: 24
|
||||||
|
};
|
||||||
|
testElements = [ {}, {}, testElement, {} ];
|
||||||
|
proxy = new ElementProxy(
|
||||||
|
testElement,
|
||||||
|
testElements.indexOf(testElement),
|
||||||
|
testElements
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("exposes element properties", function () {
|
||||||
|
Object.keys(testElement).forEach(function (k) {
|
||||||
|
expect(proxy[k]()).toEqual(testElement[k]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows elements to be removed", function () {
|
||||||
|
proxy.remove();
|
||||||
|
expect(testElements).toEqual([{}, {}, {}]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
35
platform/features/layout/test/elements/TelemetryProxySpec.js
Normal file
35
platform/features/layout/test/elements/TelemetryProxySpec.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*global define,describe,it,expect,beforeEach,jasmine*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['../../src/elements/TelemetryProxy'],
|
||||||
|
function (TelemetryProxy) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("A fixed position telemetry proxy", function () {
|
||||||
|
var testElement,
|
||||||
|
testElements,
|
||||||
|
proxy;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
testElement = {
|
||||||
|
x: 1,
|
||||||
|
y: 2,
|
||||||
|
z: 3,
|
||||||
|
width: 42,
|
||||||
|
height: 24,
|
||||||
|
id: "test-id"
|
||||||
|
};
|
||||||
|
testElements = [ {}, {}, testElement, {} ];
|
||||||
|
proxy = new TelemetryProxy(
|
||||||
|
testElement,
|
||||||
|
testElements.indexOf(testElement),
|
||||||
|
testElements
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("exposes the element's id", function () {
|
||||||
|
expect(proxy.id).toEqual('test-id');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
@ -1,5 +1,11 @@
|
|||||||
[
|
[
|
||||||
"FixedController",
|
"FixedController",
|
||||||
|
"FixedProxy",
|
||||||
"LayoutController",
|
"LayoutController",
|
||||||
"LayoutDrag"
|
"LayoutDrag",
|
||||||
|
"LayoutSelection",
|
||||||
|
"elements/AccessorMutator",
|
||||||
|
"elements/ElementProxies",
|
||||||
|
"elements/ElementProxy",
|
||||||
|
"elements/TelemetryProxy"
|
||||||
]
|
]
|
@ -10,7 +10,7 @@ define(
|
|||||||
|
|
||||||
|
|
||||||
// Methods to mock
|
// Methods to mock
|
||||||
var JQLITE_FUNCTIONS = [ "on", "off", "attr", "removeAttr" ],
|
var JQLITE_FUNCTIONS = [ "on", "off", "attr", "removeAttr", "scope" ],
|
||||||
DOMAIN_OBJECT_METHODS = [ "getId", "getModel", "getCapability", "hasCapability", "useCapability"],
|
DOMAIN_OBJECT_METHODS = [ "getId", "getModel", "getCapability", "hasCapability", "useCapability"],
|
||||||
TEST_ID = "test-id",
|
TEST_ID = "test-id",
|
||||||
DROP_ID = "drop-id";
|
DROP_ID = "drop-id";
|
||||||
@ -21,7 +21,10 @@ define(
|
|||||||
mockDomainObject,
|
mockDomainObject,
|
||||||
mockPersistence,
|
mockPersistence,
|
||||||
mockEvent,
|
mockEvent,
|
||||||
|
mockScope,
|
||||||
|
mockUnwrappedElement,
|
||||||
testModel,
|
testModel,
|
||||||
|
testRect,
|
||||||
gesture,
|
gesture,
|
||||||
callbacks;
|
callbacks;
|
||||||
|
|
||||||
@ -35,6 +38,7 @@ define(
|
|||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
testModel = { composition: [] };
|
testModel = { composition: [] };
|
||||||
|
testRect = {};
|
||||||
|
|
||||||
mockQ = { when: mockPromise };
|
mockQ = { when: mockPromise };
|
||||||
mockElement = jasmine.createSpyObj("element", JQLITE_FUNCTIONS);
|
mockElement = jasmine.createSpyObj("element", JQLITE_FUNCTIONS);
|
||||||
@ -42,11 +46,17 @@ define(
|
|||||||
mockPersistence = jasmine.createSpyObj("persistence", [ "persist" ]);
|
mockPersistence = jasmine.createSpyObj("persistence", [ "persist" ]);
|
||||||
mockEvent = jasmine.createSpyObj("event", ["preventDefault"]);
|
mockEvent = jasmine.createSpyObj("event", ["preventDefault"]);
|
||||||
mockEvent.dataTransfer = jasmine.createSpyObj("dataTransfer", [ "getData" ]);
|
mockEvent.dataTransfer = jasmine.createSpyObj("dataTransfer", [ "getData" ]);
|
||||||
|
mockScope = jasmine.createSpyObj("$scope", ["$broadcast"]);
|
||||||
|
mockUnwrappedElement = jasmine.createSpyObj("unwrapped", ["getBoundingClientRect"]);
|
||||||
|
|
||||||
mockDomainObject.getId.andReturn(TEST_ID);
|
mockDomainObject.getId.andReturn(TEST_ID);
|
||||||
mockDomainObject.getModel.andReturn(testModel);
|
mockDomainObject.getModel.andReturn(testModel);
|
||||||
mockDomainObject.getCapability.andReturn(mockPersistence);
|
mockDomainObject.getCapability.andReturn(mockPersistence);
|
||||||
|
mockDomainObject.useCapability.andReturn(true);
|
||||||
mockEvent.dataTransfer.getData.andReturn(DROP_ID);
|
mockEvent.dataTransfer.getData.andReturn(DROP_ID);
|
||||||
|
mockElement[0] = mockUnwrappedElement;
|
||||||
|
mockElement.scope.andReturn(mockScope);
|
||||||
|
mockUnwrappedElement.getBoundingClientRect.andReturn(testRect);
|
||||||
|
|
||||||
gesture = new DropGesture(mockQ, mockElement, mockDomainObject);
|
gesture = new DropGesture(mockQ, mockElement, mockDomainObject);
|
||||||
|
|
||||||
@ -114,6 +124,19 @@ define(
|
|||||||
expect(mockDomainObject.getCapability).toHaveBeenCalledWith("persistence");
|
expect(mockDomainObject.getCapability).toHaveBeenCalledWith("persistence");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("broadcasts drop position", function () {
|
||||||
|
testRect.left = 42;
|
||||||
|
testRect.top = 36;
|
||||||
|
mockEvent.pageX = 52;
|
||||||
|
mockEvent.pageY = 64;
|
||||||
|
callbacks.drop(mockEvent);
|
||||||
|
expect(mockScope.$broadcast).toHaveBeenCalledWith(
|
||||||
|
'mctDrop',
|
||||||
|
DROP_ID,
|
||||||
|
{ x: 10, y: 28 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -138,6 +138,11 @@ define(
|
|||||||
function cacheObjectReferences(objects) {
|
function cacheObjectReferences(objects) {
|
||||||
telemetryObjects = objects;
|
telemetryObjects = objects;
|
||||||
metadatas = objects.map(lookupMetadata);
|
metadatas = objects.map(lookupMetadata);
|
||||||
|
// Fire callback, as this will be the first time that
|
||||||
|
// telemetry objects are available
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,10 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("fires callbacks when subscriptions update", function () {
|
it("fires callbacks when subscriptions update", function () {
|
||||||
expect(mockCallback).not.toHaveBeenCalled();
|
// Callback fires when telemetry objects become available,
|
||||||
|
// so track initial call count instead of verifying that
|
||||||
|
// it hasn't been called at all.
|
||||||
|
var initialCalls = mockCallback.calls.length;
|
||||||
mockTelemetry.subscribe.mostRecentCall.args[0](mockSeries);
|
mockTelemetry.subscribe.mostRecentCall.args[0](mockSeries);
|
||||||
// This gets fired via a timeout, so trigger that
|
// This gets fired via a timeout, so trigger that
|
||||||
expect(mockTimeout).toHaveBeenCalledWith(
|
expect(mockTimeout).toHaveBeenCalledWith(
|
||||||
@ -86,12 +89,15 @@ define(
|
|||||||
mockTimeout.mostRecentCall.args[0]();
|
mockTimeout.mostRecentCall.args[0]();
|
||||||
// Should have triggered the callback to alert that
|
// Should have triggered the callback to alert that
|
||||||
// new data was available
|
// new data was available
|
||||||
expect(mockCallback).toHaveBeenCalled();
|
expect(mockCallback.calls.length).toEqual(initialCalls + 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("fires subscription callbacks once per cycle", function () {
|
it("fires subscription callbacks once per cycle", function () {
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
|
// Verify precondition - one call for telemetryObjects
|
||||||
|
expect(mockCallback.calls.length).toEqual(1);
|
||||||
|
|
||||||
for (i = 0; i < 100; i += 1) {
|
for (i = 0; i < 100; i += 1) {
|
||||||
mockTelemetry.subscribe.mostRecentCall.args[0](mockSeries);
|
mockTelemetry.subscribe.mostRecentCall.args[0](mockSeries);
|
||||||
}
|
}
|
||||||
@ -100,7 +106,7 @@ define(
|
|||||||
call.args[0]();
|
call.args[0]();
|
||||||
});
|
});
|
||||||
// Should have only triggered the
|
// Should have only triggered the
|
||||||
expect(mockCallback.calls.length).toEqual(1);
|
expect(mockCallback.calls.length).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("reports its latest observed data values", function () {
|
it("reports its latest observed data values", function () {
|
||||||
@ -129,7 +135,8 @@ define(
|
|||||||
// telemetrySubscription, where failure to callback
|
// telemetrySubscription, where failure to callback
|
||||||
// once-per-update results in loss of data, WTD-784
|
// once-per-update results in loss of data, WTD-784
|
||||||
it("fires one event per update if requested", function () {
|
it("fires one event per update if requested", function () {
|
||||||
var i, domains = [], ranges = [], lastCall;
|
var i, domains = [], ranges = [], lastCall, initialCalls;
|
||||||
|
|
||||||
|
|
||||||
// Clear out the subscription from beforeEach
|
// Clear out the subscription from beforeEach
|
||||||
subscription.unsubscribe();
|
subscription.unsubscribe();
|
||||||
@ -142,6 +149,9 @@ define(
|
|||||||
true // Don't drop updates!
|
true // Don't drop updates!
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Track calls at this point
|
||||||
|
initialCalls = mockCallback.calls.length;
|
||||||
|
|
||||||
// Snapshot getDomainValue, getRangeValue at time of callback
|
// Snapshot getDomainValue, getRangeValue at time of callback
|
||||||
mockCallback.andCallFake(function () {
|
mockCallback.andCallFake(function () {
|
||||||
domains.push(subscription.getDomainValue(mockDomainObject));
|
domains.push(subscription.getDomainValue(mockDomainObject));
|
||||||
@ -163,13 +173,17 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should have only triggered the
|
// Should have only triggered the
|
||||||
expect(mockCallback.calls.length).toEqual(100);
|
expect(mockCallback.calls.length).toEqual(100 + initialCalls);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("provides domain object metadata", function () {
|
it("provides domain object metadata", function () {
|
||||||
expect(subscription.getMetadata()[0])
|
expect(subscription.getMetadata()[0])
|
||||||
.toEqual(testMetadata);
|
.toEqual(testMetadata);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("fires callback when telemetry objects are available", function () {
|
||||||
|
expect(mockCallback.calls.length).toEqual(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
Reference in New Issue
Block a user