1document.addEventListener("DOMContentLoaded", function() { 2 3 var elem = document.querySelectorAll(".jirainfo"), 4 //Counter new popup elements 5 counter = 0, 6 timerElem = null, // timer for hoverByElem 7 timerPopup = null; // timer for hoverByPopup 8 9 const CONF = { 10 trigger: JSINFO['jirainfo']['trigger'] || "click", 11 placement: JSINFO['jirainfo']['placement'] || "top", 12 animation: JSINFO['jirainfo']['animation'] || "pop" 13 }; 14 15 var clickOutside = function() { 16 document.onclick = function(event) { 17 if (event.target.className != "jirainfo") { 18 plugin_jirainfo.hide(); 19 event.stopPropagation(); 20 } 21 }; 22 }; 23 24 var plugin_jirainfo = (function() { 25 var self = {}; 26 27 self.init = function () { 28 for (let i = 0; i < elem.length; i++) { 29 (CONF.trigger === "hover") ? hoverByElem(elem[i]) : eventClick(elem[i]); 30 } 31 // only click 32 (CONF.trigger === "click") ? clickOutside() : ''; 33 }; 34 35 self.open = function () { 36 if (self.isOpened(this)) return; 37 // to hide all opened popup 38 self.hide(); 39 40 var popup = new jiPopup(this); 41 popup.create(); 42 popup.show(this); 43 // if pop-element is created then only show, without getData 44 if (popup.key) popup.getDataByKey(); 45 }; 46 /** 47 * Hide popup-element 48 * @param {HTMLElement} popup 49 */ 50 self.setDisplayNone = function(popup) { 51 setTimeout(function() { popup.style.display = "none"; }, 50); 52 popup.classList.remove(CONF.animation+"-in"); 53 popup.classList.add(CONF.animation+"-out"); 54 }; 55 /** 56 * Hide all opened popup elements 57 */ 58 self.hide = function () { 59 let popupItems = document.querySelectorAll(".ji-popup."+ CONF.animation +"-in"); 60 //doesn't not found 61 if (!popupItems) return; 62 63 for(let i = 0; i < popupItems.length; i++) { 64 self.setDisplayNone(popupItems[i]); 65 } 66 }; 67 68 self.isOpened = function (elem) { 69 if (elem.hasAttribute("data-target")) { 70 return document.getElementById(elem.getAttribute("data-target")).classList.contains(CONF.animation+"-in"); 71 } 72 }; 73 return self; 74 })(); 75 76 plugin_jirainfo.init(); 77 78 /** 79 * @function 80 * Trigger Click 81 * Events by popup element 82 */ 83 function eventClick(elem) { 84 elem.onclick = function() { 85 plugin_jirainfo.open.call(elem); 86 } 87 }; 88 89 /** 90 * @function 91 * Trigger Hover 92 * Events by popup element 93 */ 94 function hoverByElem(elem) { 95 var timer = null; 96 97 elem.onmouseover = function() { 98 timer = setTimeout(bind(plugin_jirainfo.open, elem), 100); 99 clearTimeout(timerElem) 100 }; 101 elem.onmouseout = function () { 102 clearTimeout(timer); 103 if (plugin_jirainfo.isOpened(elem)) { 104 timerPopup = setTimeout(hoverByPopup.call(elem), 100); 105 } 106 }; 107 }; 108 109 /** 110 * @function 111 * Trigger Hover 112 * Events by popup element 113 */ 114 function hoverByPopup() { 115 var popup = document.getElementById(this.getAttribute("data-target")), 116 timer = setTimeout(plugin_jirainfo.hide, 100); 117 118 popup.onmouseover = function () { 119 clearTimeout(timerPopup); // on open popup 120 clearTimeout(timerElem); // if return out for refer element 121 clearTimeout(timer); // 122 }; 123 popup.onmouseout = function () { 124 timerElem = setTimeout(plugin_jirainfo.hide, 100); 125 }; 126 }; 127 128 /** 129 * @function 130 * Bind function and this(context) 131 * @param {Function} func 132 * @param {this} context 133 * @return {this} 134 */ 135 function bind(func, context) { 136 return function() { 137 return func.call(context); 138 }; 139 }; 140 141 /** 142 * @Class jiPopup 143 * @constructor 144 * @param {} elem target element 145 */ 146 function jiPopup(elem) { 147 148 if (this.isCreated(elem)) { 149 this.id = elem.getAttribute("data-target"); 150 } else { 151 this.id = "jiPopup" + ++counter; 152 elem.setAttribute("data-target", this.id); 153 } 154 this.key = elem.getAttribute("data-key"); 155 }; 156 /** 157 * Create the Popup-element with arrow and content 158 */ 159 jiPopup.prototype.create = function() { 160 if (this.getPopElemByName()) return; 161 162 const popup = document.createElement("div"); 163 popup.className = "ji-popup "+ CONF.animation +" "+ CONF.animation +"-out"; 164 popup.id = this.id; 165 popup.appendChild(this.setArrowElement()); 166 popup.appendChild(this.setPopContent()); 167 document.body.appendChild(popup); 168 }; 169 /** 170 * Show the Popup-element 171 * @param {HTMLElement} elem reference element 172 */ 173 jiPopup.prototype.show = function (elem) { 174 const popup = this.getPopElemByName(); 175 this.createPopperJS(elem); 176 177 popup.style.display = "block"; 178 setTimeout(function () { 179 popup.classList.remove(CONF.animation + "-out"); 180 popup.classList.add(CONF.animation + "-in"); 181 }, 50); 182 }; 183 184 /** 185 * Add control position element by Popper.js 186 * @param {HTMLElement} elem reference link 187 */ 188 jiPopup.prototype.createPopperJS = function (elem) { 189 let self = this; 190 191 this.popper = new Popper(elem, this.getPopElemByName(), { 192 placement: CONF.placement, 193 modifiers: { 194 offset: { offset: "0, 10px" }, 195 arrow: { 196 element: self.getPopElemByName("arrow") 197 }, 198 computeStyle: { gpuAcceleration: false } 199 }, 200 onCreate: function (data) { 201 self.setArrowPlacement(data.placement); 202 }, 203 onUpdate: function (data) { 204 self.setArrowPlacement(data.placement); 205 self.getPopElemByName("body").style.opacity = 1; // pop-content-body 206 } 207 }); 208 }; 209 210 /** 211 * Check created popper by element later 212 * @param {HTMLElement} elem - reference element 213 * @return {Boolean} 214 */ 215 jiPopup.prototype.isCreated = function(elem) { 216 return elem.hasAttribute("data-target"); 217 }; 218 219 /** 220 * Create the content in the Popup-element 221 222 * @param {string} content - icon-load 223 * @return {Element} 224 */ 225 jiPopup.prototype.setPopContent = function(content) { 226 const popContent = document.createElement("div"); 227 228 popContent.className = "ji-popup-content"; 229 popContent.innerHTML = content || '<div class="icon-load"></div>'; 230 return popContent; 231 }; 232 /** 233 * Create arrow in the Popup-element 234 235 * @param {string} content icon-load 236 * @return {Element} 237 */ 238 jiPopup.prototype.setArrowElement = function() { 239 const arrow = document.createElement("div"); 240 arrow.className = "ji-arrow arrow-"+ CONF.placement; 241 return arrow; 242 }; 243 /** 244 * Set position arrow-element 245 246 * @param {String} place placement arrow-element 247 */ 248 jiPopup.prototype.setArrowPlacement = function(place) { 249 this.getPopElemByName("arrow").className = "ji-arrow arrow-" + place; 250 }; 251 /** 252 * Returns elements Popup by their a name 253 254 * @param {string} name arrow, content, body, and by default(null) Popup 255 * @return {Element} 256 */ 257 jiPopup.prototype.getPopElemByName = function(name) { 258 switch (name) { 259 case "arrow": 260 return document.getElementById(this.id).children[0]; 261 break; 262 263 case "content": 264 return document.getElementById(this.id).children[1]; 265 break; 266 267 case "body": 268 return document.getElementById(this.id).children[1].children[0]; 269 break; 270 271 default: 272 return document.getElementById(this.id); 273 break; 274 } 275 }; 276 /** 277 * Ajax request 278 */ 279 jiPopup.prototype.getDataByKey = function () { 280 let self = this; 281 jQuery.post( 282 DOKU_BASE + "lib/exe/ajax.php", 283 { 284 call: "plugin_jirainfo", 285 key: this.key 286 }, 287 function (data) { self.fillPopBody(JSON.parse(data)); } 288 ); 289 }; 290 291 jiPopup.prototype.fillPopBody = function(obj) { 292 // task not found or does not exist 293 if (obj.errors) { 294 this.updContent(obj.errors); 295 return; 296 } 297 298 let html = '<div class="ji-popup-content-body">'; 299 //title(summary) 300 html += obj.summary ? '<p class="ji-summary">' + obj.summary + "</p>" : ""; 301 //status 302 html += obj.status ? '<div class="ji-status"><span class="color-' + obj.status.color + '">' 303 + obj.status.name + "</span></div>" : ""; 304 //issuetype 305 html += obj.issuetype ? '<img src="' + obj.issuetype.iconUrl + '" class="ji-issuetype" title="' + 306 obj.issuetype.name + '">' : ""; 307 //priority 308 html += obj.priority ? '<img src="' + obj.priority.iconUrl + '" class="ji-issuetype" title="' + 309 obj.priority.name + '">' : ""; 310 //comment 311 html += obj.totalComments ? '<div class="ji-comment-circle"><span class="total-comments">' + 312 obj.totalComments + "</span></div>" : ""; 313 // url task 314 html += obj.issueUrl ? '<a href="' + obj.issueUrl + '"class="ji-key-link">' + obj.key + "</a>" : ""; 315 html += '</div>'; 316 317 this.updContent(html); 318 }; 319 320 jiPopup.prototype.updContent = function(html) { 321 this.getPopElemByName('content').innerHTML = html; 322 // initialization a method onUpdate in popper.js 323 this.popper.scheduleUpdate(); 324 }; 325});