diff --git a/platform/commonUI/browse/bundle.json b/platform/commonUI/browse/bundle.json index 08b8dd08c8..b7b8b29807 100644 --- a/platform/commonUI/browse/bundle.json +++ b/platform/commonUI/browse/bundle.json @@ -16,7 +16,7 @@ { "key": "BrowseController", "implementation": "BrowseController.js", - "depends": [ "$scope", "$route", "$location", "objectService", "navigationService" ] + "depends": [ "$scope", "$route", "$location", "objectService", "navigationService", "urlService"] }, { "key": "BrowseObjectController", @@ -78,11 +78,16 @@ "key": "navigationService", "implementation": "navigation/NavigationService.js" }, + { + "key": "urlService", + "implementation": "services/UrlService.js", + "depends": [ "$location" ] + }, { "key": "creationService", "implementation": "creation/CreationService.js", "depends": [ "persistenceService", "$q", "$log" ] - } + } ], "actions": [ { @@ -92,10 +97,11 @@ }, { "key": "window", - "implementation": "windowing/NewWindowAction.js", - "description": "Open this object in a new window", - "category": "view-control", - "depends": [ "$window" ], + "name": "Open in a new tab", + "implementation": "windowing/NewTabAction.js", + "description": "Open this object in a new tab", + "category": ["view-control", "contextual"], + "depends": [ "urlService", "$window" ], "group": "windowing", "glyph": "y" }, diff --git a/platform/commonUI/browse/src/BrowseController.js b/platform/commonUI/browse/src/BrowseController.js index 241c39bb47..50f1da936c 100644 --- a/platform/commonUI/browse/src/BrowseController.js +++ b/platform/commonUI/browse/src/BrowseController.js @@ -41,19 +41,13 @@ define( * * @constructor */ - function BrowseController($scope, $route, $location, objectService, navigationService) { + function BrowseController($scope, $route, $location, objectService, navigationService, urlService) { var path = [ROOT_ID].concat( ($route.current.params.ids || DEFAULT_PATH).split("/") ); function updateRoute(domainObject) { - var context = domainObject && - domainObject.getCapability('context'), - objectPath = context ? context.getPath() : [], - ids = objectPath.map(function (domainObject) { - return domainObject.getId(); - }), - priorRoute = $route.current, + var priorRoute = $route.current, // Act as if params HADN'T changed to avoid page reload unlisten; @@ -61,8 +55,10 @@ define( $route.current = priorRoute; unlisten(); }); - - $location.path("/browse/" + ids.slice(1).join("/")); + // urlService.urlFor used to adjust current + // path to new, addressed, path based on + // domainObject + $location.path(urlService.urlFor("browse", domainObject)); } // Callback for updating the in-scope reference to the object diff --git a/platform/commonUI/browse/src/services/UrlService.js b/platform/commonUI/browse/src/services/UrlService.js new file mode 100644 index 0000000000..e8b05c27be --- /dev/null +++ b/platform/commonUI/browse/src/services/UrlService.js @@ -0,0 +1,75 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2014-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,Promise*/ + +/** + * Module defining UrlService. + */ +define( + [], + function () { + "use strict"; + + /** + * The url service handles calls for url paths + * using domain objects. + */ + function UrlService($location) { + // Returns the url for the mode wanted + // and the domainObject passed in. A path + // is returned. The view is defaulted to + // the current location's (current object's) + // view set. + function urlFor(mode, domainObject) { + var context = domainObject && + domainObject.getCapability('context'), + objectPath = context ? context.getPath() : [], + ids = objectPath.map(function (domainObject) { + return domainObject.getId(); + }), + viewPath = "?view=" + $location.search().view, + // Parses the path together. Starts with the + // default index.html file, then the mode passed + // into the service, followed by ids in the url + // joined by '/', and lastly the view path from + // the current location + path = "index.html#/" + mode + "/" + + ids.slice(1).join("/") + viewPath; + + return path; + } + + return { + /** + * Returns the Url path for a specific domain object + * @param {value} value of the browse or edit mode + * for the path + * @param {DomainObject} value of the domain object + * to get the path of + */ + urlFor: urlFor + }; + } + + return UrlService; + } +); \ No newline at end of file diff --git a/platform/commonUI/browse/src/windowing/NewWindowAction.js b/platform/commonUI/browse/src/windowing/NewTabAction.js similarity index 53% rename from platform/commonUI/browse/src/windowing/NewWindowAction.js rename to platform/commonUI/browse/src/windowing/NewTabAction.js index 8b7c0751b5..2437cff41f 100644 --- a/platform/commonUI/browse/src/windowing/NewWindowAction.js +++ b/platform/commonUI/browse/src/windowing/NewTabAction.js @@ -22,31 +22,46 @@ /*global define,Promise*/ /** - * Module defining NewWindowAction. Created by vwoeltje on 11/18/14. + * Module defining NewTabAction (Originally NewWindowAction). Created by vwoeltje on 11/18/14. */ define( [], function () { "use strict"; - + var ROOT_ID = "ROOT", + DEFAULT_PATH = "/mine"; /** - * The new window action allows a domain object to be opened - * into a new browser window. (Currently this is a stub, present - * to allow the control to appear in the appropriate location in - * the user interface.) + * The new tab action allows a domain object to be opened + * into a new browser tab. * @constructor */ - function NewWindowAction($window) { + function NewTabAction(urlService, $window, context) { + // Returns the selected domain object + // when using the context menu or the top right button + // based on the context and the existance of the object + // It is set to object an returned + function getSelectedObject() { + var object; + if (context.selectedObject) { + object = context.selectedObject; + } else { + object = context.domainObject; + } + return object; + } + return { - /** - * Open the object in a new window (currently a stub) - */ + // Performs the open in new tab function + // By calling the url service, the mode needed + // (browse) and the domainObject is passed in and + // the path is returned and opened in a new tab perform: function () { - $window.alert("Not yet functional. This will open objects in a new window."); + $window.open(urlService.urlFor("browse", getSelectedObject()), + "_blank"); } }; } - return NewWindowAction; + return NewTabAction; } ); \ No newline at end of file diff --git a/platform/commonUI/browse/test/BrowseControllerSpec.js b/platform/commonUI/browse/test/BrowseControllerSpec.js index 335e2f94eb..3a14589131 100644 --- a/platform/commonUI/browse/test/BrowseControllerSpec.js +++ b/platform/commonUI/browse/test/BrowseControllerSpec.js @@ -36,6 +36,7 @@ define( mockObjectService, mockNavigationService, mockRootObject, + mockUrlService, mockDomainObject, mockNextObject, controller; @@ -58,6 +59,10 @@ define( "$location", [ "path" ] ); + mockUrlService = jasmine.createSpyObj( + "urlService", + ["urlFor"] + ); mockObjectService = jasmine.createSpyObj( "objectService", [ "getObjects" ] @@ -102,7 +107,8 @@ define( mockRoute, mockLocation, mockObjectService, - mockNavigationService + mockNavigationService, + mockUrlService ); }); @@ -112,7 +118,8 @@ define( mockRoute, mockLocation, mockObjectService, - mockNavigationService + mockNavigationService, + mockUrlService ); expect(mockNavigationService.setNavigation) .toHaveBeenCalledWith(mockDomainObject); @@ -125,7 +132,8 @@ define( mockRoute, mockLocation, mockObjectService, - mockNavigationService + mockNavigationService, + mockUrlService ); expect(mockScope.navigatedObject).toBe(mockDomainObject); }); @@ -200,7 +208,8 @@ define( it("updates the displayed route to reflect current navigation", function () { var mockContext = jasmine.createSpyObj('context', ['getPath']), - mockUnlisten = jasmine.createSpy('unlisten'); + mockUnlisten = jasmine.createSpy('unlisten'), + mockMode = "browse"; mockContext.getPath.andReturn( [mockRootObject, mockDomainObject, mockNextObject] @@ -213,7 +222,11 @@ define( mockNavigationService.addListener.mostRecentCall.args[0]( mockNextObject ); - expect(mockLocation.path).toHaveBeenCalledWith("/browse/mine/next"); + // location.path to be called with the urlService's + // urlFor function with the next domainObject and mode + expect(mockLocation.path).toHaveBeenCalledWith( + mockUrlService.urlFor(mockMode, mockNextObject) + ); // Exercise the Angular workaround mockScope.$on.mostRecentCall.args[1](); diff --git a/platform/commonUI/browse/test/services/UrlServiceSpec.js b/platform/commonUI/browse/test/services/UrlServiceSpec.js new file mode 100644 index 0000000000..757a09fab0 --- /dev/null +++ b/platform/commonUI/browse/test/services/UrlServiceSpec.js @@ -0,0 +1,88 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2014-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/ + +/** + * MCTRepresentationSpec. Created by vwoeltje on 11/6/14. + */ +define( + ["../../src/services/UrlService"], + function (UrlService) { + "use strict"; + + describe("The url service", function () { + var urlService, + mockLocation; + + beforeEach(function () { + // Creates a mockLocation, used to + // do the view search + mockLocation = jasmine.createSpyObj( + "$location", + [ "path", "search" ] + ); + + urlService = new UrlService(mockLocation); + }); + + it("get url for a domainObject and mode", function () { + // The mockDomainObject is initialized as a + // spy object to ultimately be passed into the + // urlService urlFor function + var mockDomainObject = jasmine.createSpyObj( + "domainObject", + [ "getId", "getCapability", "getModel", "useCapability" ] + ), + mockContext = jasmine.createSpyObj('context', ['getPath']), + testViews = [ + { key: 'abc' }, + { key: 'def', someKey: 'some value' }, + { key: 'xyz' } + ], + mockMode = "browse"; + + // The mockContext is set a path + // for the mockDomainObject + mockContext.getPath.andReturn( + [mockDomainObject] + ); + + // view capability used with the testviews made + mockDomainObject.useCapability.andCallFake(function (c) { + return (c === 'view') && testViews; + }); + + // context capability used with the mockContext created + // so the variables including context in the urlFor are + // initialized and reached + mockDomainObject.getCapability.andCallFake(function (c) { + return c === 'context' && mockContext; + }); + + // Uses the mockLocation to get the current + // "mock" website's view + mockLocation.search.andReturn({ view: 'def' }); + urlService.urlFor(mockMode, mockDomainObject); + }); + }); + } +); \ No newline at end of file diff --git a/platform/commonUI/browse/test/suite.json b/platform/commonUI/browse/test/suite.json index e36f345caa..810b75d673 100644 --- a/platform/commonUI/browse/test/suite.json +++ b/platform/commonUI/browse/test/suite.json @@ -9,6 +9,8 @@ "creation/LocatorController", "navigation/NavigateAction", "navigation/NavigationService", + "services/UrlService", "windowing/FullscreenAction", + "windowing/NewTabAction", "windowing/WindowTitler" ] diff --git a/platform/commonUI/browse/test/windowing/NewTabActionSpec.js b/platform/commonUI/browse/test/windowing/NewTabActionSpec.js new file mode 100644 index 0000000000..8955727e19 --- /dev/null +++ b/platform/commonUI/browse/test/windowing/NewTabActionSpec.js @@ -0,0 +1,78 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2014-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web 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 Web 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. + *****************************************************************************/ +/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine,afterEach,window*/ + +define( + ["../../src/windowing/NewTabAction"], + function (NewTabAction) { + "use strict"; + + describe("The new tab action", function () { + var actionSelected, + actionCurrent, + mockWindow, + mockDomainObject, + mockContextCurrent, + mockContextSelected, + mockUrlService; + + beforeEach(function () { + mockWindow = jasmine.createSpyObj("$window", ["open", "location"]); + + // Context if the current object is selected + // For example, when the top right new tab + // button is clicked, the user is using the + // current domainObject + mockContextCurrent = jasmine.createSpyObj("context", ["domainObject"]); + + // Context if the selected object is selected + // For example, when an object in the left + // tree is opened in a new tab using the + // context menu + mockContextSelected = jasmine.createSpyObj("context", ["selectedObject", + "domainObject"]); + + // Mocks the urlService used to make the new tab's url from a + // domainObject and mode + mockUrlService = jasmine.createSpyObj("urlService", ["urlFor"]); + + // Action done using the current context or mockContextCurrent + actionCurrent = new NewTabAction(mockUrlService, mockWindow, + mockContextCurrent); + + // Action done using the selected context or mockContextSelected + actionSelected = new NewTabAction(mockUrlService, mockWindow, + mockContextSelected); + + }); + + it("new tab with current url is opened", function () { + actionCurrent.perform(); + }); + + it("new tab with a selected url is opened", function () { + actionSelected.perform(); + }); + + }); + } +); \ No newline at end of file diff --git a/platform/commonUI/general/res/css/theme-espresso.css b/platform/commonUI/general/res/css/theme-espresso.css index 142493dfd2..246b68c178 100644 --- a/platform/commonUI/general/res/css/theme-espresso.css +++ b/platform/commonUI/general/res/css/theme-espresso.css @@ -4857,6 +4857,3 @@ input[type="text"] { /* line 32, ../sass/_hide-non-functional.scss */ .browse-mode .browse-area.holder { top: 5px; } - /* line 39, ../sass/_hide-non-functional.scss */ - .browse-mode .browse-area.holder > .contents.split-layout .object-browse-bar .btn.key-window { - display: none; } diff --git a/platform/commonUI/general/res/sass/_hide-non-functional.scss b/platform/commonUI/general/res/sass/_hide-non-functional.scss index 1f029674c9..ccc752a9bb 100644 --- a/platform/commonUI/general/res/sass/_hide-non-functional.scss +++ b/platform/commonUI/general/res/sass/_hide-non-functional.scss @@ -38,7 +38,7 @@ .object-browse-bar { .btn.key-window { // Hide the Open in New Window button - display: none; +// display: none; } } }