mirror of
https://github.com/nasa/openmct.git
synced 2025-03-23 04:25:27 +00:00
Merge remote-tracking branch 'origin/open920' into open-master
This commit is contained in:
commit
b05315a140
8
platform/commonUI/general/README.md
Normal file
8
platform/commonUI/general/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Directives
|
||||
|
||||
* `mct-scroll-x` is an attribute whose value is an assignable
|
||||
Angular expression. This two-way binds that expression to the
|
||||
horizontal scroll state of the element on which it is applied.
|
||||
* `mct-scroll-y` is an attribute whose value is an assignable
|
||||
Angular expression. This two-way binds that expression to the
|
||||
vertical scroll state of the element on which it is applied.
|
@ -105,6 +105,34 @@
|
||||
"key": "mctResize",
|
||||
"implementation": "directives/MCTResize.js",
|
||||
"depends": [ "$timeout" ]
|
||||
},
|
||||
{
|
||||
"key": "mctScrollX",
|
||||
"implementation": "directives/MCTScroll.js",
|
||||
"depends": [ "$parse", "MCT_SCROLL_X_PROPERTY", "MCT_SCROLL_X_ATTRIBUTE" ]
|
||||
},
|
||||
{
|
||||
"key": "mctScrollY",
|
||||
"implementation": "directives/MCTScroll.js",
|
||||
"depends": [ "$parse", "MCT_SCROLL_Y_PROPERTY", "MCT_SCROLL_Y_ATTRIBUTE" ]
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
{
|
||||
"key": "MCT_SCROLL_X_PROPERTY",
|
||||
"value": "scrollLeft"
|
||||
},
|
||||
{
|
||||
"key": "MCT_SCROLL_X_ATTRIBUTE",
|
||||
"value": "mctScrollX"
|
||||
},
|
||||
{
|
||||
"key": "MCT_SCROLL_Y_PROPERTY",
|
||||
"value": "scrollTop"
|
||||
},
|
||||
{
|
||||
"key": "MCT_SCROLL_Y_ATTRIBUTE",
|
||||
"value": "mctScrollY"
|
||||
}
|
||||
],
|
||||
"containers": [
|
||||
|
62
platform/commonUI/general/src/directives/MCTScroll.js
Normal file
62
platform/commonUI/general/src/directives/MCTScroll.js
Normal file
@ -0,0 +1,62 @@
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Implements `mct-scroll-x` and `mct-scroll-y` directives. Listens
|
||||
* for scroll events and publishes their results into scope; watches
|
||||
* scope and updates scroll state to match. This varies for x- and y-
|
||||
* directives only by the attribute name chosen to find the expression,
|
||||
* and the property (scrollLeft or scrollTop) managed within the
|
||||
* element.
|
||||
*
|
||||
* This is exposed as two directives in `bundle.json`; the difference
|
||||
* is handled purely by parameterization.
|
||||
*
|
||||
* @constructor
|
||||
* @param $parse Angular's $parse
|
||||
* @param {string} property property to manage within the HTML element
|
||||
* @param {string} attribute attribute to look at for the assignable
|
||||
* Angular expression
|
||||
*/
|
||||
function MCTScroll($parse, property, attribute) {
|
||||
function link(scope, element, attrs) {
|
||||
var expr = attrs[attribute],
|
||||
parsed = $parse(expr);
|
||||
|
||||
// Set the element's scroll to match the scope's state
|
||||
function updateElement(value) {
|
||||
element[0][property] = value;
|
||||
}
|
||||
|
||||
// Handle event; assign to scroll state to scope
|
||||
function updateScope() {
|
||||
parsed.assign(scope, element[0][property]);
|
||||
scope.$apply(expr);
|
||||
}
|
||||
|
||||
// Initialize state in scope
|
||||
parsed.assign(scope, element[0][property]);
|
||||
|
||||
// Update element state when value in scope changes
|
||||
scope.$watch(expr, updateElement);
|
||||
|
||||
// Update state in scope when element is scrolled
|
||||
element.on('scroll', updateScope);
|
||||
}
|
||||
|
||||
return {
|
||||
// Restrict to attributes
|
||||
restrict: "A",
|
||||
// Use this link function
|
||||
link: link
|
||||
};
|
||||
}
|
||||
|
||||
return MCTScroll;
|
||||
|
||||
}
|
||||
);
|
96
platform/commonUI/general/test/directives/MCTScrollSpec.js
Normal file
96
platform/commonUI/general/test/directives/MCTScrollSpec.js
Normal file
@ -0,0 +1,96 @@
|
||||
/*global define,describe,it,expect,jasmine,beforeEach*/
|
||||
define(
|
||||
['../../src/directives/MCTScroll'],
|
||||
function (MCTScroll) {
|
||||
"use strict";
|
||||
|
||||
var EVENT_PROPERTY = "testProperty",
|
||||
ATTRIBUTE = "testAttribute",
|
||||
EXPRESSION = "some.expression";
|
||||
|
||||
|
||||
// MCTScroll is the commonality between mct-scroll-x and
|
||||
// mct-scroll-y; it gets the event property to watch and
|
||||
// the attribute which contains the associated assignable
|
||||
// expression.
|
||||
describe("An mct-scroll-* directive", function () {
|
||||
var mockParse,
|
||||
mockParsed,
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mctScroll;
|
||||
|
||||
beforeEach(function () {
|
||||
mockParse = jasmine.createSpy('$parse');
|
||||
mockParsed = jasmine.createSpy('parsed');
|
||||
mockParsed.assign = jasmine.createSpy('assign');
|
||||
|
||||
mockScope = jasmine.createSpyObj('$scope', ['$watch', '$apply']);
|
||||
mockElement = [{ testProperty: 42 }];
|
||||
mockElement.on = jasmine.createSpy('on');
|
||||
|
||||
mockParse.andReturn(mockParsed);
|
||||
|
||||
testAttrs = {};
|
||||
testAttrs[ATTRIBUTE] = EXPRESSION;
|
||||
|
||||
mctScroll = new MCTScroll(
|
||||
mockParse,
|
||||
EVENT_PROPERTY,
|
||||
ATTRIBUTE
|
||||
);
|
||||
mctScroll.link(mockScope, mockElement, testAttrs);
|
||||
});
|
||||
|
||||
it("is available for attributes", function () {
|
||||
expect(mctScroll.restrict).toEqual('A');
|
||||
});
|
||||
|
||||
it("does not create an isolate scope", function () {
|
||||
expect(mctScroll.scope).toBeUndefined();
|
||||
});
|
||||
|
||||
it("watches for changes in observed expression", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
EXPRESSION,
|
||||
jasmine.any(Function)
|
||||
);
|
||||
// Should have been only watch (other tests need this to be true)
|
||||
expect(mockScope.$watch.calls.length).toEqual(1);
|
||||
});
|
||||
|
||||
it("listens for scroll events", function () {
|
||||
expect(mockElement.on).toHaveBeenCalledWith(
|
||||
'scroll',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
// Should have been only listener (other tests need this to be true)
|
||||
expect(mockElement.on.calls.length).toEqual(1);
|
||||
});
|
||||
|
||||
it("publishes initial scroll state", function () {
|
||||
expect(mockParse).toHaveBeenCalledWith(EXPRESSION);
|
||||
expect(mockParsed.assign).toHaveBeenCalledWith(mockScope, 42);
|
||||
});
|
||||
|
||||
it("updates scroll state when scope changes", function () {
|
||||
mockScope.$watch.mostRecentCall.args[1](64);
|
||||
expect(mockElement[0].testProperty).toEqual(64);
|
||||
});
|
||||
|
||||
it("updates scope when scroll state changes", function () {
|
||||
mockElement[0].testProperty = 12321;
|
||||
mockElement.on.mostRecentCall.args[1]({ target: mockElement[0] });
|
||||
expect(mockParsed.assign).toHaveBeenCalledWith(mockScope, 12321);
|
||||
expect(mockScope.$apply).toHaveBeenCalledWith(EXPRESSION);
|
||||
});
|
||||
|
||||
// This would trigger an infinite digest exception
|
||||
it("does not call $apply during construction", function () {
|
||||
expect(mockScope.$apply).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -11,5 +11,6 @@
|
||||
"directives/MCTContainer",
|
||||
"directives/MCTDrag",
|
||||
"directives/MCTResize",
|
||||
"directives/MCTScroll",
|
||||
"StyleSheetLoader"
|
||||
]
|
Loading…
x
Reference in New Issue
Block a user