diff --git a/platform/commonUI/browse/src/navigation/OrphanNavigationHandler.js b/platform/commonUI/browse/src/navigation/OrphanNavigationHandler.js index 2a319876b5..00d6423fa4 100644 --- a/platform/commonUI/browse/src/navigation/OrphanNavigationHandler.js +++ b/platform/commonUI/browse/src/navigation/OrphanNavigationHandler.js @@ -58,7 +58,7 @@ define([], function () { function checkNavigation() { var navigatedObject = navigationService.getNavigation(); - if (navigatedObject.hasCapability('context')) { + if (navigatedObject && navigatedObject.hasCapability('context')) { if (!navigatedObject.getCapability('editor').isEditContextRoot()) { preventOrphanNavigation(navigatedObject); } diff --git a/platform/features/hyperlink/res/templates/hyperlink.html b/platform/features/hyperlink/res/templates/hyperlink.html index 3734e89470..5e3fc597c8 100644 --- a/platform/features/hyperlink/res/templates/hyperlink.html +++ b/platform/features/hyperlink/res/templates/hyperlink.html @@ -19,10 +19,10 @@ this source code distribution or the Licensing information page available at runtime from the About dialog for additional information. --> - - {{domainObject.getModel().displayText}} + 'c-hyperlink--button u-fills-container' : hyperlink.isButton(), + 'c-hyperlink--link' : !hyperlink.isButton() }"> + {{domainObject.getModel().displayText}} diff --git a/platform/features/layout/res/templates/layout.html b/platform/features/layout/res/templates/layout.html deleted file mode 100644 index e18c877006..0000000000 --- a/platform/features/layout/res/templates/layout.html +++ /dev/null @@ -1,83 +0,0 @@ - - -
- - -
-
-
-
- -
- - - - - - - - - - - - - - - - - -
- -
diff --git a/platform/features/layout/src/LayoutController.js b/platform/features/layout/src/LayoutController.js deleted file mode 100644 index ed3b016ae2..0000000000 --- a/platform/features/layout/src/LayoutController.js +++ /dev/null @@ -1,524 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2018, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is 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. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -/** - * This bundle implements object types and associated views for - * display-building. - * @namespace platform/features/layout - */ -define( - [ - 'zepto', - './LayoutDrag' - ], - function ( - $, - LayoutDrag - ) { - - var DEFAULT_DIMENSIONS = [12, 8], - DEFAULT_GRID_SIZE = [32, 32], - MINIMUM_FRAME_SIZE = [320, 180]; - - var DEFAULT_HIDDEN_FRAME_TYPES = [ - 'hyperlink' - ]; - - /** - * The LayoutController is responsible for supporting the - * Layout view. It arranges frames according to saved configuration - * and provides methods for updating these based on mouse - * movement. - * @memberof platform/features/layout - * @constructor - * @param {Scope} $scope the controller's Angular scope - */ - function LayoutController($scope, $element, openmct) { - var self = this, - callbackCount = 0; - - this.$element = $element; - - // Update grid size when it changed - function updateGridSize(layoutGrid) { - var oldSize = self.gridSize; - - self.gridSize = layoutGrid || DEFAULT_GRID_SIZE; - - // Only update panel positions if this actually changed things - if (self.gridSize[0] !== oldSize[0] || - self.gridSize[1] !== oldSize[1]) { - self.layoutPanels(Object.keys(self.positions)); - } - } - - // Position a panel after a drop event - function handleDrop(e, id, position) { - if (e.defaultPrevented) { - return; - } - - $scope.configuration = $scope.configuration || {}; - $scope.configuration.panels = $scope.configuration.panels || {}; - - self.openmct.objects.get(id).then(function (object) { - $scope.configuration.panels[id] = { - position: [ - Math.floor(position.x / self.gridSize[0]), - Math.floor(position.y / self.gridSize[1]) - ], - dimensions: self.defaultDimensions(), - hasFrame: self.getDefaultFrame(object.type) - }; - - // Store the id so that the newly-dropped object - // gets selected during refresh composition - self.droppedIdToSelectAfterRefresh = id; - - self.commit(); - - // Populate template-facing position for this id - self.rawPositions[id] = $scope.configuration.panels[id]; - self.populatePosition(id); - refreshComposition(); - }); - - // Layout may contain embedded views which will - // listen for drops, so call preventDefault() so - // that they can recognize that this event is handled. - e.preventDefault(); - } - - //Will fetch fully contextualized composed objects, and populate - // scope with them. - function refreshComposition() { - //Keep a track of how many composition callbacks have been made - var thisCount = ++callbackCount; - - $scope.domainObject.useCapability('composition').then(function (composition) { - var ids; - - //Is this callback for the most recent composition - // request? If not, discard it. Prevents race condition - if (thisCount === callbackCount) { - ids = composition.map(function (object) { - return object.getId(); - }) || []; - - $scope.composition = composition; - self.layoutPanels(ids); - self.setFrames(ids); - - if (self.selectedId && - self.selectedId !== $scope.domainObject.getId() && - composition.indexOf(self.selectedId) === -1) { - // Click triggers selection of layout parent. - self.$element[0].click(); - } - } - }); - } - - // End drag; we don't want to put $scope into this - // because it triggers "cpws" (copy window or scope) - // errors in Angular. - this.endDragInScope = function () { - // Write to configuration; this is watched and - // saved by the EditRepresenter. - $scope.configuration = - $scope.configuration || {}; - - $scope.configuration.panels = - $scope.configuration.panels || {}; - - $scope.configuration.panels[self.activeDragId] = - $scope.configuration.panels[self.activeDragId] || {}; - - $scope.configuration.panels[self.activeDragId].position = - self.rawPositions[self.activeDragId].position; - $scope.configuration.panels[self.activeDragId].dimensions = - self.rawPositions[self.activeDragId].dimensions; - - self.commit(); - }; - - // Sets the selectable object in response to the selection change event. - function setSelection(selectable) { - var selection = selectable[0]; - - if (!selection) { - delete self.selectedId; - return; - } - - self.selectedId = selection.context.oldItem.getId(); - self.drilledIn = undefined; - self.selectable = selectable; - } - - this.positions = {}; - this.rawPositions = {}; - this.gridSize = DEFAULT_GRID_SIZE; - this.$scope = $scope; - this.drilledIn = undefined; - this.openmct = openmct; - - // Watch for changes to the grid size in the model - $scope.$watch("model.layoutGrid", updateGridSize); - - // Update composed objects on screen, and position panes - $scope.$watchCollection("model.composition", refreshComposition); - - openmct.selection.on('change', setSelection); - - $scope.$on("$destroy", function () { - openmct.selection.off("change", setSelection); - self.unlisten(); - }); - - $scope.$on("mctDrop", handleDrop); - - self.unlisten = self.$scope.domainObject.getCapability('mutation').listen(function (model) { - $scope.configuration = model.configuration.layout; - $scope.model = model; - var panels = $scope.configuration.panels; - - Object.keys(panels).forEach(function (key) { - if (self.frames && self.frames.hasOwnProperty(key)) { - self.frames[key] = panels[key].hasFrame; - } - }); - }); - } - - // 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; - } - - /** - * Set the frames value. If a configuration panel has "hasFrame' property, - * use that value, otherwise set a default value. A 'hyperlink' object should - * have no frame by default. - * - * @param {string[]} ids the object ids - * @private - */ - LayoutController.prototype.setFrames = function (ids) { - var panels = shallowCopy(this.$scope.configuration.panels || {}, ids); - this.frames = {}; - - this.$scope.composition.forEach(function (object) { - var id = object.getId(); - panels[id] = panels[id] || {}; - - if (panels[id].hasOwnProperty('hasFrame')) { - this.frames[id] = panels[id].hasFrame; - } else { - this.frames[id] = this.getDefaultFrame(object.getModel().type); - } - }, this); - }; - - /** - * Gets the default value for frame. - * - * @param type the domain object type - * @return {boolean} true if the object should have - * frame by default, false, otherwise - */ - LayoutController.prototype.getDefaultFrame = function (type) { - return DEFAULT_HIDDEN_FRAME_TYPES.indexOf(type) === -1; - }; - - // Convert from { positions: ..., dimensions: ... } to an - // appropriate ng-style argument, to position frames. - LayoutController.prototype.convertPosition = function (raw) { - var gridSize = this.gridSize; - // Multiply position/dimensions by grid size - return { - left: (gridSize[0] * raw.position[0]) + 'px', - top: (gridSize[1] * raw.position[1]) + 'px', - width: (gridSize[0] * raw.dimensions[0]) + 'px', - height: (gridSize[1] * raw.dimensions[1]) + 'px', - minWidth: (gridSize[0] * raw.dimensions[0]) + 'px', - minHeight: (gridSize[1] * raw.dimensions[1]) + 'px' - }; - }; - - // Generate default positions for a new panel - LayoutController.prototype.defaultDimensions = function () { - var gridSize = this.gridSize; - return MINIMUM_FRAME_SIZE.map(function (min, i) { - return Math.max( - Math.ceil(min / gridSize[i]), - DEFAULT_DIMENSIONS[i] - ); - }); - }; - - // Generate a default position (in its raw format) for a frame. - // Use an index to ensure that default positions are unique. - LayoutController.prototype.defaultPosition = function (index) { - return { - position: [index, index], - dimensions: this.defaultDimensions() - }; - }; - - // Store a computed position for a contained frame by its - // domain object id. Called in a forEach loop, so arguments - // are as expected there. - LayoutController.prototype.populatePosition = function (id, index) { - this.rawPositions[id] = - this.rawPositions[id] || this.defaultPosition(index || 0); - this.positions[id] = - this.convertPosition(this.rawPositions[id]); - }; - - /** - * Get a style object for a frame with the specified domain - * object identifier, suitable for use in an `ng-style` - * directive to position a frame as configured for this layout. - * @param {string} id the object identifier - * @returns {Object.} an object with - * appropriate left, width, etc fields for positioning - */ - LayoutController.prototype.getFrameStyle = function (id) { - // Called in a loop, so just look up; the "positions" - // object is kept up to date by a watch. - return this.positions[id]; - }; - - /** - * Start a drag gesture to move/resize a frame. - * - * The provided position and dimensions factors will determine - * whether this is a move or a resize, and what type it - * will be. For instance, a position factor of [1, 1] - * will move a frame along with the mouse as the drag - * proceeds, while a dimension factor of [0, 0] will leave - * dimensions unchanged. Combining these in different - * ways results in different handles; a position factor of - * [1, 0] and a dimensions factor of [-1, 0] will implement - * a left-edge resize, as the horizontal position will move - * with the mouse while the horizontal dimensions shrink in - * kind (and vertical properties remain unmodified.) - * - * @param {string} id the identifier of the domain object - * in the frame being manipulated - * @param {number[]} posFactor the position factor - * @param {number[]} dimFactor the dimensions factor - */ - LayoutController.prototype.startDrag = function (id, posFactor, dimFactor) { - this.activeDragId = id; - this.activeDrag = new LayoutDrag( - this.rawPositions[id], - posFactor, - dimFactor, - this.gridSize - ); - }; - - /** - * Continue an active drag gesture. - * @param {number[]} delta the offset, in pixels, - * of the current pointer position, relative - * to its position when the drag started - */ - LayoutController.prototype.continueDrag = function (delta) { - if (this.activeDrag) { - this.rawPositions[this.activeDragId] = - this.activeDrag.getAdjustedPosition(delta); - this.populatePosition(this.activeDragId); - } - }; - - /** - * Compute panel positions based on the layout's object model. - * Defined as member function to facilitate testing. - * @private - */ - LayoutController.prototype.layoutPanels = function (ids) { - var configuration = this.$scope.configuration || {}, - self = this; - - // Pull panel positions from configuration - this.rawPositions = - shallowCopy(configuration.panels || {}, ids); - - // Clear prior computed positions - this.positions = {}; - - // Update width/height that we are tracking - this.gridSize = - (this.$scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE; - - // Compute positions and add defaults where needed - ids.forEach(function (id, index) { - self.populatePosition(id, index); - }); - }; - - /** - * End the active drag gesture. This will update the - * view configuration. - */ - LayoutController.prototype.endDrag = function () { - this.dragInProgress = true; - - setTimeout(function () { - this.dragInProgress = false; - }.bind(this), 0); - - this.endDragInScope(); - }; - - /** - * Checks if the object is currently selected. - * - * @param {string} obj the object to check for selection - * @returns {boolean} true if selected, otherwise false - */ - LayoutController.prototype.selected = function (obj) { - var sobj = this.openmct.selection.get()[0]; - return (sobj && sobj.context.oldItem.getId() === obj.getId()) ? true : false; - }; - - /** - * Bypasses selection if drag is in progress. - * - * @param event the angular event object - */ - LayoutController.prototype.bypassSelection = function (event) { - if (this.dragInProgress) { - if (event) { - event.stopPropagation(); - } - return; - } - }; - - /** - * Checks if the domain object is drilled in. - * - * @param domainObject the domain object - * @return true if the object is drilled in, false otherwise - */ - LayoutController.prototype.isDrilledIn = function (domainObject) { - return this.drilledIn === domainObject.getId(); - }; - - /** - * Puts the given object in the drilled-in mode. - * - * @param event the angular event object - * @param domainObject the domain object - */ - LayoutController.prototype.drill = function (event, domainObject) { - if (event) { - event.stopPropagation(); - } - - if (!domainObject.getCapability('editor').inEditContext()) { - return; - } - - if (!domainObject.hasCapability('composition')) { - return; - } - - // Disable since fixed position doesn't use the selection API yet - if (domainObject.getModel().type === 'telemetry.fixed') { - return; - } - - this.drilledIn = domainObject.getId(); - }; - - /** - * Check if the object has frame. - * - * @param {object} obj the object - * @return {boolean} true if object has frame, otherwise false - */ - LayoutController.prototype.hasFrame = function (obj) { - return this.frames[obj.getId()]; - }; - - /** - * Get the size of the grid, in pixels. The returned array - * is in the form `[x, y]`. - * @returns {number[]} the grid size - */ - LayoutController.prototype.getGridSize = function () { - return this.gridSize; - }; - - /** - * Gets the selection context. - * - * @param domainObject the domain object - * @returns {object} the context object which includes item and oldItem - */ - LayoutController.prototype.getContext = function (domainObject) { - return { - item: domainObject.useCapability('adapter'), - oldItem: domainObject - }; - }; - - LayoutController.prototype.commit = function () { - var model = this.$scope.model; - model.configuration = model.configuration || {}; - model.configuration.layout = this.$scope.configuration; - - this.$scope.domainObject.useCapability('mutation', function () { - return model; - }); - }; - - /** - * Selects a newly-dropped object. - * - * @param classSelector the css class selector - * @param domainObject the domain object - */ - LayoutController.prototype.selectIfNew = function (selector, domainObject) { - if (domainObject.getId() === this.droppedIdToSelectAfterRefresh) { - setTimeout(function () { - $('[data-layout-id="' + selector + '"]')[0].click(); - delete this.droppedIdToSelectAfterRefresh; - }.bind(this), 0); - } - }; - - return LayoutController; - } -); - diff --git a/platform/features/layout/test/LayoutControllerSpec.js b/platform/features/layout/test/LayoutControllerSpec.js deleted file mode 100644 index 06d425064f..0000000000 --- a/platform/features/layout/test/LayoutControllerSpec.js +++ /dev/null @@ -1,479 +0,0 @@ -/***************************************************************************** - * Open MCT, Copyright (c) 2014-2018, United States Government - * as represented by the Administrator of the National Aeronautics and Space - * Administration. All rights reserved. - * - * Open MCT is 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. - * - * Open MCT includes source code licensed under additional open source - * licenses. See the Open Source Licenses file (LICENSES.md) included with - * this source code distribution or the Licensing information page available - * at runtime from the About dialog for additional information. - *****************************************************************************/ - -define( - [ - "../src/LayoutController", - "zepto" - ], - function ( - LayoutController, - $ - ) { - - describe("The Layout controller", function () { - var mockScope, - mockEvent, - testModel, - testConfiguration, - controller, - mockCompositionCapability, - mockComposition, - mockCompositionObjects, - mockOpenMCT, - mockSelection, - mockDomainObjectCapability, - mockObjects, - unlistenFunc, - $element = [], - selectable = []; - - function mockPromise(value) { - return { - then: function (thenFunc) { - return mockPromise(thenFunc(value)); - } - }; - } - - function mockDomainObject(id) { - return { - getId: function () { - return id; - }, - useCapability: function () { - return mockCompositionCapability; - }, - getModel: function () { - if (id === 'b') { - return { - type : 'hyperlink' - }; - } else { - return {}; - } - }, - getCapability: function () { - return mockDomainObjectCapability; - }, - hasCapability: function (param) { - if (param === 'composition') { - return id !== 'b'; - } - }, - type: "testType" - }; - } - - beforeEach(function () { - mockScope = jasmine.createSpyObj( - "$scope", - ["$watch", "$watchCollection", "$on"] - ); - mockEvent = jasmine.createSpyObj( - 'event', - ['preventDefault', 'stopPropagation'] - ); - - testModel = {}; - - mockComposition = ["a", "b", "c"]; - mockCompositionObjects = mockComposition.map(mockDomainObject); - - testConfiguration = { - panels: { - a: { - position: [20, 10], - dimensions: [5, 5] - } - } - }; - - unlistenFunc = jasmine.createSpy("unlisten"); - mockDomainObjectCapability = jasmine.createSpyObj('capability', - ['inEditContext', 'listen'] - ); - mockDomainObjectCapability.listen.and.returnValue(unlistenFunc); - - mockCompositionCapability = mockPromise(mockCompositionObjects); - - mockScope.domainObject = mockDomainObject("mockDomainObject"); - mockScope.model = testModel; - mockScope.configuration = testConfiguration; - - selectable[0] = { - context: { - oldItem: mockScope.domainObject - } - }; - - mockSelection = jasmine.createSpyObj("selection", [ - 'select', - 'on', - 'off', - 'get' - ]); - mockSelection.get.and.returnValue(selectable); - - mockObjects = jasmine.createSpyObj('objects', [ - 'get' - ]); - mockObjects.get.and.returnValue(mockPromise(mockDomainObject("mockObject"))); - mockOpenMCT = { - selection: mockSelection, - objects: mockObjects - }; - - $element = $('
'); - $(document).find('body').append($element); - spyOn($element[0], 'click'); - - spyOn(mockScope.domainObject, "useCapability").and.callThrough(); - - controller = new LayoutController(mockScope, $element, mockOpenMCT); - spyOn(controller, "layoutPanels").and.callThrough(); - spyOn(controller, "commit"); - - jasmine.clock().install(); - }); - - afterEach(function () { - $element.remove(); - jasmine.clock().uninstall(); - }); - - - it("listens for selection change events", function () { - expect(mockOpenMCT.selection.on).toHaveBeenCalledWith( - 'change', - jasmine.any(Function) - ); - }); - - it("cleans up on scope destroy", function () { - expect(mockScope.$on).toHaveBeenCalledWith( - '$destroy', - jasmine.any(Function) - ); - - mockScope.$on.calls.all()[0].args[1](); - - expect(mockOpenMCT.selection.off).toHaveBeenCalledWith( - 'change', - jasmine.any(Function) - ); - }); - - // Model changes will indicate that panel positions - // may have changed, for instance. - it("watches for changes to composition", function () { - expect(mockScope.$watchCollection).toHaveBeenCalledWith( - "model.composition", - jasmine.any(Function) - ); - }); - - it("Retrieves updated composition from composition capability", function () { - mockScope.$watchCollection.calls.mostRecent().args[1](); - expect(mockScope.domainObject.useCapability).toHaveBeenCalledWith( - "composition" - ); - expect(controller.layoutPanels).toHaveBeenCalledWith( - mockComposition - ); - }); - - it("Is robust to concurrent changes to composition", function () { - var secondMockComposition = ["a", "b", "c", "d"], - secondMockCompositionObjects = secondMockComposition.map(mockDomainObject), - firstCompositionCB, - secondCompositionCB; - - spyOn(mockCompositionCapability, "then"); - mockScope.$watchCollection.calls.mostRecent().args[1](); - mockScope.$watchCollection.calls.mostRecent().args[1](); - - firstCompositionCB = mockCompositionCapability.then.calls.all()[0].args[0]; - secondCompositionCB = mockCompositionCapability.then.calls.all()[1].args[0]; - - //Resolve promises in reverse order - secondCompositionCB(secondMockCompositionObjects); - firstCompositionCB(mockCompositionObjects); - - //Expect the promise call that was initiated most recently to - // be the one used to populate scope, irrespective of order that - // it was eventually resolved - expect(mockScope.composition).toBe(secondMockCompositionObjects); - }); - - - it("provides styles for frames, from configuration", function () { - mockScope.$watchCollection.calls.mostRecent().args[1](); - expect(controller.getFrameStyle("a")).toEqual({ - top: "320px", - left: "640px", - width: "160px", - height: "160px", - minWidth : '160px', - minHeight : '160px' - }); - }); - - it("provides default styles for frames", function () { - var styleB, styleC; - - // b and c do not have configured positions - mockScope.$watchCollection.calls.mostRecent().args[1](); - - styleB = controller.getFrameStyle("b"); - styleC = controller.getFrameStyle("c"); - - // Should have a position, but we don't care what - expect(styleB.left).toBeDefined(); - expect(styleB.top).toBeDefined(); - expect(styleC.left).toBeDefined(); - expect(styleC.top).toBeDefined(); - - // Should have ensured some difference in position - expect(styleB).not.toEqual(styleC); - }); - - it("allows panels to be dragged", function () { - // Populate scope - mockScope.$watchCollection.calls.mostRecent().args[1](); - - // Verify precondition - expect(testConfiguration.panels.b).not.toBeDefined(); - - // Do a drag - controller.startDrag("b", [1, 1], [0, 0]); - controller.continueDrag([100, 100]); - controller.endDrag(); - - // We do not look closely at the details here; - // that is tested in LayoutDragSpec. Just make sure - // that a configuration for b has been defined. - expect(testConfiguration.panels.b).toBeDefined(); - }); - - - it("invokes commit after drag", function () { - // Populate scope - mockScope.$watchCollection.calls.mostRecent().args[1](); - - // Do a drag - controller.startDrag("b", [1, 1], [0, 0]); - controller.continueDrag([100, 100]); - controller.endDrag(); - - expect(controller.commit).toHaveBeenCalled(); - }); - - it("listens for drop events", function () { - // Layout should position panels according to - // where the user dropped them, so it needs to - // listen for drop events. - expect(mockScope.$on).toHaveBeenCalledWith( - 'mctDrop', - jasmine.any(Function) - ); - - // Verify precondition - expect(testConfiguration.panels.d).not.toBeDefined(); - - // Notify that a drop occurred - mockScope.$on.calls.mostRecent().args[1]( - mockEvent, - 'd', - { x: 300, y: 100 } - ); - expect(testConfiguration.panels.d).toBeDefined(); - expect(mockEvent.preventDefault).toHaveBeenCalled(); - expect(controller.commit).toHaveBeenCalled(); - }); - - it("ignores drops when default has been prevented", function () { - // Avoids redundant drop-handling, WTD-1233 - mockEvent.defaultPrevented = true; - - // Notify that a drop occurred - mockScope.$on.calls.mostRecent().args[1]( - mockEvent, - 'd', - { x: 300, y: 100 } - ); - expect(testConfiguration.panels.d).not.toBeDefined(); - }); - - it("ensures a minimum frame size", function () { - var styleB; - - // Start with a very small frame size - testModel.layoutGrid = [1, 1]; - - // White-boxy; we know which watch is which - mockScope.$watch.calls.all()[0].args[1](testModel.layoutGrid); - mockScope.$watchCollection.calls.all()[0].args[1](testModel.composition); - - styleB = controller.getFrameStyle("b"); - - // Resulting size should still be reasonably large pixel-size - expect(parseInt(styleB.width, 10)).toBeGreaterThan(63); - expect(parseInt(styleB.width, 10)).toBeGreaterThan(31); - }); - - it("ensures a minimum frame size on drop", function () { - var style; - - // Start with a very small frame size - testModel.layoutGrid = [1, 1]; - mockScope.$watch.calls.all()[0].args[1](testModel.layoutGrid); - - // Add a new object to the composition - mockComposition = ["a", "b", "c", "d"]; - mockCompositionObjects = mockComposition.map(mockDomainObject); - mockCompositionCapability = mockPromise(mockCompositionObjects); - - // Notify that a drop occurred - mockScope.$on.calls.mostRecent().args[1]( - mockEvent, - 'd', - { x: 300, y: 100 } - ); - - style = controller.getFrameStyle("d"); - - // Resulting size should still be reasonably large pixel-size - expect(parseInt(style.width, 10)).toBeGreaterThan(63); - expect(parseInt(style.height, 10)).toBeGreaterThan(31); - }); - - it("updates positions of existing objects on a drop", function () { - var oldStyle; - - mockScope.$watchCollection.calls.mostRecent().args[1](); - - oldStyle = controller.getFrameStyle("b"); - - expect(oldStyle).toBeDefined(); - - // ...drop event... - mockScope.$on.calls.mostRecent() - .args[1](mockEvent, 'b', { x: 300, y: 100 }); - - expect(controller.getFrameStyle("b")) - .not.toEqual(oldStyle); - }); - - it("allows objects to be selected", function () { - mockScope.$watchCollection.calls.mostRecent().args[1](); - var childObj = mockCompositionObjects[0]; - selectable[0].context.oldItem = childObj; - mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable); - - expect(controller.selected(childObj)).toBe(true); - }); - - it("prevents event bubbling while drag is in progress", function () { - mockScope.$watchCollection.calls.mostRecent().args[1](); - var childObj = mockCompositionObjects[0]; - - // Do a drag - controller.startDrag(childObj.getId(), [1, 1], [0, 0]); - controller.continueDrag([100, 100]); - controller.endDrag(); - - // Because mouse position could cause the parent object to be selected, this should be ignored. - controller.bypassSelection(mockEvent); - - expect(mockEvent.stopPropagation).toHaveBeenCalled(); - - // Shoud be able to select another object when dragging is done. - jasmine.clock().tick(0); - mockEvent.stopPropagation.calls.reset(); - controller.bypassSelection(mockEvent); - - expect(mockEvent.stopPropagation).not.toHaveBeenCalled(); - }); - - it("shows frames by default", function () { - mockScope.$watchCollection.calls.mostRecent().args[1](); - - expect(controller.hasFrame(mockCompositionObjects[0])).toBe(true); - }); - - it("hyperlinks hide frame by default", function () { - mockScope.$watchCollection.calls.mostRecent().args[1](); - - expect(controller.hasFrame(mockCompositionObjects[1])).toBe(false); - }); - - it("selects the parent object when selected object is removed", function () { - mockScope.$watchCollection.calls.mostRecent().args[1](); - var childObj = mockCompositionObjects[0]; - selectable[0].context.oldItem = childObj; - mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable); - - var composition = ["b", "c"]; - mockScope.$watchCollection.calls.mostRecent().args[1](composition); - - expect($element[0].click).toHaveBeenCalled(); - }); - - it("allows objects to be drilled-in only when editing", function () { - mockScope.$watchCollection.calls.mostRecent().args[1](); - var childObj = mockCompositionObjects[0]; - childObj.getCapability().inEditContext.and.returnValue(false); - controller.drill(mockEvent, childObj); - - expect(controller.isDrilledIn(childObj)).toBe(false); - }); - - it("allows objects to be drilled-in only if it has sub objects", function () { - mockScope.$watchCollection.calls.mostRecent().args[1](); - var childObj = mockCompositionObjects[1]; - childObj.getCapability().inEditContext.and.returnValue(true); - controller.drill(mockEvent, childObj); - - expect(controller.isDrilledIn(childObj)).toBe(false); - }); - - it("selects a newly-dropped object", function () { - mockScope.$on.calls.mostRecent().args[1]( - mockEvent, - 'd', - { x: 300, y: 100 } - ); - - var childObj = mockDomainObject("d"); - var testElement = $("
"); - $element.append(testElement); - spyOn(testElement[0], 'click'); - - controller.selectIfNew('some-id', childObj); - jasmine.clock().tick(0); - - expect(testElement[0].click).toHaveBeenCalled(); - }); - }); - } -); diff --git a/src/MCT.js b/src/MCT.js index e747cc992e..af53e8076e 100644 --- a/src/MCT.js +++ b/src/MCT.js @@ -228,6 +228,7 @@ define([ this.legacyRegistry = defaultRegistry; this.install(this.plugins.Plot()); this.install(this.plugins.TelemetryTable()); + this.install(this.plugins.DisplayLayout()); if (typeof BUILD_CONSTANTS !== 'undefined') { this.install(buildInfoPlugin(BUILD_CONSTANTS)); diff --git a/src/defaultRegistry.js b/src/defaultRegistry.js index cbd4d677fc..3f575be501 100644 --- a/src/defaultRegistry.js +++ b/src/defaultRegistry.js @@ -56,7 +56,6 @@ define([ '../platform/features/clock/bundle', '../platform/features/fixed/bundle', '../platform/features/imagery/bundle', - '../platform/features/layout/bundle', '../platform/features/my-items/bundle', '../platform/features/pages/bundle', '../platform/features/hyperlink/bundle', @@ -99,7 +98,6 @@ define([ 'platform/features/clock', 'platform/features/fixed', 'platform/features/imagery', - 'platform/features/layout', 'platform/features/pages', 'platform/features/hyperlink', 'platform/features/timeline', diff --git a/src/plugins/displayLayout/DisplayLayout.vue b/src/plugins/displayLayout/DisplayLayout.vue new file mode 100644 index 0000000000..1fa403e26f --- /dev/null +++ b/src/plugins/displayLayout/DisplayLayout.vue @@ -0,0 +1,331 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is 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. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + + + + + + + \ No newline at end of file diff --git a/src/plugins/displayLayout/DisplayLayoutType.js b/src/plugins/displayLayout/DisplayLayoutType.js new file mode 100644 index 0000000000..c1de4c7204 --- /dev/null +++ b/src/plugins/displayLayout/DisplayLayoutType.js @@ -0,0 +1,41 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is 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. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +define(function () { + function DisplayLayoutType() { + return { + name: "Display Layout", + creatable: true, + cssClass: 'icon-layout', + initialize(domainObject) { + domainObject.composition = []; + domainObject.configuration = { + layout: { + panels: {} + } + }; + } + } + } + + return DisplayLayoutType; +}); \ No newline at end of file diff --git a/src/plugins/displayLayout/LayoutDrag.js b/src/plugins/displayLayout/LayoutDrag.js new file mode 100644 index 0000000000..a950cbdb3a --- /dev/null +++ b/src/plugins/displayLayout/LayoutDrag.js @@ -0,0 +1,115 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is 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. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +define( + [], + function () { + + /** + * Handles drag interactions on frames in layouts. This will + * provides new positions/dimensions for frames based on + * relative pixel positions provided; these will take into account + * the grid size (in a snap-to sense) and will enforce some minimums + * on both position and dimensions. + * + * The provided position and dimensions factors will determine + * whether this is a move or a resize, and what type of resize it + * will be. For instance, a position factor of [1, 1] + * will move a frame along with the mouse as the drag + * proceeds, while a dimension factor of [0, 0] will leave + * dimensions unchanged. Combining these in different + * ways results in different handles; a position factor of + * [1, 0] and a dimensions factor of [-1, 0] will implement + * a left-edge resize, as the horizontal position will move + * with the mouse while the horizontal dimensions shrink in + * kind (and vertical properties remain unmodified.) + * + * @param {object} rawPosition the initial position/dimensions + * of the frame being interacted with + * @param {number[]} posFactor the position factor + * @param {number[]} dimFactor the dimensions factor + * @param {number[]} the size of each grid element, in pixels + * @constructor + * @memberof platform/features/layout + */ + function LayoutDrag(rawPosition, posFactor, dimFactor, gridSize) { + this.rawPosition = rawPosition; + this.posFactor = posFactor; + this.dimFactor = dimFactor; + this.gridSize = gridSize; + } + + // Convert a delta from pixel coordinates to grid coordinates, + // rounding to whole-number grid coordinates. + function toGridDelta(gridSize, pixelDelta) { + return pixelDelta.map(function (v, i) { + return Math.round(v / gridSize[i]); + }); + } + + // Utility function to perform element-by-element multiplication + function multiply(array, factors) { + return array.map(function (v, i) { + return v * factors[i]; + }); + } + + // Utility function to perform element-by-element addition + function add(array, other) { + return array.map(function (v, i) { + return v + other[i]; + }); + } + + // Utility function to perform element-by-element max-choosing + function max(array, other) { + return array.map(function (v, i) { + return Math.max(v, other[i]); + }); + } + + + /** + * Get a new position object in grid coordinates, with + * position and dimensions both offset appropriately + * according to the factors supplied in the constructor. + * @param {number[]} pixelDelta the offset from the + * original position, in pixels + */ + LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) { + var gridDelta = toGridDelta(this.gridSize, pixelDelta); + return { + position: max(add( + this.rawPosition.position, + multiply(gridDelta, this.posFactor) + ), [0, 0]), + dimensions: max(add( + this.rawPosition.dimensions, + multiply(gridDelta, this.dimFactor) + ), [1, 1]) + }; + }; + + return LayoutDrag; + + } +); diff --git a/src/plugins/displayLayout/LayoutFrame.vue b/src/plugins/displayLayout/LayoutFrame.vue new file mode 100644 index 0000000000..904aef92ec --- /dev/null +++ b/src/plugins/displayLayout/LayoutFrame.vue @@ -0,0 +1,338 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is 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. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + + + + + + + \ No newline at end of file diff --git a/src/plugins/displayLayout/plugin.js b/src/plugins/displayLayout/plugin.js new file mode 100644 index 0000000000..fb58b8054d --- /dev/null +++ b/src/plugins/displayLayout/plugin.js @@ -0,0 +1,67 @@ +/***************************************************************************** + * Open MCT, Copyright (c) 2014-2018, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT is 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. + * + * Open MCT includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +import Layout from './DisplayLayout.vue' +import Vue from 'vue' +import objectUtils from '../../api/objects/object-utils.js' +import DisplayLayoutType from './DisplayLayoutType.js' + +export default function () { + return function (openmct) { + openmct.objectViews.addProvider({ + key: 'layout.view', + canView: function (domainObject) { + return domainObject.type === 'layout'; + }, + view: function (domainObject) { + let component; + return { + show(container) { + component = new Vue({ + components: { + Layout + }, + template: '', + provide: { + openmct, + objectUtils + }, + el: container, + data () { + return { + domainObject: domainObject + } + } + }); + }, + destroy() { + component.$destroy(); + } + }; + }, + priority() { + return 100; + } + }); + openmct.types.addType('layout', DisplayLayoutType()); + } +} \ No newline at end of file diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js index ab44dd2c2e..17e2c17752 100644 --- a/src/plugins/plugins.js +++ b/src/plugins/plugins.js @@ -35,6 +35,7 @@ define([ './telemetryTable/plugin', './staticRootPlugin/plugin', './notebook/plugin', + './displayLayout/plugin', './folderView/plugin' ], function ( _, @@ -51,6 +52,7 @@ define([ TelemetryTablePlugin, StaticRootPlugin, Notebook, + DisplayLayoutPlugin, FolderView ) { var bundleMap = { @@ -161,6 +163,7 @@ define([ plugins.TelemetryMean = TelemetryMean; plugins.URLIndicator = URLIndicatorPlugin; plugins.Notebook = Notebook; + plugins.DisplayLayout = DisplayLayoutPlugin.default; plugins.FolderView = FolderView; return plugins; diff --git a/src/plugins/summaryWidget/src/SummaryWidget.js b/src/plugins/summaryWidget/src/SummaryWidget.js index 9c3436a143..7b5b669de8 100644 --- a/src/plugins/summaryWidget/src/SummaryWidget.js +++ b/src/plugins/summaryWidget/src/SummaryWidget.js @@ -264,7 +264,7 @@ define([ this.applyStyle($('#widget', this.domElement), activeRule.getProperty('style')); $('#widget', this.domElement).prop('title', activeRule.getProperty('message')); $('#widgetLabel', this.domElement).html(activeRule.getProperty('label')); - $('#widgetLabel', this.domElement).removeClass().addClass('label widget-label ' + activeRule.getProperty('icon')); + $('#widgetLabel', this.domElement).removeClass().addClass('label widget-label c-summary-widget__label ' + activeRule.getProperty('icon')); }; /** diff --git a/src/plugins/summaryWidget/src/views/SummaryWidgetView.js b/src/plugins/summaryWidget/src/views/SummaryWidgetView.js index cedfd90f7e..38826081b7 100644 --- a/src/plugins/summaryWidget/src/views/SummaryWidgetView.js +++ b/src/plugins/summaryWidget/src/views/SummaryWidgetView.js @@ -18,7 +18,7 @@ define([ this.widget.title = datum.message; this.label.title = datum.message; this.label.innerHTML = datum.ruleLabel; - this.label.className = 'label widget-label ' + datum.icon; + this.label.className = 'label widget-label c-summary-widget__label ' + datum.icon; }; SummaryWidgetView.prototype.render = function () { diff --git a/src/plugins/summaryWidget/src/views/summary-widget.html b/src/plugins/summaryWidget/src/views/summary-widget.html index b8675649cd..d6af1ea539 100644 --- a/src/plugins/summaryWidget/src/views/summary-widget.html +++ b/src/plugins/summaryWidget/src/views/summary-widget.html @@ -1,5 +1,5 @@ -
- - Loading... + diff --git a/src/styles-new/_constants.scss b/src/styles-new/_constants.scss index 6fb8d8b564..2fb9f0baaf 100644 --- a/src/styles-new/_constants.scss +++ b/src/styles-new/_constants.scss @@ -121,7 +121,7 @@ $glyph-icon-pointer-right: '\e1028'; $glyph-icon-refresh: '\e1029'; $glyph-icon-save: '\e1030'; $glyph-icon-sine: '\e1031'; -$glyph-icon-T: '\e1032'; +$glyph-icon-font: '\e1032'; $glyph-icon-thumbs-strip: '\e1033'; $glyph-icon-two-parts-both: '\e1034'; $glyph-icon-two-parts-one-only: '\e1035'; @@ -138,7 +138,7 @@ $glyph-icon-frame-show: '\e1045'; $glyph-icon-frame-hide: '\e1046'; $glyph-icon-import: '\e1047'; $glyph-icon-export: '\e1048'; -$glyph-icon-minimize: '\e1049'; // 12px only +$glyph-icon-font-size: '\e1049'; $glyph-icon-activity: '\e1100'; $glyph-icon-activity-mode: '\e1101'; $glyph-icon-autoflow-tabular: '\e1102'; diff --git a/src/styles-new/_controls.scss b/src/styles-new/_controls.scss index 426b123c75..3a2dd1fb1f 100644 --- a/src/styles-new/_controls.scss +++ b/src/styles-new/_controls.scss @@ -78,7 +78,7 @@ &:hover { background: $colorBtnCautionBgHov; } -} + } } @mixin cClickIcon() { @@ -111,24 +111,24 @@ // Wraps --menu elements, contains button and menu overflow: visible; - .c-menu { + .c-menu { // Default position of contained menu - top: 100%; left: 0; - } + top: 100%; left: 0; + } &[class*='--menus-up'] { - .c-menu { - top: auto; bottom: 100%; - } - } - - &[class*='--menus-left'] { - .c-menu { - left: auto; right: 0; - } + .c-menu { + top: auto; bottom: 100%; } } + &[class*='--menus-left'] { + .c-menu { + left: auto; right: 0; + } + } +} + /********* Buttons */ // Optionally can include icon in :before via markup button { @@ -237,38 +237,11 @@ button { } /******************************************************** FORM ELEMENTS */ -input, textarea { - font-family: inherit; - font-weight: inherit; - letter-spacing: inherit; -} - -input[type=text], -input[type=search], -input[type=number] { - @include reactive-input(); - padding: $inputTextP; - &.numeric { - text-align: right; - } -} - -.c-input { - &--datetime { - // Sized for values such as 2018-09-28 22:32:33.468Z - width: 160px; - } - - &--hrs-min-sec { - // Sized for values such as 00:25:00 - width: 60px; - } - - &-inline, - &--inline { -// A text input or contenteditable element that indicates edit affordance on hover and looks like an input on focus - @include reactive-input(); - box-shadow: none; +/********* Inline inputs */ +.c-input-inline { + // A text input or contenteditable element that indicates edit affordance on hover and looks like an input on focus + @include input-base(); + border: 1px solid transparent; display: block !important; min-width: 0; padding-left: 0; @@ -286,10 +259,16 @@ input[type=number] { padding-left: $inputTextPLeftRight; padding-right: $inputTextPLeftRight; } + &:hover { + border-color: rgba($colorBodyFg, 0.2); + } + &:focus { + @include nice-input($shdw: rgba(0, 0, 0, 0.6) 0 1px 3px); + border-color: transparent; + } } - &--labeled { - // TODO: replace .c-labeled-input with this +.c-labeled-input { // An input used in the Toolbar // Assumes label is before the input @include cControl(); @@ -298,6 +277,16 @@ input[type=number] { margin-left: $interiorMarginSm; } } + +/******************************************************** HYPERLINKS AND HYPERLINK BUTTONS */ +.c-hyperlink { + &--link { + color: $colorKey; + } + + &--button { + @include cButton(); + } } .c-labeled-input { @@ -360,6 +349,10 @@ input[type=number] { } } +@mixin modalMenu() { + // Optional modifier that makes a c-menu more mobile-friendly +} + .c-menu { @include menuOuter(); @include menuInner(); @@ -583,9 +576,3 @@ input[type=number] { } } } - -/***************************************************** SLIDERS */ -.c-slider { - @include cControl(); - > * + * { margin-left: $interiorMargin; } -} diff --git a/src/styles-new/_global.scss b/src/styles-new/_global.scss index ff09b73f2c..c8964682e0 100644 --- a/src/styles-new/_global.scss +++ b/src/styles-new/_global.scss @@ -49,7 +49,7 @@ font-style: normal; } -/******************************* RESETS */ +/******************************************************** RESETS */ *, :before, :after { @@ -60,7 +60,7 @@ div { position: relative; } -/******************************* UTILITIES */ +/******************************************************** UTILITIES */ .u-contents { display: contents; } @@ -74,7 +74,7 @@ div { } } -/******************************* BROWSER ELEMENTS */ +/******************************************************** BROWSER ELEMENTS */ body.desktop { ::-webkit-scrollbar { box-sizing: border-box; @@ -111,6 +111,13 @@ body.desktop { } } +input[type=number]::-webkit-inner-spin-button, +input[type=number]::-webkit-outer-spin-button { + //margin: -1px -5px inherit -5px !important; + margin-right: -5px !important; + margin-top: -1px !important; +} + /************************** HTML ENTITIES */ a { color: $colorA; @@ -175,7 +182,6 @@ li { padding: 0; } - /******************************************************** HAS */ // Local Controls: Controls placed in proximity to or overlaid on components and views body.desktop .has-local-controls { @@ -217,7 +223,21 @@ body.desktop .has-local-controls { //} //} -/************************** LEGACY */ +/******************************************************** IS */ + +.is-selectable { + &:hover { + + } + +} + +.is-editing { + .is-selectable { + + } +} +/******************************************************** LEGACY */ mct-container { display: block; @@ -289,21 +309,6 @@ a.disabled { text-align: center; } -.no-selection { - // aka selection = "None". Used in palettes and their menu buttons. - $c: red; - $s: 48%; - $e: 52%; - background-image: linear-gradient(-45deg, - transparent $s - 5%, - $c $s, - $c $e, - transparent $e + 5% - ); - background-repeat: no-repeat; - background-size: contain; -} - .scrolling, .scroll { overflow: auto; @@ -386,3 +391,8 @@ a.disabled { .t-imagery { display: contents; } + +.t-frame-outer { + min-width: 200px; + min-height: 200px; +} diff --git a/src/styles-new/_glyphs.scss b/src/styles-new/_glyphs.scss index bc0f7e730a..142e3be55f 100644 --- a/src/styles-new/_glyphs.scss +++ b/src/styles-new/_glyphs.scss @@ -113,7 +113,7 @@ .icon-refresh { @include glyphBefore($glyph-icon-refresh); } .icon-save { @include glyphBefore($glyph-icon-save); } .icon-sine { @include glyphBefore($glyph-icon-sine); } -.icon-T { @include glyphBefore($glyph-icon-T); } +.icon-font { @include glyphBefore($glyph-icon-font); } .icon-thumbs-strip { @include glyphBefore($glyph-icon-thumbs-strip); } .icon-two-parts-both { @include glyphBefore($glyph-icon-two-parts-both); } .icon-two-parts-one-only { @include glyphBefore($glyph-icon-two-parts-one-only); } @@ -130,6 +130,7 @@ .icon-frame-hide { @include glyphBefore($glyph-icon-frame-hide); } .icon-import { @include glyphBefore($glyph-icon-import); } .icon-export { @include glyphBefore($glyph-icon-export); } +.icon-font-size { @include glyphBefore($glyph-icon-font-size); } .icon-activity { @include glyphBefore($glyph-icon-activity); } .icon-activity-mode { @include glyphBefore($glyph-icon-activity-mode); } .icon-autoflow-tabular { @include glyphBefore($glyph-icon-autoflow-tabular); } diff --git a/src/styles-new/_mixins.scss b/src/styles-new/_mixins.scss index 30767101cc..46b87e3c01 100644 --- a/src/styles-new/_mixins.scss +++ b/src/styles-new/_mixins.scss @@ -177,7 +177,6 @@ } } - @mixin input-base() { @include htmlInputReset(); border-radius: $controlCr; diff --git a/src/styles-new/fonts/icomoon-project-openmct-symbols-16px.json b/src/styles-new/fonts/icomoon-project-openmct-symbols-16px.json index eaef303c41..f092dac961 100644 --- a/src/styles-new/fonts/icomoon-project-openmct-symbols-16px.json +++ b/src/styles-new/fonts/icomoon-project-openmct-symbols-16px.json @@ -2,7 +2,7 @@ "metadata": { "name": "openmct-symbols-16px", "lastOpened": 0, - "created": 1529545133464 + "created": 1537817705550 }, "iconSets": [ { @@ -525,7 +525,7 @@ "tempChar": "" }, { - "order": 102, + "order": 149, "prevSize": 24, "name": "icon-T", "id": 84, @@ -660,13 +660,21 @@ "code": 921672, "tempChar": "" }, + { + "order": 150, + "id": 119, + "name": "icon-font-size-alt1", + "prevSize": 24, + "code": 921673, + "tempChar": "" + }, { "order": 37, "prevSize": 24, "name": "icon-activity", "id": 32, "code": 921856, - "tempChar": "" + "tempChar": "" }, { "order": 36, @@ -674,7 +682,7 @@ "name": "icon-activity-mode", "id": 31, "code": 921857, - "tempChar": "" + "tempChar": "" }, { "order": 52, @@ -682,7 +690,7 @@ "name": "icon-autoflow-tabular", "id": 47, "code": 921858, - "tempChar": "" + "tempChar": "" }, { "order": 55, @@ -690,7 +698,7 @@ "name": "icon-clock", "id": 50, "code": 921859, - "tempChar": "" + "tempChar": "" }, { "order": 58, @@ -698,7 +706,7 @@ "name": "icon-database", "id": 53, "code": 921860, - "tempChar": "" + "tempChar": "" }, { "order": 57, @@ -706,7 +714,7 @@ "name": "icon-database-query", "id": 52, "code": 921861, - "tempChar": "" + "tempChar": "" }, { "order": 17, @@ -714,7 +722,7 @@ "name": "icon-dataset", "id": 12, "code": 921862, - "tempChar": "" + "tempChar": "" }, { "order": 22, @@ -722,7 +730,7 @@ "name": "icon-datatable", "id": 17, "code": 921863, - "tempChar": "" + "tempChar": "" }, { "order": 59, @@ -730,7 +738,7 @@ "name": "icon-dictionary", "id": 54, "code": 921864, - "tempChar": "" + "tempChar": "" }, { "order": 62, @@ -738,7 +746,7 @@ "name": "icon-folder", "id": 57, "code": 921865, - "tempChar": "" + "tempChar": "" }, { "order": 66, @@ -746,7 +754,7 @@ "name": "icon-image", "id": 61, "code": 921872, - "tempChar": "" + "tempChar": "" }, { "order": 68, @@ -754,7 +762,7 @@ "name": "icon-layout", "id": 63, "code": 921873, - "tempChar": "" + "tempChar": "" }, { "order": 77, @@ -762,7 +770,7 @@ "name": "icon-object", "id": 72, "code": 921874, - "tempChar": "" + "tempChar": "" }, { "order": 78, @@ -770,7 +778,7 @@ "name": "icon-object-unknown", "id": 73, "code": 921875, - "tempChar": "" + "tempChar": "" }, { "order": 79, @@ -778,7 +786,7 @@ "name": "icon-packet", "id": 74, "code": 921876, - "tempChar": "" + "tempChar": "" }, { "order": 80, @@ -786,7 +794,7 @@ "name": "icon-page", "id": 75, "code": 921877, - "tempChar": "" + "tempChar": "" }, { "order": 135, @@ -794,7 +802,7 @@ "name": "icon-plot-overlay", "prevSize": 24, "code": 921878, - "tempChar": "" + "tempChar": "" }, { "order": 113, @@ -802,7 +810,7 @@ "name": "icon-plot-stacked", "prevSize": 24, "code": 921879, - "tempChar": "" + "tempChar": "" }, { "order": 10, @@ -810,7 +818,7 @@ "name": "icon-session", "id": 5, "code": 921880, - "tempChar": "" + "tempChar": "" }, { "order": 24, @@ -818,7 +826,7 @@ "name": "icon-tabular", "id": 19, "code": 921881, - "tempChar": "" + "tempChar": "" }, { "order": 7, @@ -826,7 +834,7 @@ "name": "icon-tabular-lad", "id": 2, "code": 921888, - "tempChar": "" + "tempChar": "" }, { "order": 6, @@ -834,7 +842,7 @@ "name": "icon-tabular-lad-set", "id": 1, "code": 921889, - "tempChar": "" + "tempChar": "" }, { "order": 8, @@ -842,7 +850,7 @@ "name": "icon-tabular-realtime", "id": 3, "code": 921890, - "tempChar": "" + "tempChar": "" }, { "order": 23, @@ -850,7 +858,7 @@ "name": "icon-tabular-scrolling", "id": 18, "code": 921891, - "tempChar": "" + "tempChar": "" }, { "order": 112, @@ -858,7 +866,7 @@ "name": "icon-telemetry", "id": 86, "code": 921892, - "tempChar": "" + "tempChar": "" }, { "order": 90, @@ -866,7 +874,7 @@ "name": "icon-telemetry-panel", "id": 85, "code": 921893, - "tempChar": "" + "tempChar": "" }, { "order": 93, @@ -874,15 +882,15 @@ "name": "icon-timeline", "id": 88, "code": 921894, - "tempChar": "" + "tempChar": "" }, { "order": 116, "id": 101, - "name": "icon-timer-v1.5", + "name": "icon-timer-v15", "prevSize": 24, "code": 921895, - "tempChar": "" + "tempChar": "" }, { "order": 11, @@ -890,7 +898,7 @@ "name": "icon-topic", "id": 6, "code": 921896, - "tempChar": "" + "tempChar": "" }, { "order": 115, @@ -898,7 +906,7 @@ "name": "icon-box-with-dashed-lines", "id": 29, "code": 921897, - "tempChar": "" + "tempChar": "" }, { "order": 126, @@ -906,7 +914,7 @@ "name": "icon-summary-widget", "prevSize": 24, "code": 921904, - "tempChar": "" + "tempChar": "" }, { "order": 139, @@ -914,13 +922,13 @@ "name": "icon-notebook", "prevSize": 24, "code": 921905, - "tempChar": "" + "tempChar": "" } ], "metadata": { "name": "openmct-symbols-16px", "importSize": { - "width": 512, + "width": 745, "height": 512 }, "designer": "Charles Hacskaylo", @@ -2360,7 +2368,7 @@ }, { "paths": [ - "M0 0v256h128v-64h256v704h-192v128h640v-128h-192v-704h256v64h128v-256z" + "M800 1024h224l-384-1024h-256l-384 1024h224l84-224h408zM380 608l132-352 132 352z" ], "grid": 16, "tags": [ @@ -2368,9 +2376,15 @@ ], "defaultCode": 228, "id": 84, - "attrs": [], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, "colorPermutations": { - "1161751207457516161751": [] + "1161751207457516161751": [ + {} + ] } }, { @@ -2840,6 +2854,30 @@ ] } }, + { + "id": 119, + "paths": [ + "M1226.4 320h-176l-76.22 203.24 77 205.34 87.22-232.58 90.74 242h-174.44l49.5 132h174.44l57.76 154h154l-264-704z", + "M384 0l-384 1024h224l84-224h408l84 224h224l-384-1024zM380 608l132-352 132 352z" + ], + "attrs": [ + {}, + {} + ], + "width": 1490, + "isMulticolor": false, + "isMulticolor2": false, + "grid": 16, + "tags": [ + "icon-font-size-alt1" + ], + "colorPermutations": { + "1161751207457516161751": [ + {}, + {} + ] + } + }, { "paths": [ "M576 64h-256l320 320h-290.256c-44.264-76.516-126.99-128-221.744-128h-128v512h128c94.754 0 177.48-51.484 221.744-128h290.256l-320 320h256l448-448-448-448z" @@ -3740,7 +3778,9 @@ "classSelector": ".ui-symbol", "showMetrics": true, "showMetadata": true, - "embed": false + "embed": false, + "noie8": true, + "ie7": false }, "imagePref": { "prefix": "icon-", diff --git a/src/styles-new/fonts/openmct-symbols-16px.svg b/src/styles-new/fonts/openmct-symbols-16px.svg index d8a4b93643..3516e99b82 100755 --- a/src/styles-new/fonts/openmct-symbols-16px.svg +++ b/src/styles-new/fonts/openmct-symbols-16px.svg @@ -71,7 +71,7 @@ - + @@ -88,6 +88,7 @@ + @@ -115,7 +116,7 @@ - + diff --git a/src/styles-new/fonts/openmct-symbols-16px.ttf b/src/styles-new/fonts/openmct-symbols-16px.ttf index 39ee867c06..81c481cafd 100755 Binary files a/src/styles-new/fonts/openmct-symbols-16px.ttf and b/src/styles-new/fonts/openmct-symbols-16px.ttf differ diff --git a/src/styles-new/fonts/openmct-symbols-16px.woff b/src/styles-new/fonts/openmct-symbols-16px.woff index 94a65eb834..a88b1a7b73 100755 Binary files a/src/styles-new/fonts/openmct-symbols-16px.woff and b/src/styles-new/fonts/openmct-symbols-16px.woff differ diff --git a/src/styles/_widgets.scss b/src/styles/_widgets.scss index 82c47ba8c5..aebc97c5c0 100644 --- a/src/styles/_widgets.scss +++ b/src/styles/_widgets.scss @@ -21,6 +21,26 @@ *****************************************************************************/ /************************************************************* WIDGET OBJECT */ +@mixin cSummaryWidget() { + @include boxShdw($shdwBtns); + border-radius: $basicCr; + border-style: solid; + border-width: 1px; + cursor: default; + &[href] { + cursor: pointer; + } + + &__label { + &:before { + // Widget icon + font-size: 0.9em; + margin-right: $interiorMarginSm; + } + } + +} + .l-summary-widget { // Widget layout classes here @include ellipsize(); @@ -33,19 +53,9 @@ } } -.s-summary-widget { - // Widget style classes here - @include boxShdw($shdwBtns); - border-radius: $basicCr; - border-style: solid; - border-width: 1px; - box-sizing: border-box; - cursor: default; - font-size: 0.8rem; +.c-summary-widget { + @include cSummaryWidget(); padding: $interiorMarginLg $interiorMarginLg * 2; - &[href] { - cursor: pointer; - } } .widget-edit-holder { @@ -267,7 +277,6 @@ .widget-thumb { @include ellipsize(); - @extend .s-summary-widget; - @extend .l-summary-widget; + @include cSummaryWidget(); padding: $interiorMarginSm $interiorMargin; } \ No newline at end of file diff --git a/src/ui/components/controls/CreateButton.vue b/src/ui/components/controls/CreateButton.vue index ace398d089..1c306d891b 100644 --- a/src/ui/components/controls/CreateButton.vue +++ b/src/ui/components/controls/CreateButton.vue @@ -31,10 +31,6 @@ .c-create-button, .c-create-menu { - &--w { - // Wrapper for Create button and menu - overflow: visible; - } font-size: 1.1em; } diff --git a/src/ui/components/controls/checkboxCustom.vue b/src/ui/components/controls/checkboxCustom.vue new file mode 100644 index 0000000000..96590d06c6 --- /dev/null +++ b/src/ui/components/controls/checkboxCustom.vue @@ -0,0 +1,168 @@ + + + + + + diff --git a/src/ui/components/controls/labeledNumberInput.vue b/src/ui/components/controls/labeledNumberInput.vue new file mode 100644 index 0000000000..5a13f1115c --- /dev/null +++ b/src/ui/components/controls/labeledNumberInput.vue @@ -0,0 +1,51 @@ + + + diff --git a/src/ui/components/controls/search.vue b/src/ui/components/controls/search.vue index 8ed1c2e9bf..06bcd31147 100644 --- a/src/ui/components/controls/search.vue +++ b/src/ui/components/controls/search.vue @@ -15,45 +15,15 @@ + + \ No newline at end of file diff --git a/src/ui/components/layout/BrowseBar.vue b/src/ui/components/layout/BrowseBar.vue index 1cad073c56..4d100c7741 100644 --- a/src/ui/components/layout/BrowseBar.vue +++ b/src/ui/components/layout/BrowseBar.vue @@ -142,7 +142,6 @@ display: flex; align-items: center; flex: 1 1 auto; - font-size: 1.4em; margin-right: $interiorMargin; min-width: 0; // Forces interior to compress when pushed on } @@ -174,6 +173,7 @@ align-items: center; display: flex; flex: 0 1 auto; + font-size: 1.4em; min-width: 0; &:before { diff --git a/src/ui/components/layout/Layout.vue b/src/ui/components/layout/Layout.vue index 7f3e7db71d..54c94696be 100644 --- a/src/ui/components/layout/Layout.vue +++ b/src/ui/components/layout/Layout.vue @@ -27,10 +27,12 @@
- + + ref="browseBar"> + @@ -162,7 +164,7 @@ margin-right: 2.5%; } - /********** MAIN AREA */ + /******************************* MAIN AREA */ &__main-container { // Wrapper for main views flex: 1 1 auto; @@ -196,6 +198,11 @@ &__pane-inspector { width: 200px; } + + &__toolbar { + flex: 0 0 auto; + margin-bottom: $interiorMargin; + } } } @@ -212,6 +219,7 @@ import multipane from '../controls/multipane.vue'; import pane from '../controls/pane.vue'; import BrowseBar from './BrowseBar.vue'; + import Toolbar from './Toolbar.vue'; var enterFullScreen = () => { var docElm = document.documentElement; @@ -257,7 +265,8 @@ search, multipane, pane, - BrowseBar + BrowseBar, + Toolbar }, mounted() { this.openmct.editor.on('isEditing', (isEditing)=>{ diff --git a/src/ui/components/layout/ObjectView.vue b/src/ui/components/layout/ObjectView.vue index 42dabe423a..2b856272bb 100644 --- a/src/ui/components/layout/ObjectView.vue +++ b/src/ui/components/layout/ObjectView.vue @@ -2,7 +2,7 @@ @@ -33,6 +33,7 @@ export default { this.debounceUpdateView = _.debounce(this.updateView, 10); }, mounted() { + this.currentObject = this.object; this.updateView(); }, methods: { @@ -50,7 +51,7 @@ export default { return; } this.viewContainer = document.createElement('div'); - this.viewContainer.classList.add('l-object-view'); + this.viewContainer.classList.add('c-object-view'); this.$el.append(this.viewContainer); let provider = this.openmct.objectViews.getByProviderKey(this.viewKey); if (!provider) { diff --git a/src/ui/components/layout/Toolbar.vue b/src/ui/components/layout/Toolbar.vue new file mode 100644 index 0000000000..88eb04278a --- /dev/null +++ b/src/ui/components/layout/Toolbar.vue @@ -0,0 +1,291 @@ + + + diff --git a/src/ui/components/layout/mct-tree.vue b/src/ui/components/layout/mct-tree.vue index 8a5bcb9df5..69574021dd 100644 --- a/src/ui/components/layout/mct-tree.vue +++ b/src/ui/components/layout/mct-tree.vue @@ -99,7 +99,7 @@ children: [] }; }, - inject: ['openmct'], + inject: ['openmct', 'domainObject'], mounted: function () { this.openmct.objects.get('ROOT') .then(root => this.openmct.composition.get(root).load()) diff --git a/src/ui/components/layout/tree-item.vue b/src/ui/components/layout/tree-item.vue index d8be127488..8346f63a71 100644 --- a/src/ui/components/layout/tree-item.vue +++ b/src/ui/components/layout/tree-item.vue @@ -8,6 +8,8 @@ @click="toggleChildren">
@@ -89,6 +91,9 @@ .then(() => this.loaded = true); } }, + dragStart($event) { + $event.dataTransfer.setData("domainObject", JSON.stringify(this.node.object)); + } }, components: { viewControl