PageSourceSearch

https://support.centuria.pl/includes/ajs/layer/LayerManager.js

js centuria.pl collected 2026-10-05 07:02:53 UTC 6,851 bytes, 170 lines download raw bytes

1/**
2 * @fileOverview
3 * JIRA's layer management has some fundamental shortcomings. I'll do my best to explain them.
4 *
5 * An ideal layer management solution would be something like:
6 * - a single 'layerable' component exists, from which every other component extends or mixes in.
7 * - all layers have a parent-child relationship with something else in the DOM.
8 * - whenever a layer is to be shown or hidden, correct layering would be a case of
9 * -- determining the parent of the layer to be shown/hidden
10 * -- popping every layer that's a child of the parent you found, then
11 * -- pushing the new layer (if it was to be shown).
12 *
13 * JIRA's layer management is nothing like that.
14 *
15 * JIRA has no core layerable component, and no hierarchy of layers. Rather,
16 * each component can decide whether it shows or hides individually.
17 * A consequence of this: no one layerable component knows about (or could know about) another.
18 * There is no layer hierarchy; instead of a "stack" of layers, each component has a
19 * singleton value for the "current" shown instance of that component.
20 *
21 * Because of this, JIRA's layer management consists of:
22 * (1) figuring out what components can be shown or hidden at any given time,
23 * (2) knowing what all layerable events might occur, and
24 * (3) knowing which shown layers should appear/disappear when an event occurs.
25 *
26 * @note
27 * This file is deliberately *not* an AMD module, because the event registration
28 * needs to happen immediately an synchronously so as not to miss any events fired
29 * during page initialisation.
30 */
31(function () {
32  'use strict';
33
34  var Events = require('jira/util/events');
35  var Types = require('jira/util/events/types');
36  var Strings = require('jira/util/strings');
37  var LayerHideReason = require('jira/ajs/layer/hide-reasons');
38  var interactions = require('jira/ajs/layer/layer-interactions');
39  var topSameOriginWindow = require('jira/util/top-same-origin-window');
40  var jQuery = require('jquery');
41  var _ = require('underscore');
42  var $doc = jQuery(document);
43  function anyStringContains(haystack, needles) {
44    if (typeof needles === "string") {
45      needles = [needles];
46    }
47    return _.any(needles, function (n) {
48      return Strings.contains(haystack, n);
49    });
50  }
51
52  // We want to make sure that we don't have any other layers open before we close the dialog
53  Events.bind("Dialog.beforeHide", function (e) {
54    var shouldPrevent = _.any(interactions.preventDialogHide(), function (layerable) {
55      return layerable && layerable.current;
56    });
57    if (shouldPrevent) {
58      e.preventDefault();
59    }
60  });
61
62  // Close any layers that are currently open before allowing a dialog open to occur
63  Events.bind("Dialog.show", function (e) {
64    _.each(interactions.hideBeforeDialogShown(), function (layerable) {
65      if (layerable && layerable.current) {
66        layerable.current.hide();
67        e.preventDefault();
68      }
69    });
70  });
71
72  // If there are layers that should affect an input, the user is probably still selecting a value
73  // for the input field. Therefore, don't allow the input to be blurred while these layers are active.
74  $doc.bind("beforeBlurInput", function (e) {
75    var shouldPrevent = _.any(interactions.preventInputBlur(), function (layerable) {
76      return layerable && layerable.current;
77    });
78    if (shouldPrevent) {
79      e.preventDefault();
80    }
81  });
82
83  // Some layers are shown to allow picking values for inline editable fields. If one is shown when an inline edit
84  // is cancelled, the user is probably still picking a value; prevent the edit from being cancelled until the layer is gone.
85  if (Types.BEFORE_INLINE_EDIT_CANCEL) {
86    Events.bind(Types.BEFORE_INLINE_EDIT_CANCEL, function (e, id, type, reason) {
87      if (reason !== JIRA.Issues.CANCEL_REASON.escPressed) {
88        return;
89      }
90      var shouldPrevent = _.any(interactions.preventInlineEditCancel(), function (layerable) {
91        return layerable && layerable.current;
92      });
93      if (shouldPrevent) {
94        e.preventDefault();
95      }
96    });
97  }
98  function getWindow() {
99    return topSameOriginWindow(window);
100  }
101  function getLayer(instance) {
102    // instance is:
103    //  - AJS.InlineLayer
104    //  - JIRA.Dialog
105    //  - AJS.dropDown
106    //  - AJS.InlineDialog.
107    //  - AJS.Dialog
108    return (instance.$layer || instance.$popup || instance.$ || instance.popup || instance.element || instance)[0];
109  }
110  function listenForLayerEvents($doc) {
111    $doc.bind("showLayer", function (e, type, item) {
112      // User hover and inline edit dialogs don't participate in layer management.
113      if (anyStringContains(item && item.id, ["user-hover-dialog", "aui-inline-edit-error", "watchers", "jira-help-tip"])) {
114        return;
115      }
116      var topWindow = getWindow().AJS;
117      //the user-hover-dialog has a dropdown in it which is why we're not hiding it on showLayer. It hides
118      //itself anyway when the user doesn't hover over it any more with the mouse.
119      if (topWindow.currentLayerItem && item !== topWindow.currentLayerItem && topWindow.currentLayerItem.type !== "popup") {
120        topWindow.currentLayerItem.hide();
121      }
122      if (item) {
123        topWindow.currentLayerItem = item;
124        topWindow.currentLayerItem.type = type;
125      }
126    }).bind("hideLayer", function (e, type, item) {
127      // User hover dialogs don't participate in layer management.
128      if (!item || anyStringContains(item.id, ["user-hover-dialog", "aui-inline-edit-error", "jira-help-tip"])) {
129        return;
130      }
131      var topWindow = getWindow().AJS;
132      if (topWindow.currentLayerItem) {
133        if (topWindow.currentLayerItem === item) {
134          topWindow.currentLayerItem = null;
135        } else if (jQuery.contains(getLayer(item), getLayer(topWindow.currentLayerItem))) {
136          topWindow.currentLayerItem.hide();
137        }
138      }
139    }).bind("hideAllLayers", function () {
140      var topWindow = getWindow().AJS;
141      if (topWindow.currentLayerItem) {
142        topWindow.currentLayerItem.hide();
143      }
144    }).click(function (e) {
145      var topWindow = getWindow().AJS;
146      var layerItem = topWindow.currentLayerItem;
147      if (!layerItem || layerItem.type === "popup" || layerItem.type === "inlineDialog" && layerItem.persistent) {
148        return;
149      }
150      if (layerItem._validateClickToClose) {
151        if (layerItem._validateClickToClose(e)) {
152          if (layerItem instanceof AJS.InlineLayer) {
153            layerItem.hide(LayerHideReason.clickOutside, e);
154          } else {
155            layerItem.hide();
156          }
157        }
158      } else {
159        layerItem.hide();
160      }
161    });
162  }
163  $doc.bind("iframeAppended", function (e, iframe) {
164    iframe = jQuery(iframe);
165    iframe.on('load', function () {
166      listenForLayerEvents(iframe.contents());
167    });
168  });
169  listenForLayerEvents($doc);
170})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.