Skip to content

Commit 8df8448

Browse files
Add origin common modal popup component.
1 parent 49b4c62 commit 8df8448

File tree

11 files changed

+704
-2
lines changed

11 files changed

+704
-2
lines changed

dist/less/_modal-popup.less

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
.origin-modal-popup {
2+
background-color: @color-pf-white;
3+
bottom: 0;
4+
color: @text-color;
5+
left: 0;
6+
position: fixed;
7+
padding: 0 (@grid-gutter-width / 2) (@grid-gutter-width / 2);
8+
right: 0;
9+
top: 0;
10+
z-index: @zindex-modal;
11+
12+
@media (min-width: @screen-sm-min) {
13+
border: 1px solid @dropdown-border;
14+
bottom: auto;
15+
box-shadow: 0 6px 12px rgba(0,0,0,.175);
16+
left: auto;
17+
margin-top: 15px;
18+
right: auto;
19+
top: auto;
20+
21+
&:after {
22+
border: solid 7px transparent;
23+
border-bottom-color: @dropdown-border;
24+
content: "";
25+
position: absolute;
26+
right: (@grid-gutter-width / 4);
27+
top: -15px;
28+
}
29+
30+
&:before {
31+
border: solid 7px transparent;
32+
border-bottom-color: @color-pf-black-150;
33+
content: "";
34+
position: absolute;
35+
right: (@grid-gutter-width / 4);
36+
top: -14px;
37+
z-index: 1;
38+
}
39+
40+
&.position-above {
41+
margin-top: -15px;
42+
&:after {
43+
border-bottom-color:transparent;
44+
border-top-color: @color-pf-white;
45+
bottom: -15px;
46+
top: auto;
47+
}
48+
49+
&:before {
50+
border-bottom-color:transparent;
51+
border-top-color: @color-pf-white;
52+
bottom: -14px;
53+
top: auto;
54+
}
55+
}
56+
&.position-left {
57+
&:after {
58+
left: (@grid-gutter-width / 4);
59+
right: auto;
60+
}
61+
62+
&:before {
63+
left: (@grid-gutter-width / 4);
64+
right: auto;
65+
}
66+
}
67+
}
68+
69+
.origin-modal-popup-close {
70+
color: @color-pf-black-600;
71+
font-size: 14px;
72+
line-height: 1;
73+
position: absolute;
74+
right: (@grid-gutter-width / 2);
75+
top: (@grid-gutter-width / 4) + 1;
76+
77+
&:hover {
78+
color: @color-pf-black-800;
79+
}
80+
}
81+
82+
.origin-modal-popup-title {
83+
background: @color-pf-black-150;
84+
margin-left: -(@grid-gutter-width / 2);
85+
margin-right: -(@grid-gutter-width / 2);
86+
margin-top: 0;
87+
padding: 10px @grid-gutter-width 10px (@grid-gutter-width / 2);
88+
}
89+
}
90+
91+
.origin-modal-popup-backdrop.modal-backdrop {
92+
background-color: transparent;
93+
cursor: not-allowed;
94+
z-index: @zindex-navbar-fixed + 1;
95+
}

dist/less/common.less

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
@import "_forms.less";
77
@import "_guided-tour.less";
88
@import "_mixins.less";
9+
@import "_modal-popup.less";
910
@import "_notifications.less";
1011
@import "_tile-click.less";
1112
@import "_ui-select.less";

dist/origin-web-common-ui.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,20 @@ hawtioPluginLoader.addModule('openshiftCommonUI');
393393
);
394394

395395

396+
$templateCache.put('src/components/origin-modal-popup/origin-modal-popup.html',
397+
"<div class=\"origin-modal-popup tile-click-prevent\" ng-if=\"$ctrl.shown\" ng-style=\"$ctrl.positionStyle\"\n" +
398+
" ng-class=\"{'position-above': $ctrl.showAbove, 'position-left': $ctrl.showLeft}\">\n" +
399+
" <h4 class=\"origin-modal-popup-title\">\n" +
400+
" {{$ctrl.modalTitle}}\n" +
401+
" </h4>\n" +
402+
" <div ng-transclude></div>\n" +
403+
" <a href=\"\" class=\"origin-modal-popup-close\" ng-click=\"$ctrl.onClose()\">\n" +
404+
" <span class=\"pficon pficon-close\"></span>\n" +
405+
" </a>\n" +
406+
"</div>\n"
407+
);
408+
409+
396410
$templateCache.put('src/components/toast-notifications/toast-notifications.html',
397411
"<div class=\"toast-notifications-list-pf\">\n" +
398412
" <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")
848862
},
849863
};
850864
});
865+
;"use strict";
866+
867+
angular.module("openshiftCommonUI").component("originModalPopup", {
868+
transclude: true,
869+
bindings: {
870+
modalTitle: '@',
871+
shown: '<',
872+
position: '@', // 'top-left', 'top-right', 'bottom-left', or 'bottom-right' (default is 'bottom-right')
873+
referenceElement: '<?', // Optional reference element, default is parent element. Used to position popup based on screen position
874+
onClose: '<'
875+
},
876+
templateUrl: 'src/components/origin-modal-popup/origin-modal-popup.html',
877+
controller: function($scope, HTMLService, $element, $window) {
878+
var ctrl = this;
879+
var debounceResize;
880+
881+
function updatePosition() {
882+
var positionElement = ctrl.referenceElement || $element[0].parentNode;
883+
884+
if (positionElement && HTMLService.isWindowAboveBreakpoint(HTMLService.WINDOW_SIZE_SM)) {
885+
var posAbove = ctrl.position && ctrl.position.indexOf('top') > -1;
886+
var posLeft = ctrl.position && ctrl.position.indexOf('left') > -1;
887+
var topPos;
888+
var leftPos;
889+
var elementRect = positionElement.getBoundingClientRect();
890+
var windowHeight = $window.innerHeight;
891+
var modalElement = $element[0].children[0];
892+
var modalHeight = _.get(modalElement, 'offsetHeight', 0);
893+
var modalWidth = _.get(modalElement, 'offsetWidth', 0);
894+
895+
// auto-adjust vertical position based on showing in the viewport
896+
if (elementRect.top < modalHeight) {
897+
posAbove = false;
898+
} else if (elementRect.bottom + modalHeight > windowHeight) {
899+
posAbove = true;
900+
}
901+
902+
if (posAbove) {
903+
topPos = (elementRect.top - modalHeight) + 'px';
904+
} else {
905+
topPos = elementRect.bottom + 'px';
906+
}
907+
908+
if (posLeft) {
909+
leftPos = elementRect.left + 'px';
910+
} else {
911+
leftPos = (elementRect.right - modalWidth) + 'px';
912+
}
913+
914+
ctrl.showAbove = posAbove;
915+
ctrl.showLeft = posLeft;
916+
917+
ctrl.positionStyle = {
918+
left: leftPos,
919+
top: topPos
920+
};
921+
} else {
922+
ctrl.positionStyle = {};
923+
}
924+
}
925+
926+
function showModalBackdrop() {
927+
var backdropElement = '<div class="origin-modal-popup-backdrop modal-backdrop fade in tile-click-prevent"></div>';
928+
var parentNode = ctrl.referenceElement ? ctrl.referenceElement.parentNode : $element[0].parentNode;
929+
$(parentNode).append(backdropElement);
930+
}
931+
932+
function hideModalBackdrop() {
933+
$('.origin-modal-popup-backdrop').remove();
934+
}
935+
936+
function onWindowResize() {
937+
$scope.$evalAsync(updatePosition);
938+
}
939+
940+
function onShow() {
941+
showModalBackdrop();
942+
debounceResize = _.debounce(onWindowResize, 50, { maxWait: 250 });
943+
angular.element($window).on('resize', debounceResize);
944+
}
945+
946+
function onHide() {
947+
hideModalBackdrop();
948+
angular.element($window).off('resize', debounceResize);
949+
}
950+
951+
ctrl.$onChanges = function (changeObj) {
952+
if (changeObj.shown) {
953+
if (ctrl.shown) {
954+
onShow();
955+
} else {
956+
onHide();
957+
}
958+
}
959+
960+
if (changeObj.shown || changeObj.referenceElement) {
961+
if (ctrl.shown) {
962+
updatePosition();
963+
}
964+
}
965+
};
966+
967+
ctrl.$onDestroy = function() {
968+
if (ctrl.shown) {
969+
onHide();
970+
}
971+
}
972+
}
973+
});
851974
;'use strict';
852975
// oscUnique is a validation directive
853976
// use:

dist/origin-web-common.css

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,91 @@ div.hopscotch-bubble .hopscotch-nav-button.prev {
272272
word-break: break-word;
273273
overflow-wrap: break-word;
274274
}
275+
.origin-modal-popup {
276+
background-color: #fff;
277+
bottom: 0;
278+
color: #363636;
279+
left: 0;
280+
position: fixed;
281+
padding: 0 20px 20px;
282+
right: 0;
283+
top: 0;
284+
z-index: 1050;
285+
}
286+
@media (min-width: 768px) {
287+
.origin-modal-popup {
288+
border: 1px solid #bbb;
289+
bottom: auto;
290+
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
291+
left: auto;
292+
margin-top: 15px;
293+
right: auto;
294+
top: auto;
295+
}
296+
.origin-modal-popup:after {
297+
border: solid 7px transparent;
298+
border-bottom-color: #bbb;
299+
content: "";
300+
position: absolute;
301+
right: 10px;
302+
top: -15px;
303+
}
304+
.origin-modal-popup:before {
305+
border: solid 7px transparent;
306+
border-bottom-color: #f5f5f5;
307+
content: "";
308+
position: absolute;
309+
right: 10px;
310+
top: -14px;
311+
z-index: 1;
312+
}
313+
.origin-modal-popup.position-above {
314+
margin-top: -15px;
315+
}
316+
.origin-modal-popup.position-above:after {
317+
border-bottom-color: transparent;
318+
border-top-color: #fff;
319+
bottom: -15px;
320+
top: auto;
321+
}
322+
.origin-modal-popup.position-above:before {
323+
border-bottom-color: transparent;
324+
border-top-color: #fff;
325+
bottom: -14px;
326+
top: auto;
327+
}
328+
.origin-modal-popup.position-left:after {
329+
left: 10px;
330+
right: auto;
331+
}
332+
.origin-modal-popup.position-left:before {
333+
left: 10px;
334+
right: auto;
335+
}
336+
}
337+
.origin-modal-popup .origin-modal-popup-close {
338+
color: #72767b;
339+
font-size: 14px;
340+
line-height: 1;
341+
position: absolute;
342+
right: 20px;
343+
top: 11px;
344+
}
345+
.origin-modal-popup .origin-modal-popup-close:hover {
346+
color: #393f44;
347+
}
348+
.origin-modal-popup .origin-modal-popup-title {
349+
background: #f5f5f5;
350+
margin-left: -20px;
351+
margin-right: -20px;
352+
margin-top: 0;
353+
padding: 10px 40px 10px 20px;
354+
}
355+
.origin-modal-popup-backdrop.modal-backdrop {
356+
background-color: transparent;
357+
cursor: not-allowed;
358+
z-index: 1031;
359+
}
275360
.toast-action-divider {
276361
color: #9c9c9c;
277362
}

0 commit comments

Comments
 (0)