Commit 2ed31262 by Sam Padgett Committed by GitHub

Merge pull request #135 from jeff-phillips-18/modal

Add origin common modal popup component.
parents 49b4c625 8df84483
.origin-modal-popup {
background-color: @color-pf-white;
bottom: 0;
color: @text-color;
left: 0;
position: fixed;
padding: 0 (@grid-gutter-width / 2) (@grid-gutter-width / 2);
right: 0;
top: 0;
z-index: @zindex-modal;
@media (min-width: @screen-sm-min) {
border: 1px solid @dropdown-border;
bottom: auto;
box-shadow: 0 6px 12px rgba(0,0,0,.175);
left: auto;
margin-top: 15px;
right: auto;
top: auto;
&:after {
border: solid 7px transparent;
border-bottom-color: @dropdown-border;
content: "";
position: absolute;
right: (@grid-gutter-width / 4);
top: -15px;
}
&:before {
border: solid 7px transparent;
border-bottom-color: @color-pf-black-150;
content: "";
position: absolute;
right: (@grid-gutter-width / 4);
top: -14px;
z-index: 1;
}
&.position-above {
margin-top: -15px;
&:after {
border-bottom-color:transparent;
border-top-color: @color-pf-white;
bottom: -15px;
top: auto;
}
&:before {
border-bottom-color:transparent;
border-top-color: @color-pf-white;
bottom: -14px;
top: auto;
}
}
&.position-left {
&:after {
left: (@grid-gutter-width / 4);
right: auto;
}
&:before {
left: (@grid-gutter-width / 4);
right: auto;
}
}
}
.origin-modal-popup-close {
color: @color-pf-black-600;
font-size: 14px;
line-height: 1;
position: absolute;
right: (@grid-gutter-width / 2);
top: (@grid-gutter-width / 4) + 1;
&:hover {
color: @color-pf-black-800;
}
}
.origin-modal-popup-title {
background: @color-pf-black-150;
margin-left: -(@grid-gutter-width / 2);
margin-right: -(@grid-gutter-width / 2);
margin-top: 0;
padding: 10px @grid-gutter-width 10px (@grid-gutter-width / 2);
}
}
.origin-modal-popup-backdrop.modal-backdrop {
background-color: transparent;
cursor: not-allowed;
z-index: @zindex-navbar-fixed + 1;
}
......@@ -6,6 +6,7 @@
@import "_forms.less";
@import "_guided-tour.less";
@import "_mixins.less";
@import "_modal-popup.less";
@import "_notifications.less";
@import "_tile-click.less";
@import "_ui-select.less";
......
......@@ -393,6 +393,20 @@ hawtioPluginLoader.addModule('openshiftCommonUI');
);
$templateCache.put('src/components/origin-modal-popup/origin-modal-popup.html',
"<div class=\"origin-modal-popup tile-click-prevent\" ng-if=\"$ctrl.shown\" ng-style=\"$ctrl.positionStyle\"\n" +
" ng-class=\"{'position-above': $ctrl.showAbove, 'position-left': $ctrl.showLeft}\">\n" +
" <h4 class=\"origin-modal-popup-title\">\n" +
" {{$ctrl.modalTitle}}\n" +
" </h4>\n" +
" <div ng-transclude></div>\n" +
" <a href=\"\" class=\"origin-modal-popup-close\" ng-click=\"$ctrl.onClose()\">\n" +
" <span class=\"pficon pficon-close\"></span>\n" +
" </a>\n" +
"</div>\n"
);
$templateCache.put('src/components/toast-notifications/toast-notifications.html',
"<div class=\"toast-notifications-list-pf\">\n" +
" <div ng-repeat=\"(notificationID, notification) in notifications track by (notificationID + (notification.message || notification.details))\" ng-if=\"!notification.hidden || notification.isHover\"\n" +
......@@ -848,6 +862,115 @@ angular.module("openshiftCommonUI")
},
};
});
;"use strict";
angular.module("openshiftCommonUI").component("originModalPopup", {
transclude: true,
bindings: {
modalTitle: '@',
shown: '<',
position: '@', // 'top-left', 'top-right', 'bottom-left', or 'bottom-right' (default is 'bottom-right')
referenceElement: '<?', // Optional reference element, default is parent element. Used to position popup based on screen position
onClose: '<'
},
templateUrl: 'src/components/origin-modal-popup/origin-modal-popup.html',
controller: function($scope, HTMLService, $element, $window) {
var ctrl = this;
var debounceResize;
function updatePosition() {
var positionElement = ctrl.referenceElement || $element[0].parentNode;
if (positionElement && HTMLService.isWindowAboveBreakpoint(HTMLService.WINDOW_SIZE_SM)) {
var posAbove = ctrl.position && ctrl.position.indexOf('top') > -1;
var posLeft = ctrl.position && ctrl.position.indexOf('left') > -1;
var topPos;
var leftPos;
var elementRect = positionElement.getBoundingClientRect();
var windowHeight = $window.innerHeight;
var modalElement = $element[0].children[0];
var modalHeight = _.get(modalElement, 'offsetHeight', 0);
var modalWidth = _.get(modalElement, 'offsetWidth', 0);
// auto-adjust vertical position based on showing in the viewport
if (elementRect.top < modalHeight) {
posAbove = false;
} else if (elementRect.bottom + modalHeight > windowHeight) {
posAbove = true;
}
if (posAbove) {
topPos = (elementRect.top - modalHeight) + 'px';
} else {
topPos = elementRect.bottom + 'px';
}
if (posLeft) {
leftPos = elementRect.left + 'px';
} else {
leftPos = (elementRect.right - modalWidth) + 'px';
}
ctrl.showAbove = posAbove;
ctrl.showLeft = posLeft;
ctrl.positionStyle = {
left: leftPos,
top: topPos
};
} else {
ctrl.positionStyle = {};
}
}
function showModalBackdrop() {
var backdropElement = '<div class="origin-modal-popup-backdrop modal-backdrop fade in tile-click-prevent"></div>';
var parentNode = ctrl.referenceElement ? ctrl.referenceElement.parentNode : $element[0].parentNode;
$(parentNode).append(backdropElement);
}
function hideModalBackdrop() {
$('.origin-modal-popup-backdrop').remove();
}
function onWindowResize() {
$scope.$evalAsync(updatePosition);
}
function onShow() {
showModalBackdrop();
debounceResize = _.debounce(onWindowResize, 50, { maxWait: 250 });
angular.element($window).on('resize', debounceResize);
}
function onHide() {
hideModalBackdrop();
angular.element($window).off('resize', debounceResize);
}
ctrl.$onChanges = function (changeObj) {
if (changeObj.shown) {
if (ctrl.shown) {
onShow();
} else {
onHide();
}
}
if (changeObj.shown || changeObj.referenceElement) {
if (ctrl.shown) {
updatePosition();
}
}
};
ctrl.$onDestroy = function() {
if (ctrl.shown) {
onHide();
}
}
}
});
;'use strict';
// oscUnique is a validation directive
// use:
......
......@@ -272,6 +272,91 @@ div.hopscotch-bubble .hopscotch-nav-button.prev {
word-break: break-word;
overflow-wrap: break-word;
}
.origin-modal-popup {
background-color: #fff;
bottom: 0;
color: #363636;
left: 0;
position: fixed;
padding: 0 20px 20px;
right: 0;
top: 0;
z-index: 1050;
}
@media (min-width: 768px) {
.origin-modal-popup {
border: 1px solid #bbb;
bottom: auto;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
left: auto;
margin-top: 15px;
right: auto;
top: auto;
}
.origin-modal-popup:after {
border: solid 7px transparent;
border-bottom-color: #bbb;
content: "";
position: absolute;
right: 10px;
top: -15px;
}
.origin-modal-popup:before {
border: solid 7px transparent;
border-bottom-color: #f5f5f5;
content: "";
position: absolute;
right: 10px;
top: -14px;
z-index: 1;
}
.origin-modal-popup.position-above {
margin-top: -15px;
}
.origin-modal-popup.position-above:after {
border-bottom-color: transparent;
border-top-color: #fff;
bottom: -15px;
top: auto;
}
.origin-modal-popup.position-above:before {
border-bottom-color: transparent;
border-top-color: #fff;
bottom: -14px;
top: auto;
}
.origin-modal-popup.position-left:after {
left: 10px;
right: auto;
}
.origin-modal-popup.position-left:before {
left: 10px;
right: auto;
}
}
.origin-modal-popup .origin-modal-popup-close {
color: #72767b;
font-size: 14px;
line-height: 1;
position: absolute;
right: 20px;
top: 11px;
}
.origin-modal-popup .origin-modal-popup-close:hover {
color: #393f44;
}
.origin-modal-popup .origin-modal-popup-title {
background: #f5f5f5;
margin-left: -20px;
margin-right: -20px;
margin-top: 0;
padding: 10px 40px 10px 20px;
}
.origin-modal-popup-backdrop.modal-backdrop {
background-color: transparent;
cursor: not-allowed;
z-index: 1031;
}
.toast-action-divider {
color: #9c9c9c;
}
......
......@@ -564,6 +564,20 @@ hawtioPluginLoader.addModule('openshiftCommonUI');
);
$templateCache.put('src/components/origin-modal-popup/origin-modal-popup.html',
"<div class=\"origin-modal-popup tile-click-prevent\" ng-if=\"$ctrl.shown\" ng-style=\"$ctrl.positionStyle\"\n" +
" ng-class=\"{'position-above': $ctrl.showAbove, 'position-left': $ctrl.showLeft}\">\n" +
" <h4 class=\"origin-modal-popup-title\">\n" +
" {{$ctrl.modalTitle}}\n" +
" </h4>\n" +
" <div ng-transclude></div>\n" +
" <a href=\"\" class=\"origin-modal-popup-close\" ng-click=\"$ctrl.onClose()\">\n" +
" <span class=\"pficon pficon-close\"></span>\n" +
" </a>\n" +
"</div>\n"
);
$templateCache.put('src/components/toast-notifications/toast-notifications.html',
"<div class=\"toast-notifications-list-pf\">\n" +
" <div ng-repeat=\"(notificationID, notification) in notifications track by (notificationID + (notification.message || notification.details))\" ng-if=\"!notification.hidden || notification.isHover\"\n" +
......@@ -1019,6 +1033,115 @@ angular.module("openshiftCommonUI")
}],
};
}]);
;"use strict";
angular.module("openshiftCommonUI").component("originModalPopup", {
transclude: true,
bindings: {
modalTitle: '@',
shown: '<',
position: '@', // 'top-left', 'top-right', 'bottom-left', or 'bottom-right' (default is 'bottom-right')
referenceElement: '<?', // Optional reference element, default is parent element. Used to position popup based on screen position
onClose: '<'
},
templateUrl: 'src/components/origin-modal-popup/origin-modal-popup.html',
controller: ["$scope", "HTMLService", "$element", "$window", function($scope, HTMLService, $element, $window) {
var ctrl = this;
var debounceResize;
function updatePosition() {
var positionElement = ctrl.referenceElement || $element[0].parentNode;
if (positionElement && HTMLService.isWindowAboveBreakpoint(HTMLService.WINDOW_SIZE_SM)) {
var posAbove = ctrl.position && ctrl.position.indexOf('top') > -1;
var posLeft = ctrl.position && ctrl.position.indexOf('left') > -1;
var topPos;
var leftPos;
var elementRect = positionElement.getBoundingClientRect();
var windowHeight = $window.innerHeight;
var modalElement = $element[0].children[0];
var modalHeight = _.get(modalElement, 'offsetHeight', 0);
var modalWidth = _.get(modalElement, 'offsetWidth', 0);
// auto-adjust vertical position based on showing in the viewport
if (elementRect.top < modalHeight) {
posAbove = false;
} else if (elementRect.bottom + modalHeight > windowHeight) {
posAbove = true;
}
if (posAbove) {
topPos = (elementRect.top - modalHeight) + 'px';
} else {
topPos = elementRect.bottom + 'px';
}
if (posLeft) {
leftPos = elementRect.left + 'px';
} else {
leftPos = (elementRect.right - modalWidth) + 'px';
}
ctrl.showAbove = posAbove;
ctrl.showLeft = posLeft;
ctrl.positionStyle = {
left: leftPos,
top: topPos
};
} else {
ctrl.positionStyle = {};
}
}
function showModalBackdrop() {
var backdropElement = '<div class="origin-modal-popup-backdrop modal-backdrop fade in tile-click-prevent"></div>';
var parentNode = ctrl.referenceElement ? ctrl.referenceElement.parentNode : $element[0].parentNode;
$(parentNode).append(backdropElement);
}
function hideModalBackdrop() {
$('.origin-modal-popup-backdrop').remove();
}
function onWindowResize() {
$scope.$evalAsync(updatePosition);
}
function onShow() {
showModalBackdrop();
debounceResize = _.debounce(onWindowResize, 50, { maxWait: 250 });
angular.element($window).on('resize', debounceResize);
}
function onHide() {
hideModalBackdrop();
angular.element($window).off('resize', debounceResize);
}
ctrl.$onChanges = function (changeObj) {
if (changeObj.shown) {
if (ctrl.shown) {
onShow();
} else {
onHide();
}
}
if (changeObj.shown || changeObj.referenceElement) {
if (ctrl.shown) {
updatePosition();
}
}
};
ctrl.$onDestroy = function() {
if (ctrl.shown) {
onHide();
}
}
}]
});
;'use strict';
// oscUnique is a validation directive
// use:
......
......@@ -91,7 +91,7 @@ $templateCache.put("src/components/binding/bindServiceForm.html", '<div class="b
$templateCache.put("src/components/create-project/createProject.html", '<form name="createProjectForm" novalidate>\n <fieldset ng-disabled="disableInputs">\n <div class="form-group">\n <label for="name" class="required">Name</label>\n <span ng-class="{\'has-error\': (createProjectForm.name.$error.pattern && createProjectForm.name.$touched) || nameTaken}">\n <input class="form-control input-lg"\n name="name"\n id="name"\n placeholder="my-project"\n type="text"\n required\n take-focus\n minlength="2"\n maxlength="63"\n pattern="[a-z0-9]([-a-z0-9]*[a-z0-9])?"\n aria-describedby="nameHelp"\n ng-model="name"\n ng-model-options="{ updateOn: \'default blur\' }"\n ng-change="nameTaken = false"\n autocorrect="off"\n autocapitalize="off"\n spellcheck="false">\n </span>\n <div>\n <span class="help-block">A unique name for the project.</span>\n </div>\n <div class="has-error">\n <span id="nameHelp" class="help-block" ng-if="createProjectForm.name.$error.required && createProjectForm.name.$dirty">\n Name is required.\n </span>\n </div>\n <div class="has-error">\n <span id="nameHelp" class="help-block" ng-if="createProjectForm.name.$error.minlength && createProjectForm.name.$touched">\n Name must have at least two characters.\n </span>\n </div>\n <div class="has-error">\n <span id="nameHelp" class="help-block" ng-if="createProjectForm.name.$error.pattern && createProjectForm.name.$touched">\n Project names may only contain lower-case letters, numbers, and dashes.\n They may not start or end with a dash.\n </span>\n </div>\n <div class="has-error">\n <span class="help-block" ng-if="nameTaken">\n This name is already in use. Please choose a different name.\n </span>\n </div>\n </div>\n\n <div class="form-group">\n <label for="displayName">Display Name</label>\n <input class="form-control input-lg"\n name="displayName"\n id="displayName"\n placeholder="My Project"\n type="text"\n ng-model="displayName">\n </div>\n\n <div class="form-group">\n <label for="description">Description</label>\n <textarea class="form-control input-lg"\n name="description"\n id="description"\n placeholder="A short description."\n ng-model="description"></textarea>\n </div>\n\n <div class="button-group">\n <button type="submit"\n class="btn btn-primary btn-lg"\n ng-class="{\'dialog-btn\': isDialog}"\n ng-click="createProject()"\n ng-disabled="createProjectForm.$invalid || nameTaken || disableInputs"\n value="">\n Create\n </button>\n <button\n class="btn btn-default btn-lg"\n ng-class="{\'dialog-btn\': isDialog}"\n ng-click="cancelCreateProject()">\n Cancel\n </button>\n </div>\n </fieldset>\n</form>\n'),
$templateCache.put("src/components/delete-project/delete-project-button.html", '<div class="actions">\n <!-- Avoid whitespace inside the link -->\n <a href=""\n ng-click="$event.stopPropagation(); openDeleteModal()"\n role="button"\n class="action-button"\n ng-attr-aria-disabled="{{disableDelete ? \'true\' : undefined}}"\n ng-class="{ \'disabled-link\': disableDelete }"\n ><i class="fa fa-trash-o" aria-hidden="true"\n ></i><span class="sr-only">Delete Project {{projectName}}</span></a>\n</div>\n'), $templateCache.put("src/components/delete-project/delete-project-modal.html", '<div class="delete-resource-modal">\n <!-- Use a form so that the enter key submits when typing a project name to confirm. -->\n <form>\n <div class="modal-body">\n <h1>Are you sure you want to delete the project\n \'<strong>{{displayName ? displayName : projectName}}</strong>\'?</h1>\n <p>\n This will <strong>delete all resources</strong> associated with\n the project {{displayName ? displayName : projectName}} and <strong>cannot be\n undone</strong>. Make sure this is something you really want to do!\n </p>\n <div ng-show="typeNameToConfirm">\n <p>Type the name of the project to confirm.</p>\n <p>\n <label class="sr-only" for="resource-to-delete">project to delete</label>\n <input\n ng-model="confirmName"\n id="resource-to-delete"\n type="text"\n class="form-control input-lg"\n autocorrect="off"\n autocapitalize="off"\n spellcheck="false"\n autofocus>\n </p>\n </div>\n </div>\n <div class="modal-footer">\n <button ng-disabled="typeNameToConfirm && confirmName !== projectName && confirmName !== displayName" class="btn btn-lg btn-danger" type="submit" ng-click="delete();">Delete</button>\n <button class="btn btn-lg btn-default" type="button" ng-click="cancel();">Cancel</button>\n </div>\n </form>\n</div>\n'),
$templateCache.put("src/components/delete-project/delete-project.html", '<a href="javascript:void(0)"\n ng-click="openDeleteModal()"\n role="button"\n ng-attr-aria-disabled="{{disableDelete ? \'true\' : undefined}}"\n ng-class="{ \'disabled-link\': disableDelete }"\n>{{label || \'Delete\'}}</a>\n'), $templateCache.put("src/components/edit-project/editProject.html", '<form name="editProjectForm">\n <fieldset ng-disabled="disableInputs">\n <div class="form-group">\n <label for="displayName">Display Name</label>\n <input class="form-control input-lg"\n name="displayName"\n id="displayName"\n placeholder="My Project"\n type="text"\n ng-model="editableFields.displayName">\n </div>\n\n <div class="form-group">\n <label for="description">Description</label>\n <textarea class="form-control input-lg"\n name="description"\n id="description"\n placeholder="A short description."\n ng-model="editableFields.description"></textarea>\n </div>\n\n <div class="button-group">\n <button type="submit"\n class="btn btn-primary btn-lg"\n ng-class="{\'dialog-btn\': isDialog}"\n ng-click="update()"\n ng-disabled="editProjectForm.$invalid || disableInputs"\n value="">{{submitButtonLabel}}</button>\n <button\n class="btn btn-default btn-lg"\n ng-class="{\'dialog-btn\': isDialog}"\n ng-click="cancelEditProject()">\n Cancel\n </button>\n </div>\n </fieldset>\n</form>\n'),
$templateCache.put("src/components/toast-notifications/toast-notifications.html", '<div class="toast-notifications-list-pf">\n <div ng-repeat="(notificationID, notification) in notifications track by (notificationID + (notification.message || notification.details))" ng-if="!notification.hidden || notification.isHover"\n ng-mouseenter="setHover(notification, true)" ng-mouseleave="setHover(notification, false)">\n <div class="toast-pf alert {{notification.type | alertStatus}}" ng-class="{\'alert-dismissable\': !hideCloseButton}">\n <button ng-if="!hideCloseButton" type="button" class="close" ng-click="close(notification)">\n <span class="pficon pficon-close" aria-hidden="true"></span>\n <span class="sr-only">Close</span>\n </button>\n <span class="{{notification.type | alertIcon}}" aria-hidden="true"></span>\n <span class="sr-only">{{notification.type}}</span>\n <span class="toast-notification-message" ng-if="notification.message">{{notification.message}}</span>\n <div ng-if="notification.details" class="toast-notification-details">\n <truncate-long-text\n limit="200"\n content="notification.details"\n use-word-boundary="true"\n expandable="true"\n hide-collapse="true">\n </truncate-long-text>\n </div>\n <span ng-repeat="link in notification.links">\n <a ng-if="!link.href" href="" ng-click="onClick(notification, link)" role="button">{{link.label}}</a>\n <a ng-if="link.href" ng-href="{{link.href}}" ng-attr-target="{{link.target}}">{{link.label}}</a>\n <span ng-if="!$last" class="toast-action-divider">|</span>\n </span>\n </div>\n </div>\n</div>\n'),
$templateCache.put("src/components/origin-modal-popup/origin-modal-popup.html", '<div class="origin-modal-popup tile-click-prevent" ng-if="$ctrl.shown" ng-style="$ctrl.positionStyle"\n ng-class="{\'position-above\': $ctrl.showAbove, \'position-left\': $ctrl.showLeft}">\n <h4 class="origin-modal-popup-title">\n {{$ctrl.modalTitle}}\n </h4>\n <div ng-transclude></div>\n <a href="" class="origin-modal-popup-close" ng-click="$ctrl.onClose()">\n <span class="pficon pficon-close"></span>\n </a>\n</div>\n'), $templateCache.put("src/components/toast-notifications/toast-notifications.html", '<div class="toast-notifications-list-pf">\n <div ng-repeat="(notificationID, notification) in notifications track by (notificationID + (notification.message || notification.details))" ng-if="!notification.hidden || notification.isHover"\n ng-mouseenter="setHover(notification, true)" ng-mouseleave="setHover(notification, false)">\n <div class="toast-pf alert {{notification.type | alertStatus}}" ng-class="{\'alert-dismissable\': !hideCloseButton}">\n <button ng-if="!hideCloseButton" type="button" class="close" ng-click="close(notification)">\n <span class="pficon pficon-close" aria-hidden="true"></span>\n <span class="sr-only">Close</span>\n </button>\n <span class="{{notification.type | alertIcon}}" aria-hidden="true"></span>\n <span class="sr-only">{{notification.type}}</span>\n <span class="toast-notification-message" ng-if="notification.message">{{notification.message}}</span>\n <div ng-if="notification.details" class="toast-notification-details">\n <truncate-long-text\n limit="200"\n content="notification.details"\n use-word-boundary="true"\n expandable="true"\n hide-collapse="true">\n </truncate-long-text>\n </div>\n <span ng-repeat="link in notification.links">\n <a ng-if="!link.href" href="" ng-click="onClick(notification, link)" role="button">{{link.label}}</a>\n <a ng-if="link.href" ng-href="{{link.href}}" ng-attr-target="{{link.target}}">{{link.label}}</a>\n <span ng-if="!$last" class="toast-action-divider">|</span>\n </span>\n </div>\n </div>\n</div>\n'),
$templateCache.put("src/components/truncate-long-text/truncateLongText.html", '<!--\n Do not remove class `truncated-content` (here or below) even though it\'s not\n styled directly in origin-web-common. `truncated-content` is used by\n origin-web-console in certain contexts.\n-->\n<span ng-if="!truncated" ng-bind-html="content | highlightKeywords : keywords" class="truncated-content"></span>\n<span ng-if="truncated">\n <span ng-if="!toggles.expanded">\n <span ng-attr-title="{{content}}" class="truncation-block">\n <span ng-bind-html="truncatedContent | highlightKeywords : keywords" class="truncated-content"></span>&hellip;\n </span>\n <a ng-if="expandable" href="" ng-click="toggles.expanded = true" class="nowrap">See All</a>\n </span>\n <span ng-if="toggles.expanded">\n <div ng-if="prettifyJson" class="well">\n <span ng-if="!hideCollapse" class="pull-right" style="margin-top: -10px;"><a href="" ng-click="toggles.expanded = false" class="truncation-collapse-link">Collapse</a></span>\n <span ng-bind-html="content | prettifyJSON | highlightKeywords : keywords" class="pretty-json truncated-content"></span>\n </div>\n <span ng-if="!prettifyJson">\n <span ng-if="!hideCollapse" class="pull-right"><a href="" ng-click="toggles.expanded = false" class="truncation-collapse-link">Collapse</a></span>\n <span ng-bind-html="content | highlightKeywords : keywords" class="truncated-content"></span>\n </span>\n </span>\n</span>\n');
} ]), angular.module("openshiftCommonUI").component("bindApplicationForm", {
controllerAs:"ctrl",
......@@ -325,7 +325,53 @@ cb ? cb() :$window.history.back();
};
} ]
};
} ]), angular.module("openshiftCommonUI").directive("oscUnique", function() {
} ]), angular.module("openshiftCommonUI").component("originModalPopup", {
transclude:!0,
bindings:{
modalTitle:"@",
shown:"<",
position:"@",
referenceElement:"<?",
onClose:"<"
},
templateUrl:"src/components/origin-modal-popup/origin-modal-popup.html",
controller:[ "$scope", "HTMLService", "$element", "$window", function($scope, HTMLService, $element, $window) {
function updatePosition() {
var positionElement = ctrl.referenceElement || $element[0].parentNode;
if (positionElement && HTMLService.isWindowAboveBreakpoint(HTMLService.WINDOW_SIZE_SM)) {
var topPos, leftPos, posAbove = ctrl.position && ctrl.position.indexOf("top") > -1, posLeft = ctrl.position && ctrl.position.indexOf("left") > -1, elementRect = positionElement.getBoundingClientRect(), windowHeight = $window.innerHeight, modalElement = $element[0].children[0], modalHeight = _.get(modalElement, "offsetHeight", 0), modalWidth = _.get(modalElement, "offsetWidth", 0);
elementRect.top < modalHeight ? posAbove = !1 :elementRect.bottom + modalHeight > windowHeight && (posAbove = !0), topPos = posAbove ? elementRect.top - modalHeight + "px" :elementRect.bottom + "px", leftPos = posLeft ? elementRect.left + "px" :elementRect.right - modalWidth + "px", ctrl.showAbove = posAbove, ctrl.showLeft = posLeft, ctrl.positionStyle = {
left:leftPos,
top:topPos
};
} else ctrl.positionStyle = {};
}
function showModalBackdrop() {
var backdropElement = '<div class="origin-modal-popup-backdrop modal-backdrop fade in tile-click-prevent"></div>', parentNode = ctrl.referenceElement ? ctrl.referenceElement.parentNode :$element[0].parentNode;
$(parentNode).append(backdropElement);
}
function hideModalBackdrop() {
$(".origin-modal-popup-backdrop").remove();
}
function onWindowResize() {
$scope.$evalAsync(updatePosition);
}
function onShow() {
showModalBackdrop(), debounceResize = _.debounce(onWindowResize, 50, {
maxWait:250
}), angular.element($window).on("resize", debounceResize);
}
function onHide() {
hideModalBackdrop(), angular.element($window).off("resize", debounceResize);
}
var debounceResize, ctrl = this;
ctrl.$onChanges = function(changeObj) {
changeObj.shown && (ctrl.shown ? onShow() :onHide()), (changeObj.shown || changeObj.referenceElement) && ctrl.shown && updatePosition();
}, ctrl.$onDestroy = function() {
ctrl.shown && onHide();
};
} ]
}), angular.module("openshiftCommonUI").directive("oscUnique", function() {
return {
restrict:"A",
scope:{
......
......@@ -364,6 +364,20 @@ angular.module('openshiftCommonUI').run(['$templateCache', function($templateCac
);
$templateCache.put('src/components/origin-modal-popup/origin-modal-popup.html',
"<div class=\"origin-modal-popup tile-click-prevent\" ng-if=\"$ctrl.shown\" ng-style=\"$ctrl.positionStyle\"\n" +
" ng-class=\"{'position-above': $ctrl.showAbove, 'position-left': $ctrl.showLeft}\">\n" +
" <h4 class=\"origin-modal-popup-title\">\n" +
" {{$ctrl.modalTitle}}\n" +
" </h4>\n" +
" <div ng-transclude></div>\n" +
" <a href=\"\" class=\"origin-modal-popup-close\" ng-click=\"$ctrl.onClose()\">\n" +
" <span class=\"pficon pficon-close\"></span>\n" +
" </a>\n" +
"</div>\n"
);
$templateCache.put('src/components/toast-notifications/toast-notifications.html',
"<div class=\"toast-notifications-list-pf\">\n" +
" <div ng-repeat=\"(notificationID, notification) in notifications track by (notificationID + (notification.message || notification.details))\" ng-if=\"!notification.hidden || notification.isHover\"\n" +
......
<div class="origin-modal-popup tile-click-prevent" ng-if="$ctrl.shown" ng-style="$ctrl.positionStyle"
ng-class="{'position-above': $ctrl.showAbove, 'position-left': $ctrl.showLeft}">
<h4 class="origin-modal-popup-title">
{{$ctrl.modalTitle}}
</h4>
<div ng-transclude></div>
<a href="" class="origin-modal-popup-close" ng-click="$ctrl.onClose()">
<span class="pficon pficon-close"></span>
</a>
</div>
"use strict";
angular.module("openshiftCommonUI").component("originModalPopup", {
transclude: true,
bindings: {
modalTitle: '@',
shown: '<',
position: '@', // 'top-left', 'top-right', 'bottom-left', or 'bottom-right' (default is 'bottom-right')
referenceElement: '<?', // Optional reference element, default is parent element. Used to position popup based on screen position
onClose: '<'
},
templateUrl: 'src/components/origin-modal-popup/origin-modal-popup.html',
controller: function($scope, HTMLService, $element, $window) {
var ctrl = this;
var debounceResize;
function updatePosition() {
var positionElement = ctrl.referenceElement || $element[0].parentNode;
if (positionElement && HTMLService.isWindowAboveBreakpoint(HTMLService.WINDOW_SIZE_SM)) {
var posAbove = ctrl.position && ctrl.position.indexOf('top') > -1;
var posLeft = ctrl.position && ctrl.position.indexOf('left') > -1;
var topPos;
var leftPos;
var elementRect = positionElement.getBoundingClientRect();
var windowHeight = $window.innerHeight;
var modalElement = $element[0].children[0];
var modalHeight = _.get(modalElement, 'offsetHeight', 0);
var modalWidth = _.get(modalElement, 'offsetWidth', 0);
// auto-adjust vertical position based on showing in the viewport
if (elementRect.top < modalHeight) {
posAbove = false;
} else if (elementRect.bottom + modalHeight > windowHeight) {
posAbove = true;
}
if (posAbove) {
topPos = (elementRect.top - modalHeight) + 'px';
} else {
topPos = elementRect.bottom + 'px';
}
if (posLeft) {
leftPos = elementRect.left + 'px';
} else {
leftPos = (elementRect.right - modalWidth) + 'px';
}
ctrl.showAbove = posAbove;
ctrl.showLeft = posLeft;
ctrl.positionStyle = {
left: leftPos,
top: topPos
};
} else {
ctrl.positionStyle = {};
}
}
function showModalBackdrop() {
var backdropElement = '<div class="origin-modal-popup-backdrop modal-backdrop fade in tile-click-prevent"></div>';
var parentNode = ctrl.referenceElement ? ctrl.referenceElement.parentNode : $element[0].parentNode;
$(parentNode).append(backdropElement);
}
function hideModalBackdrop() {
$('.origin-modal-popup-backdrop').remove();
}
function onWindowResize() {
$scope.$evalAsync(updatePosition);
}
function onShow() {
showModalBackdrop();
debounceResize = _.debounce(onWindowResize, 50, { maxWait: 250 });
angular.element($window).on('resize', debounceResize);
}
function onHide() {
hideModalBackdrop();
angular.element($window).off('resize', debounceResize);
}
ctrl.$onChanges = function (changeObj) {
if (changeObj.shown) {
if (ctrl.shown) {
onShow();
} else {
onHide();
}
}
if (changeObj.shown || changeObj.referenceElement) {
if (ctrl.shown) {
updatePosition();
}
}
};
ctrl.$onDestroy = function() {
if (ctrl.shown) {
onHide();
}
}
}
});
.origin-modal-popup {
background-color: @color-pf-white;
bottom: 0;
color: @text-color;
left: 0;
position: fixed;
padding: 0 (@grid-gutter-width / 2) (@grid-gutter-width / 2);
right: 0;
top: 0;
z-index: @zindex-modal;
@media (min-width: @screen-sm-min) {
border: 1px solid @dropdown-border;
bottom: auto;
box-shadow: 0 6px 12px rgba(0,0,0,.175);
left: auto;
margin-top: 15px;
right: auto;
top: auto;
&:after {
border: solid 7px transparent;
border-bottom-color: @dropdown-border;
content: "";
position: absolute;
right: (@grid-gutter-width / 4);
top: -15px;
}
&:before {
border: solid 7px transparent;
border-bottom-color: @color-pf-black-150;
content: "";
position: absolute;
right: (@grid-gutter-width / 4);
top: -14px;
z-index: 1;
}
&.position-above {
margin-top: -15px;
&:after {
border-bottom-color:transparent;
border-top-color: @color-pf-white;
bottom: -15px;
top: auto;
}
&:before {
border-bottom-color:transparent;
border-top-color: @color-pf-white;
bottom: -14px;
top: auto;
}
}
&.position-left {
&:after {
left: (@grid-gutter-width / 4);
right: auto;
}
&:before {
left: (@grid-gutter-width / 4);
right: auto;
}
}
}
.origin-modal-popup-close {
color: @color-pf-black-600;
font-size: 14px;
line-height: 1;
position: absolute;
right: (@grid-gutter-width / 2);
top: (@grid-gutter-width / 4) + 1;
&:hover {
color: @color-pf-black-800;
}
}
.origin-modal-popup-title {
background: @color-pf-black-150;
margin-left: -(@grid-gutter-width / 2);
margin-right: -(@grid-gutter-width / 2);
margin-top: 0;
padding: 10px @grid-gutter-width 10px (@grid-gutter-width / 2);
}
}
.origin-modal-popup-backdrop.modal-backdrop {
background-color: transparent;
cursor: not-allowed;
z-index: @zindex-navbar-fixed + 1;
}
......@@ -6,6 +6,7 @@
@import "_forms.less";
@import "_guided-tour.less";
@import "_mixins.less";
@import "_modal-popup.less";
@import "_notifications.less";
@import "_tile-click.less";
@import "_ui-select.less";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment