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});