PageSourceSearch

https://fedorabr.org/js/flyouts.js?v=2022.003

js fedorabr.org collected 2026-10-04 09:27:12 UTC 10,777 bytes, 329 lines download raw bytes

1/**
2 * Legacy flyout code extracted from global.js
3 *
4 * @copyright 2009-2018 Vanilla Forums Inc.
5 * @license GPL-2.0-only
6 */
7
8/**
9 * IFFE for flyout code.
10 *
11 * @param {Window} window
12 * @param {jQuery} $
13 */
14(function(window, $) {
15    var USE_NEW_FLYOUTS = window.gdn.meta.themeFeatures.NewFlyouts || false;
16    var OPEN_CLASS = "Open";
17
18    /**
19     * Content load handler, which is fired on first load, and when additional content is loaded in.
20     */
21    $(document).on("contentLoad", function(e) {
22        kludgeFlyoutHTML();
23    });
24
25    /**
26     * Document ready handler. Runs only the first time the page is loaded.
27     */
28    $(function() {
29        $(document).delegate(".Hijack, .js-hijack", "click", handleHijackClick);
30        $(document).delegate(".ButtonGroup > .Handle", "click", handleButtonHandleClick);
31        $(document).delegate(".ToggleFlyout", "click", handleToggleFlyoutClick);
32        $(document).delegate(".ToggleFlyout a", "mouseup", handleToggleFlyoutMouseUp);
33        $(document).delegate(document, "click", closeAllFlyouts);
34        $(document).delegate(".mobileFlyoutOverlay", "click", function (e) {
35            e.stopPropagation();
36            closeAllFlyouts();
37        });
38    });
39
40    /**
41     * Workarounds for limitations of flyout's HTML structure.
42     */
43    function kludgeFlyoutHTML() {
44        var $handles = $(".ToggleFlyout:not([data-is-kludged]), .editor-dropdown:not([data-is-kludged]), .ButtonGroup:not([data-is-kludged])");
45
46        $handles.each(function() {
47            $handles
48                .find(".FlyoutButton, .Handle, .editor-action:not(.editor-action-separator)")
49                .each(function() {
50                    $(this)
51                        .attr("tabindex", "0")
52                        .attr("role", "button")
53                        .attr("aria-haspopup", "true");
54
55                    $(this).accessibleFlyoutHandle(false);
56                });
57
58            $handles.find(".Flyout, .Dropdown").each(function() {
59                $(this).accessibleFlyout(false);
60
61                $(this)
62                    .find("a")
63                    .each(function() {
64                        $(this).attr("tabindex", "0");
65                    });
66            });
67
68            $(this).attr("data-is-kludged", "true");
69            $(this).attr("role", "button");
70            $(this).attr("tabIndex", "0");
71        });
72
73        if (USE_NEW_FLYOUTS) {
74            var $contents = $(".Flyout:not([data-is-kludged]), .ButtonGroup .Dropdown:not([data-is-kludged])");
75            var wrap = document.createElement("span");
76            wrap.classList.add("mobileFlyoutOverlay");
77
78            $contents.each(function() {
79                var $item = $(this);
80                if (!this.parentElement.classList.contains("mobileFlyoutOverlay")) {
81                    $item.wrap(wrap);
82                }
83
84                // Some flyouts had conflicting inline display: none directly in the view.
85                // We don't change that on open/close with the new style anymore so let's clean it up here.
86                $item.removeAttr("style");
87
88                $(this).attr("data-is-kludged", "true");
89            });
90        }
91    }
92
93    var BODY_CLASS = "flyoutIsOpen";
94
95    /**
96     * Close all flyouts and open the specified one.
97     *
98     * @param {JQuery} $toggleFlyout The flyout handle
99     * @param {JQuery} $flyout The flyout body.
100     */
101    function openFlyout($toggleFlyout, $flyout) {
102        closeAllFlyouts();
103
104        $toggleFlyout
105            .addClass(OPEN_CLASS)
106            .closest(".Item")
107            .addClass(OPEN_CLASS);
108
109        if (!USE_NEW_FLYOUTS) {
110            $flyout.show();
111        }
112        $toggleFlyout.setFlyoutAttributes();
113        document.body.classList.add(BODY_CLASS);
114    }
115
116    /**
117     * Close the specified flyout.
118     *
119     * @param {JQuery} $toggleFlyout The flyout handle
120     * @param {JQuery} $flyout The flyout body.
121     */
122    function closeFlyout($toggleFlyout, $flyout) {
123        if (!USE_NEW_FLYOUTS) {
124            $flyout.hide();
125        }
126        $toggleFlyout
127            .removeClass(OPEN_CLASS)
128            .closest(".Item")
129            .removeClass(OPEN_CLASS);
130        $toggleFlyout.setFlyoutAttributes();
131        document.body.classList.remove(BODY_CLASS);
132    }
133
134    /**
135     * Close all flyouts, including ButtonGroups.
136     */
137    function closeAllFlyouts(e) {
138        closeFlyout($(".ToggleFlyout"), $(".Flyout"));
139        // Clear the button groups that are open as well.
140        $(".ButtonGroup")
141            .removeClass(OPEN_CLASS)
142            .setFlyoutAttributes();
143
144        // Kludge for legacy editor.
145        $(".editor-dropdown-open")
146            .removeClass("editor-dropdown-open")
147            .setFlyoutAttributes();
148        document.body.classList.remove(BODY_CLASS);
149    }
150
151    window.closeAllFlyouts = closeAllFlyouts;
152
153    /**
154     * Take over the clicking of an element in order to make a post request.
155     *
156     * @param {MouseEvent} e The click event.
157     */
158    function handleHijackClick(e) {
159        var $elem = $(this);
160        var $parent = $(this).closest(".Item");
161        var $toggleFlyout = $elem.closest(".ToggleFlyout");
162        var href = $elem.attr("href");
163        var progressClass = $elem.hasClass("Bookmark") ? "Bookmarking" : "InProgress";
164        var ariaPressed = $elem.attr("aria-pressed");
165
166        // If empty, or starts with a fragment identifier, do not send
167        // an async request.
168        if (!href || href.trim().indexOf("#") === 0) return;
169
170        gdn.disable(this, progressClass);
171        e.stopPropagation();
172
173        $.ajax({
174            type: "POST",
175            url: href,
176            data: { DeliveryType: "VIEW", DeliveryMethod: "JSON", TransientKey: gdn.definition("TransientKey") },
177            dataType: "json",
178            complete: function() {
179                gdn.enable($elem.get(0));
180                if (typeof ariaPressed !== 'undefined') {
181                    $elem.attr("aria-pressed", !ariaPressed);
182                }
183                $elem.removeClass(progressClass);
184                $elem.attr("href", href);
185                $flyout = $toggleFlyout.find(".Flyout");
186                closeFlyout($toggleFlyout, $flyout);
187            },
188            error: function(xhr) {
189                gdn.informError(xhr);
190            },
191            success: function(json) {
192                if (json === null) json = {};
193
194                var informed = gdn.inform(json);
195                gdn.processTargets(json.Targets, $elem, $parent);
196
197                // return focus to element
198                // this is necessary because the element got re-rendered
199                // select element by href because classes got manipulated
200                if ($parent.length > 0) {
201                    $parent.find('[href="'+href+'"]').focus();
202                }
203
204                // If there is a redirect url, go to it.
205                if (json.RedirectTo) {
206                    setTimeout(function() {
207                        window.location.replace(json.RedirectTo);
208                    }, informed ? 3000 : 0);
209                }
210            },
211        });
212
213        return false;
214    }
215
216    /**
217     * Close existing flyouts and dropdowns and open the dropdown for a particular button handle.
218     */
219    function handleButtonHandleClick() {
220        var $buttonGroup = $(this).closest(".ButtonGroup");
221        var $isOpen = $buttonGroup.hasClass(OPEN_CLASS);
222        closeAllFlyouts();
223        if (!$isOpen) {
224            // Open this one
225            $buttonGroup.addClass(OPEN_CLASS).setFlyoutAttributes();
226        }
227        return false;
228    }
229
230    /**
231     * Handle clicks on the flyout.
232     *
233     * @param {MouseEvent} e The click event to handle.
234     */
235    function handleToggleFlyoutClick(e) {
236        var $toggleFlyout = $(this);
237        var $flyout = $(".Flyout", this);
238        var isHandle = false;
239
240        if ($(e.target).closest(".Flyout").length === 0) {
241            isHandle = true;
242            e.stopPropagation();
243        } else if (
244            $(e.target).hasClass("Hijack") ||
245            $(e.target)
246                .closest("a")
247                .hasClass("Hijack")
248        ) {
249            return;
250        }
251        e.stopPropagation();
252        $toggleFlyout.fillFlyoutDynamically();
253
254        // The old check.
255        var isFlyoutClosed = $flyout.css("display") == "none";
256        if (USE_NEW_FLYOUTS) {
257            // The new check.
258            isFlyoutClosed = !$toggleFlyout.hasClass(OPEN_CLASS);
259        }
260
261        // Toggling.
262        if (isFlyoutClosed) {
263            openFlyout($toggleFlyout, $flyout);
264        } else {
265            closeFlyout($toggleFlyout, $flyout);
266        }
267
268        if (isHandle) return false;
269    }
270
271    /**
272     * Close all of the flyouts unless we are clicking on a button inside of a flyout.
273     */
274    function handleToggleFlyoutMouseUp() {
275        if ($(this).hasClass("FlyoutButton")) return;
276        closeAllFlyouts();
277    }
278
279    /**
280     * jQuery function extensions
281     */
282    $.fn.extend({
283        fillFlyoutDynamically: function() {
284            var rel = $(this).attr("rel");
285            if (rel) {
286                $flyout = $(this).find(".Flyout");
287
288                // Clear the rel and set a progress indicator.
289                $(this).attr("rel", "");
290                $flyout.html('<div class="InProgress" style="height: 30px"></div>');
291
292                // Fetch the contents dynamically and fill on contents of the flyout.
293                $.ajax({
294                    url: gdn.url(rel),
295                    data: { DeliveryType: "VIEW" },
296                    success: function(data) {
297                        $flyout.html(data);
298                    },
299                    error: function(xhr) {
300                        $flyout.html("");
301                        gdn.informError(xhr, true);
302                    },
303                });
304            }
305        },
306        accessibleFlyoutHandle: function(isOpen) {
307            $(this).attr("aria-expanded", isOpen.toString());
308        },
309
310        accessibleFlyout: function(isOpen) {
311            $(this).attr("aria-hidden", (!isOpen).toString());
312        },
313
314        setFlyoutAttributes: function() {
315            $toggleFlyouts = $(this);
316            $toggleFlyouts.each(function() {
317                $toggle = $(this);
318                var $handle = $(this).find(
319                    ".FlyoutButton, .Button-Options, .Handle, .editor-action:not(.editor-action-separator)"
320                );
321                var $flyout = $(this).find(".Flyout, .Dropdown");
322                var isOpen = $toggle.hasClass(OPEN_CLASS);
323
324                $handle.accessibleFlyoutHandle(isOpen);
325                $flyout.accessibleFlyout(isOpen);
326            });
327        },
328    });
329})(window, jQuery);

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.