1 | export default {
|
2 | name: "cjsPopover",
|
3 | injections: [],
|
4 | fn: () => ({
|
5 |
|
6 | link: function(scope, element, attrs) {
|
7 | var useOverlay = attrs.noOverlay === undefined;
|
8 | var horizontal = attrs.horizontal !== undefined;
|
9 | var menuwidth = parseFloat(attrs.menuwidth) || 280;
|
10 | var menuheight = parseFloat(attrs.menuheight) || 150;
|
11 |
|
12 | element.addClass("modal");
|
13 | element.addClass("popover");
|
14 | var removeEventHandlers;
|
15 |
|
16 | function clickOutsidePopup(e) {
|
17 | removeEventHandlers();
|
18 | var r = element[0].getBoundingClientRect();
|
19 | var x = e.changedTouches ? e.changedTouches[0].clientX : e.touches ? e.touches[0].clientX : e.clientX;
|
20 | var y = e.changedTouches ? e.changedTouches[0].clientY : e.touches ? e.touches[0].clientY : e.clientY;
|
21 | if (x > r.left && x < r.right && y > r.top && y < r.bottom) return;
|
22 | scope.$apply("hideModal('" + attrs.cjsSidepanel + "')");
|
23 | removeEventHandlers();
|
24 | }
|
25 |
|
26 | function closeWithKey(e) {
|
27 | e.preventDefault();
|
28 | clickOutsidePopup(e);
|
29 | }
|
30 |
|
31 | removeEventHandlers = function() {
|
32 | window.document.body.removeEventListener(window.useMouse ? 'mousedown' : "touchstart", clickOutsidePopup, true);
|
33 | window.document.body.removeEventListener('keydown', closeWithKey, true);
|
34 | };
|
35 |
|
36 | scope.$on('$destroy', removeEventHandlers);
|
37 |
|
38 | function ensureOverlay() {
|
39 | var parentPageElement = element.closest(".chondric-page");
|
40 | if (parentPageElement.length === 0) parentPageElement = element.closest(".chondric-section");
|
41 | if (parentPageElement.length === 0) parentPageElement = element.closest(".chondric-viewport");
|
42 | if (useOverlay) {
|
43 | var overlay = angular.element(".modal-overlay", parentPageElement);
|
44 | if (overlay.length === 0) {
|
45 | overlay = angular.element('<div class="modal-overlay"></div>');
|
46 | parentPageElement.append(overlay);
|
47 | }
|
48 | return overlay;
|
49 | }
|
50 | }
|
51 | var lastFocused = null;
|
52 | scope.$watch(attrs.cjsPopover, function(val) {
|
53 |
|
54 | var overlay = ensureOverlay();
|
55 |
|
56 | if (!val) {
|
57 |
|
58 | if (lastFocused && document.activeElement === element[0]) {
|
59 | if (lastFocused.tagName == "BODY") {
|
60 | document.activeElement.blur();
|
61 | } else {
|
62 | lastFocused.focus();
|
63 | }
|
64 | lastFocused = null;
|
65 | }
|
66 |
|
67 | if (useOverlay) {
|
68 | overlay.removeClass("active");
|
69 | }
|
70 | element.removeClass("active");
|
71 | removeEventHandlers();
|
72 | } else {
|
73 | if (window.useMouse) {
|
74 |
|
75 | if (document.activeElement && document.activeElement.tagName != "BODY") {
|
76 | lastFocused = document.activeElement;
|
77 | }
|
78 | element.focus();
|
79 | }
|
80 |
|
81 | window.document.body.addEventListener(window.useMouse ? 'mousedown' : "touchstart", clickOutsidePopup, true);
|
82 | window.document.body.addEventListener('keydown', closeWithKey, true);
|
83 | menuheight = element.outerHeight() || menuheight;
|
84 | menuwidth = element.outerWidth() || menuwidth;
|
85 |
|
86 | var menupos = {};
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 | var parentRect = element[0].offsetParent.getBoundingClientRect();
|
93 |
|
94 | var br = (element.closest(".chondric-page")[0] || document.body).getBoundingClientRect();
|
95 | var pageRect = {
|
96 | top: Math.max(0, br.top),
|
97 | bottom: Math.min(angular.element(window).height(), br.bottom),
|
98 | left: Math.max(0, br.left),
|
99 | right: Math.min(angular.element(window).width(), br.right)
|
100 | };
|
101 | pageRect.width = pageRect.right - pageRect.left;
|
102 | pageRect.height = pageRect.bottom - pageRect.top;
|
103 |
|
104 | var horizontalCutoff = pageRect.left + pageRect.width / 2;
|
105 | var verticalCutoff = pageRect.top + pageRect.height / 2;
|
106 | var idealX = 0;
|
107 | var idealY = 0;
|
108 |
|
109 | var cr;
|
110 | if (val.element && val.element[0]) {
|
111 | var button = val.element[0];
|
112 | cr = button.getBoundingClientRect();
|
113 |
|
114 | if (horizontal) {
|
115 |
|
116 | if (cr.right > horizontalCutoff) {
|
117 | idealX = cr.right;
|
118 | } else {
|
119 | idealX = cr.left;
|
120 | }
|
121 | idealY = cr.top + cr.height / 2;
|
122 | } else {
|
123 |
|
124 | var w = cr.width;
|
125 | if (!w) w = cr.right - cr.left;
|
126 |
|
127 | idealX = cr.left + w / 2;
|
128 | if (cr.top > verticalCutoff) {
|
129 | idealY = cr.top;
|
130 | } else {
|
131 | idealY = cr.bottom;
|
132 | }
|
133 | }
|
134 |
|
135 | } else {
|
136 |
|
137 |
|
138 | idealX = (val.x || 0) - (window.pageXOffset || 0);
|
139 | idealY = (val.y || 0) - (window.pageYOffset || 0);
|
140 | }
|
141 |
|
142 |
|
143 | var actualX = idealX;
|
144 | var actualY = idealY;
|
145 |
|
146 | if (horizontal) {
|
147 | if (idealY - 10 - menuheight / 2 < pageRect.top) actualY = pageRect.top + menuheight / 2 + 10;
|
148 | if ((idealY + 10 + menuheight / 2) > pageRect.bottom) actualY = pageRect.bottom - menuheight / 2 - 10;
|
149 | } else {
|
150 | if (idealX - 10 - menuwidth / 2 < pageRect.left) actualX = pageRect.left + menuwidth / 2 + 10;
|
151 | if ((idealX + 10 + menuwidth / 2) > pageRect.right) actualX = pageRect.right - menuwidth / 2 - 10;
|
152 | }
|
153 |
|
154 | if (horizontal) {
|
155 | if (actualX < horizontalCutoff) {
|
156 | menupos.left = (actualX + 13 - parentRect.left) + "px";
|
157 | menupos.right = "auto";
|
158 | element.addClass("right").removeClass("left");
|
159 | } else {
|
160 | menupos.right = (parentRect.right - actualX + 13) + "px";
|
161 | menupos.left = "auto";
|
162 | element.addClass("left").removeClass("right");
|
163 | }
|
164 | menupos.top = (actualY - menuheight / 2 - parentRect.top) + "px";
|
165 | } else {
|
166 | if (actualY < verticalCutoff || (cr && actualY > cr.top)) {
|
167 | menupos.top = (actualY + 13 - parentRect.top) + "px";
|
168 | menupos.bottom = "auto";
|
169 | element.addClass("down").removeClass("up");
|
170 | } else {
|
171 | menupos.bottom = (parentRect.bottom - actualY + 13) + "px";
|
172 | menupos.top = "auto";
|
173 | element.addClass("up").removeClass("down");
|
174 | }
|
175 | menupos.left = (actualX - menuwidth / 2 - parentRect.left) + "px";
|
176 | }
|
177 |
|
178 | var indel = angular.element(".poparrow", element);
|
179 | if (indel.length > 0) {
|
180 | if (horizontal) {
|
181 | var arrowtop = idealY - (actualY - menuheight / 2) - 13;
|
182 | if (arrowtop < 10) arrowtop = 10;
|
183 | if (arrowtop + 26 > menuheight - 10) arrowtop = menuheight - 10 - 26;
|
184 | indel.css("top", arrowtop + "px");
|
185 | } else {
|
186 | var arrowleft = idealX - (actualX - menuwidth / 2) - 13;
|
187 | if (arrowleft < 10) arrowleft = 10;
|
188 | if (arrowleft + 26 > menuwidth - 10) arrowleft = menuwidth - 10 - 26;
|
189 | indel.css("left", arrowleft + "px");
|
190 |
|
191 | }
|
192 | }
|
193 | if (useOverlay) {
|
194 | overlay.addClass("active");
|
195 | }
|
196 | element.addClass("active");
|
197 | element.css(menupos);
|
198 | }
|
199 | });
|
200 | }
|
201 | })
|
202 | };
|