diff --git a/platform/commonUI/general/src/directives/MCTClickElsewhere.js b/platform/commonUI/general/src/directives/MCTClickElsewhere.js
new file mode 100644
index 0000000000..a6066fc271
--- /dev/null
+++ b/platform/commonUI/general/src/directives/MCTClickElsewhere.js
@@ -0,0 +1,70 @@
+/*****************************************************************************
+ * 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*/
+
+define(
+ [],
+ function () {
+ "use strict";
+
+ function MCTClickElsewhere($document) {
+
+ // Link; install event handlers.
+ function link(scope, element, attrs) {
+ // Keep a reference to the body, to attach/detach
+ // mouse event handlers; mousedown and mouseup cannot
+ // only be attached to the element being linked, as the
+ // mouse may leave this element during the drag.
+ var body = $document.find('body');
+
+ function clickBody(event) {
+ var x = event.clientX,
+ y = event.clientY,
+ rect = element[0].getBoundingClientRect(),
+ xMin = rect.left,
+ xMax = xMin + rect.width,
+ yMin = rect.top,
+ yMax = yMin + rect.height;
+
+ if (x < xMin || x > xMax || y < yMin || y > yMax) {
+ scope.$eval(attrs.mctClickElsewhere);
+ }
+ }
+
+ body.on("mousedown", clickBody);
+ scope.$on("$destroy", function () {
+ body.off("mousedown", clickBody);
+ });
+ }
+
+ return {
+ // mct-drag only makes sense as an attribute
+ restrict: "A",
+ // Link function, to install event handlers
+ link: link
+ };
+ }
+
+ return MCTClickElsewhere;
+ }
+);
+
diff --git a/platform/commonUI/general/src/directives/MCTPopup.js b/platform/commonUI/general/src/directives/MCTPopup.js
new file mode 100644
index 0000000000..0e9f6f1586
--- /dev/null
+++ b/platform/commonUI/general/src/directives/MCTPopup.js
@@ -0,0 +1,69 @@
+/*****************************************************************************
+ * 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*/
+
+define(
+ function () {
+ var TEMPLATE = "
";
+
+ function MCTPopup($window, $document, $compile, $interval) {
+ function link(scope, element, attrs, ctrl, transclude) {
+ var body = $document.find('body'),
+ popup = $compile(TEMPLATE)(scope),
+ winDim = [$window.innerWidth, $window.innerHeight],
+ rect = element[0].getBoundingClientRect(),
+ position = [ rect.left, rect.top ],
+ isLeft = position[0] <= (winDim[0] / 2),
+ isTop = position[1] <= (winDim[1] / 2);
+
+ popup.css('position', 'absolute');
+ popup.css(
+ isLeft ? 'left' : 'right',
+ (isLeft ? position[0] : (winDim[0] - position[0])) + 'px'
+ );
+ popup.css(
+ isTop ? 'top' : 'bottom',
+ (isTop ? position[1] : (winDim[1] - position[1])) + 'px'
+ );
+ body.append(popup);
+
+ transclude(function (clone) {
+ popup.append(clone);
+ });
+
+ scope.$on('$destroy', function () {
+ popup.remove();
+ $interval.cancel(activeInterval);
+ });
+ }
+
+ return {
+ restrict: "E",
+ transclude: true,
+ link: link,
+ scope: {}
+ }
+ }
+
+ return MCTPopup;
+ }
+);