xref: /OpenGrok/opengrok-web/src/main/webapp/js/utils-0.0.45.js (revision 587e9867142902595bd3e8ebcd1e834ee5f73750)
1d7d00a41SKrystof Tulinger/*
2d7d00a41SKrystof Tulinger * CDDL HEADER START
3d7d00a41SKrystof Tulinger *
4d7d00a41SKrystof Tulinger * The contents of this file are subject to the terms of the
5d7d00a41SKrystof Tulinger * Common Development and Distribution License (the "License").
6d7d00a41SKrystof Tulinger * You may not use this file except in compliance with the License.
7d7d00a41SKrystof Tulinger *
8d7d00a41SKrystof Tulinger * See LICENSE.txt included in this distribution for the specific
9d7d00a41SKrystof Tulinger * language governing permissions and limitations under the License.
10d7d00a41SKrystof Tulinger *
11d7d00a41SKrystof Tulinger * When distributing Covered Code, include this CDDL HEADER in each
12d7d00a41SKrystof Tulinger * file and include the License file at LICENSE.txt.
13d7d00a41SKrystof Tulinger * If applicable, add the following below this CDDL HEADER, with the
14d7d00a41SKrystof Tulinger * fields enclosed by brackets "[]" replaced with your own identifying
15d7d00a41SKrystof Tulinger * information: Portions Copyright [yyyy] [name of copyright owner]
16d7d00a41SKrystof Tulinger *
17d7d00a41SKrystof Tulinger * CDDL HEADER END
18d7d00a41SKrystof Tulinger */
19d7d00a41SKrystof Tulinger
20d7d00a41SKrystof Tulinger/*
21d7d00a41SKrystof Tulinger * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved.
22d7d00a41SKrystof Tulinger * Portions Copyright 2011 Jens Elkner.
23d7d00a41SKrystof Tulinger * Portions Copyright (c) 2017, 2020, Chris Fraire <cfraire@me.com>.
24*587e9867SKrystof Tulinger * Portions Copyright (c) 2022, Krystof Tulinger <k.tulinger@seznam.cz>.
25d7d00a41SKrystof Tulinger */
26d7d00a41SKrystof Tulinger
27d7d00a41SKrystof Tulinger/**
28d7d00a41SKrystof Tulinger * Spaces plugin.
29d7d00a41SKrystof Tulinger *
30d7d00a41SKrystof Tulinger * Inserts a dummy space between line number and the text so that on copy-paste
31d7d00a41SKrystof Tulinger * the white space is preserved.
32d7d00a41SKrystof Tulinger *
33d7d00a41SKrystof Tulinger * Internally listens on scroll events and autofills the spaces only for the visible
34d7d00a41SKrystof Tulinger * elements.
35d7d00a41SKrystof Tulinger *
36d7d00a41SKrystof Tulinger * IMPORTANT: This plugin is strictly dependent on ascending order of lines
37d7d00a41SKrystof Tulinger * and on their attribute "name". It performs a binary search which boosts performance
38d7d00a41SKrystof Tulinger * of this plugin for really long files.
39d7d00a41SKrystof Tulinger *
40d7d00a41SKrystof Tulinger * @author Krystof Tulinger
41d7d00a41SKrystof Tulinger */
42d7d00a41SKrystof Tulinger(function (w, $) {
43d7d00a41SKrystof Tulinger    const spaces = function () {
44d7d00a41SKrystof Tulinger        const inner = {
45d7d00a41SKrystof Tulinger            defaults: {
46d7d00a41SKrystof Tulinger                interval: 750,
47d7d00a41SKrystof Tulinger                selector: "a.l, a.hl",
48d7d00a41SKrystof Tulinger                $parent: null,
49d7d00a41SKrystof Tulinger                callback: function () {
50d7d00a41SKrystof Tulinger                    if (!$(this).hasClass("selected")) {
51d7d00a41SKrystof Tulinger                        $(this).addClass("selected");
52d7d00a41SKrystof Tulinger                        $(this).text($(this).text() + " ");
53d7d00a41SKrystof Tulinger                    }
54d7d00a41SKrystof Tulinger                }
55d7d00a41SKrystof Tulinger            },
56d7d00a41SKrystof Tulinger            options: {},
57d7d00a41SKrystof Tulinger            $collection: $(),
58d7d00a41SKrystof Tulinger            initialized: false,
59d7d00a41SKrystof Tulinger            lock: false,
60d7d00a41SKrystof Tulinger            binarySearch: function (array, key, compare) {
61d7d00a41SKrystof Tulinger                let lo = 0;
62d7d00a41SKrystof Tulinger                let hi = array.length - 1;
63d7d00a41SKrystof Tulinger                while (lo <= hi) {
64d7d00a41SKrystof Tulinger                    const mid = ((lo + hi) >> 1);
65d7d00a41SKrystof Tulinger                    const cmp = compare(array[mid], key);
66d7d00a41SKrystof Tulinger                    if (cmp === 0) {
67d7d00a41SKrystof Tulinger                        return mid;
68d7d00a41SKrystof Tulinger                    } else if (cmp < 0) {
69d7d00a41SKrystof Tulinger                        lo = mid + 1;
70d7d00a41SKrystof Tulinger                    } else {
71d7d00a41SKrystof Tulinger                        hi = mid - 1;
72d7d00a41SKrystof Tulinger                    }
73d7d00a41SKrystof Tulinger                }
74d7d00a41SKrystof Tulinger                return -1;
75d7d00a41SKrystof Tulinger            },
76d7d00a41SKrystof Tulinger            handleScrollEvent: function () {
77d7d00a41SKrystof Tulinger                inner.lock = false;
78d7d00a41SKrystof Tulinger
79d7d00a41SKrystof Tulinger                const myOffset = inner.$collection.first().offset() ? inner.$collection.first().offset().top : 0;
80d7d00a41SKrystof Tulinger                const myHeight = inner.$collection.first().height() || 0;
81d7d00a41SKrystof Tulinger                const parentOffset = inner.options.$parent.offset() ? inner.options.$parent.offset().top : 0;
82d7d00a41SKrystof Tulinger                const parentHeight = inner.options.$parent.height() || 0;
83d7d00a41SKrystof Tulinger
84d7d00a41SKrystof Tulinger                const expectations = {
85d7d00a41SKrystof Tulinger                    // the first element in viewport
86d7d00a41SKrystof Tulinger                    start: Math.floor(Math.abs(Math.min(myOffset - parentOffset, 0)) / myHeight),
87d7d00a41SKrystof Tulinger                    // the last element in viewport
88d7d00a41SKrystof Tulinger                    end: Math.ceil((Math.abs(Math.min(myOffset - parentOffset, 0)) + parentHeight) / myHeight)
89d7d00a41SKrystof Tulinger                };
90d7d00a41SKrystof Tulinger
91d7d00a41SKrystof Tulinger                const indices = {
92d7d00a41SKrystof Tulinger                    start: 0,
93d7d00a41SKrystof Tulinger                    end: inner.$collection.length
94d7d00a41SKrystof Tulinger                };
95d7d00a41SKrystof Tulinger
96d7d00a41SKrystof Tulinger                const cmp = function (a, key) {
97d7d00a41SKrystof Tulinger                    return $(a).attr("name") - key; // comparing the "name" attribute with the desired value
98d7d00a41SKrystof Tulinger                };
99d7d00a41SKrystof Tulinger
100d7d00a41SKrystof Tulinger
101d7d00a41SKrystof Tulinger                indices.start = inner.binarySearch(inner.$collection, expectations.start, cmp);
102d7d00a41SKrystof Tulinger                indices.end = inner.binarySearch(inner.$collection, expectations.end, cmp);
103d7d00a41SKrystof Tulinger
104d7d00a41SKrystof Tulinger                /** cutoffs */
105d7d00a41SKrystof Tulinger                indices.start = Math.max(0, indices.start);
106d7d00a41SKrystof Tulinger                indices.start = Math.min(inner.$collection.length - 1, indices.start);
107d7d00a41SKrystof Tulinger
108d7d00a41SKrystof Tulinger                if (indices.end === -1) {
109d7d00a41SKrystof Tulinger                    indices.end = inner.$collection.length - 1;
110d7d00a41SKrystof Tulinger                }
111d7d00a41SKrystof Tulinger                indices.end = Math.min(inner.$collection.length - 1, indices.end);
112d7d00a41SKrystof Tulinger
113d7d00a41SKrystof Tulinger                /** calling callback for every element in the viewport */
114d7d00a41SKrystof Tulinger                for (var i = indices.start; i <= indices.end; i++) {
115d7d00a41SKrystof Tulinger                    inner.options.callback.apply(inner.$collection[i]);
116d7d00a41SKrystof Tulinger                }
117d7d00a41SKrystof Tulinger            },
118d7d00a41SKrystof Tulinger            init: function () {
119d7d00a41SKrystof Tulinger
120d7d00a41SKrystof Tulinger                if (inner.initialized) {
121d7d00a41SKrystof Tulinger                    return;
122d7d00a41SKrystof Tulinger                }
123d7d00a41SKrystof Tulinger
124d7d00a41SKrystof Tulinger                inner.$collection = inner.options.$parent.find(inner.options.selector);
125d7d00a41SKrystof Tulinger
126d7d00a41SKrystof Tulinger                if (inner.$collection.length <= 0) {
127d7d00a41SKrystof Tulinger                    return;
128d7d00a41SKrystof Tulinger                }
129d7d00a41SKrystof Tulinger
130d7d00a41SKrystof Tulinger                const scrollHandler = function (e) {
131d7d00a41SKrystof Tulinger                    if (inner.lock) {
132d7d00a41SKrystof Tulinger                        return;
133d7d00a41SKrystof Tulinger                    }
134d7d00a41SKrystof Tulinger                    inner.lock = true;
135d7d00a41SKrystof Tulinger                    setTimeout(inner.handleScrollEvent, inner.options.interval);
136d7d00a41SKrystof Tulinger                };
137d7d00a41SKrystof Tulinger                // fire the event if user has not scrolled
138d7d00a41SKrystof Tulinger                inner.options.$parent.scroll(scrollHandler).resize(scrollHandler).scroll();
139d7d00a41SKrystof Tulinger                inner.initialized = true;
140d7d00a41SKrystof Tulinger            }
141d7d00a41SKrystof Tulinger        };
142d7d00a41SKrystof Tulinger
143d7d00a41SKrystof Tulinger        this.init = function (options) {
144d7d00a41SKrystof Tulinger            inner.options = $.extend({}, inner.defaults, {$parent: $("#content")}, options);
145d7d00a41SKrystof Tulinger            inner.init();
146d7d00a41SKrystof Tulinger            return this;
147d7d00a41SKrystof Tulinger        };
148d7d00a41SKrystof Tulinger    };
149d7d00a41SKrystof Tulinger
150d7d00a41SKrystof Tulinger    $.spaces = new ($.extend(spaces, $.spaces ? $.spaces : {}))();
151d7d00a41SKrystof Tulinger})(window, window.jQuery);
152d7d00a41SKrystof Tulinger
153d7d00a41SKrystof Tulinger/**
154d7d00a41SKrystof Tulinger * Offseting the target anchors by the height of the fixed header.
155d7d00a41SKrystof Tulinger * Code taken from http://jsfiddle.net/ianclark001/rkocah23/.
156d7d00a41SKrystof Tulinger *
157d7d00a41SKrystof Tulinger * If this is not used, clicking on a anchor
158d7d00a41SKrystof Tulinger * with a hash target (href="#some-id") will
159d7d00a41SKrystof Tulinger * lead to incorrect positioning at the top of the page.
160d7d00a41SKrystof Tulinger */
161d7d00a41SKrystof Tulinger(function (document, history, location) {
162d7d00a41SKrystof Tulinger    const HISTORY_SUPPORT = !!(history && history.pushState);
163d7d00a41SKrystof Tulinger
164d7d00a41SKrystof Tulinger    const anchorScrolls = {
165d7d00a41SKrystof Tulinger        ANCHOR_REGEX: /^#[^ ]+$/,
166d7d00a41SKrystof Tulinger        OFFSET_HEIGHT_PX: 90,
167d7d00a41SKrystof Tulinger
168d7d00a41SKrystof Tulinger        /**
169d7d00a41SKrystof Tulinger         * Establish events, and fix initial scroll position if a hash is provided.
170d7d00a41SKrystof Tulinger         */
171d7d00a41SKrystof Tulinger        init: function () {
172d7d00a41SKrystof Tulinger            this.scrollToCurrent();
173d7d00a41SKrystof Tulinger            $(window).on('hashchange', $.proxy(this, 'scrollToCurrent'));
174d7d00a41SKrystof Tulinger            $('body').on('click', 'a', $.proxy(this, 'delegateAnchors'));
175d7d00a41SKrystof Tulinger        },
176d7d00a41SKrystof Tulinger
177d7d00a41SKrystof Tulinger        /**
178d7d00a41SKrystof Tulinger         * Return the offset amount to deduct from the normal scroll position.
179d7d00a41SKrystof Tulinger         * Modify as appropriate to allow for dynamic calculations
180d7d00a41SKrystof Tulinger         */
181d7d00a41SKrystof Tulinger        getFixedOffset: function () {
182d7d00a41SKrystof Tulinger            return this.OFFSET_HEIGHT_PX;
183d7d00a41SKrystof Tulinger        },
184d7d00a41SKrystof Tulinger
185d7d00a41SKrystof Tulinger        /**
186d7d00a41SKrystof Tulinger         * If the provided href is an anchor which resolves to an element on the
187d7d00a41SKrystof Tulinger         * page, scroll to it.
188d7d00a41SKrystof Tulinger         * @param  {String} href
189d7d00a41SKrystof Tulinger         * @return {Boolean} - Was the href an anchor.
190d7d00a41SKrystof Tulinger         */
191d7d00a41SKrystof Tulinger        scrollIfAnchor: function (href, pushToHistory) {
192d7d00a41SKrystof Tulinger            if (!this.ANCHOR_REGEX.test(href)) {
193d7d00a41SKrystof Tulinger                return false;
194d7d00a41SKrystof Tulinger            }
195d7d00a41SKrystof Tulinger
196d7d00a41SKrystof Tulinger            let match = document.getElementById(href.slice(1));
197d7d00a41SKrystof Tulinger            if (!match) {
198d7d00a41SKrystof Tulinger                /**
199d7d00a41SKrystof Tulinger                 * Match the elements with name="href", take the first match
200d7d00a41SKrystof Tulinger                 */
201d7d00a41SKrystof Tulinger                match = document.getElementsByName(href.slice(1));
202d7d00a41SKrystof Tulinger                match = match.length > 0 ? match[0] : null;
203d7d00a41SKrystof Tulinger            }
204d7d00a41SKrystof Tulinger
205d7d00a41SKrystof Tulinger            if (match) {
206d7d00a41SKrystof Tulinger                const anchorOffset = $(match.nextElementSibling).offset().top - this.getFixedOffset();
207d7d00a41SKrystof Tulinger                $('html, body').animate({scrollTop: anchorOffset});
208d7d00a41SKrystof Tulinger
209d7d00a41SKrystof Tulinger                location.hash = href;
210d7d00a41SKrystof Tulinger
211d7d00a41SKrystof Tulinger                // Add the state to history as-per normal anchor links
212d7d00a41SKrystof Tulinger                if (HISTORY_SUPPORT && pushToHistory) {
213d7d00a41SKrystof Tulinger                    history.pushState({}, document.title, location.pathname + location.search + href);
214d7d00a41SKrystof Tulinger                }
215d7d00a41SKrystof Tulinger            }
216d7d00a41SKrystof Tulinger
217d7d00a41SKrystof Tulinger            return !!match;
218d7d00a41SKrystof Tulinger        },
219d7d00a41SKrystof Tulinger
220d7d00a41SKrystof Tulinger        /**
221d7d00a41SKrystof Tulinger         * Attempt to scroll to the current location's hash.
222d7d00a41SKrystof Tulinger         */
223d7d00a41SKrystof Tulinger        scrollToCurrent: function (e) {
224d7d00a41SKrystof Tulinger            if (this.scrollIfAnchor(window.location.hash) && e) {
225d7d00a41SKrystof Tulinger                e.preventDefault();
226d7d00a41SKrystof Tulinger            }
227d7d00a41SKrystof Tulinger        },
228d7d00a41SKrystof Tulinger
229d7d00a41SKrystof Tulinger        /**
230d7d00a41SKrystof Tulinger         * If the click event's target was an anchor, fix the scroll position.
231d7d00a41SKrystof Tulinger         */
232d7d00a41SKrystof Tulinger        delegateAnchors: function (e) {
233d7d00a41SKrystof Tulinger            const elem = e.target;
234d7d00a41SKrystof Tulinger
235d7d00a41SKrystof Tulinger            if (this.scrollIfAnchor(elem.getAttribute('href'), true)) {
236d7d00a41SKrystof Tulinger                e.preventDefault();
237d7d00a41SKrystof Tulinger            }
238d7d00a41SKrystof Tulinger        }
239d7d00a41SKrystof Tulinger    };
240d7d00a41SKrystof Tulinger
241d7d00a41SKrystof Tulinger
242d7d00a41SKrystof Tulinger    $(document).ready($.proxy(anchorScrolls, 'init'));
243d7d00a41SKrystof Tulinger})(window.document, window.history, window.location);
244d7d00a41SKrystof Tulinger
245d7d00a41SKrystof Tulinger(function(window, $) {
246d7d00a41SKrystof Tulinger    const hash = function () {
247d7d00a41SKrystof Tulinger        const inner = {
248d7d00a41SKrystof Tulinger            self: this,
249d7d00a41SKrystof Tulinger            initialized: false,
250d7d00a41SKrystof Tulinger            highlighted: [],
251d7d00a41SKrystof Tulinger            defaults: {
252d7d00a41SKrystof Tulinger              highlightedClass: 'target',
253d7d00a41SKrystof Tulinger              linkSelectorTemplate: '{parent} a[name={n}]',
254d7d00a41SKrystof Tulinger              clickSelector: '{parent} a.l, {parent} a.hl',
255d7d00a41SKrystof Tulinger              parent: 'div#src',
256d7d00a41SKrystof Tulinger              autoScroll: true,
257d7d00a41SKrystof Tulinger              autoScrollDuration: 500
258d7d00a41SKrystof Tulinger            },
259d7d00a41SKrystof Tulinger            options: {},
260d7d00a41SKrystof Tulinger            bindClickHandler: function() {
261d7d00a41SKrystof Tulinger                $(inner.format(inner.options.clickSelector, {parent: inner.options.parent})).click(function (e) {
262d7d00a41SKrystof Tulinger                    if(e.shiftKey) {
263d7d00a41SKrystof Tulinger                        // shift pressed
264d7d00a41SKrystof Tulinger                        const val = inner.toInt($(this).attr("name"));
265d7d00a41SKrystof Tulinger                        if (!val) {
266d7d00a41SKrystof Tulinger                            return false;
267d7d00a41SKrystof Tulinger                        }
268d7d00a41SKrystof Tulinger
269d7d00a41SKrystof Tulinger                        const l = inner.getLinesParts(window.location.hash);
270d7d00a41SKrystof Tulinger
271d7d00a41SKrystof Tulinger                        if (l.length == 2) {
272d7d00a41SKrystof Tulinger                            window.location.hash = "#" + Math.min(l[0], val) + "-" + Math.max(val, l[1]);
273d7d00a41SKrystof Tulinger                        } else if (l.length == 1) {
274d7d00a41SKrystof Tulinger                            window.location.hash = "#" + Math.min(l[0], val) + "-" + Math.max(l[0], val);
275d7d00a41SKrystof Tulinger                        }
276d7d00a41SKrystof Tulinger                        return false;
277d7d00a41SKrystof Tulinger                    }
278d7d00a41SKrystof Tulinger                    return true;
279d7d00a41SKrystof Tulinger                });
280d7d00a41SKrystof Tulinger            },
281d7d00a41SKrystof Tulinger
282d7d00a41SKrystof Tulinger            getHashParts: function (hash) {
283d7d00a41SKrystof Tulinger                if (!hash || hash === "") {
284d7d00a41SKrystof Tulinger                    return hash;
285d7d00a41SKrystof Tulinger                }
286d7d00a41SKrystof Tulinger                return (hash = hash.split("#")).length > 1 ? hash[1] : "";
287d7d00a41SKrystof Tulinger            },
288d7d00a41SKrystof Tulinger
289d7d00a41SKrystof Tulinger            getLinesParts: function ( hashPart ) {
290d7d00a41SKrystof Tulinger              hashPart = inner.getHashParts(hashPart);
291d7d00a41SKrystof Tulinger              if (!hashPart || hashPart === "") {
292d7d00a41SKrystof Tulinger                  return hashPart;
293d7d00a41SKrystof Tulinger              }
294d7d00a41SKrystof Tulinger              const s = hashPart.split("-");
295d7d00a41SKrystof Tulinger              if (s.length > 1 && inner.toInt(s[0]) && inner.toInt(s[1])) {
296d7d00a41SKrystof Tulinger                  return [inner.toInt(s[0]), inner.toInt(s[1])];
297d7d00a41SKrystof Tulinger              }
298d7d00a41SKrystof Tulinger              if (s.length > 0 && inner.toInt(s[0])) {
299d7d00a41SKrystof Tulinger                  return [inner.toInt(s[0])];
300d7d00a41SKrystof Tulinger              }
301d7d00a41SKrystof Tulinger              return [];
302d7d00a41SKrystof Tulinger            },
303d7d00a41SKrystof Tulinger
304d7d00a41SKrystof Tulinger            lines: function (urlPart) {
305d7d00a41SKrystof Tulinger                const p = inner.getLinesParts(urlPart);
306d7d00a41SKrystof Tulinger                if (p.length == 2) {
307d7d00a41SKrystof Tulinger                    let l = [];
308d7d00a41SKrystof Tulinger                    for (let i = Math.min(p[0],p[1]); i <= Math.max(p[0], p[1]); i++) {
309d7d00a41SKrystof Tulinger                        l.push(i);
310d7d00a41SKrystof Tulinger                    }
311d7d00a41SKrystof Tulinger                    return l;
312d7d00a41SKrystof Tulinger                } else if (p.length == 1){
313d7d00a41SKrystof Tulinger                    return [p[0]];
314d7d00a41SKrystof Tulinger                }
315d7d00a41SKrystof Tulinger                return [];
316d7d00a41SKrystof Tulinger            },
317d7d00a41SKrystof Tulinger
318d7d00a41SKrystof Tulinger            reload: function(e){
319d7d00a41SKrystof Tulinger                for (let i = 0; i < inner.highlighted.length; i++) {
320d7d00a41SKrystof Tulinger                    // remove color
321d7d00a41SKrystof Tulinger                    inner.highlighted[i].removeClass(inner.options.highlightedClass);
322d7d00a41SKrystof Tulinger                }
323d7d00a41SKrystof Tulinger                inner.highlighted = [];
324d7d00a41SKrystof Tulinger
325d7d00a41SKrystof Tulinger                const lines = inner.lines(window.location.hash);
326d7d00a41SKrystof Tulinger
327d7d00a41SKrystof Tulinger                if (lines.length < 1) {
328d7d00a41SKrystof Tulinger                    // not a case of line highlighting
329d7d00a41SKrystof Tulinger                    return;
330d7d00a41SKrystof Tulinger                }
331d7d00a41SKrystof Tulinger                for (let j = 0; j < lines.length; j++) {
332d7d00a41SKrystof Tulinger                    // color
333d7d00a41SKrystof Tulinger                    const slc = inner.format(inner.options.linkSelectorTemplate, { "parent": inner.options.parent,
334d7d00a41SKrystof Tulinger                                                                                  "n": lines[j] } );
335d7d00a41SKrystof Tulinger                    const el = $(slc).addClass(inner.options.highlightedClass);
336d7d00a41SKrystof Tulinger                    inner.highlighted.push(el);
337d7d00a41SKrystof Tulinger                }
338d7d00a41SKrystof Tulinger            },
339d7d00a41SKrystof Tulinger            format: function(format) {
340d7d00a41SKrystof Tulinger                let args = Array.prototype.slice.call(arguments, 1);
341d7d00a41SKrystof Tulinger                args = args.length > 0 ? typeof args[0] === "object" ? args[0] : args : args;
342d7d00a41SKrystof Tulinger                return format.replace(/{([a-zA-Z0-9_-]+)}/g, function(match, number) {
343d7d00a41SKrystof Tulinger                  return typeof args[number] != 'undefined' ? args[number] : match;
344d7d00a41SKrystof Tulinger                });
345d7d00a41SKrystof Tulinger            },
346d7d00a41SKrystof Tulinger            toInt: function (string) {
347d7d00a41SKrystof Tulinger                return parseInt(string, 10);
348d7d00a41SKrystof Tulinger            },
349d7d00a41SKrystof Tulinger            scroll: function (){
350d7d00a41SKrystof Tulinger                if (!inner.options.autoScroll) {
351d7d00a41SKrystof Tulinger                    return;
352d7d00a41SKrystof Tulinger                }
353d7d00a41SKrystof Tulinger                const lines = inner.getLinesParts(window.location.hash);
354d7d00a41SKrystof Tulinger                if (lines.length > 0) {
355d7d00a41SKrystof Tulinger                    const line = lines[0]; // first line
356d7d00a41SKrystof Tulinger                    const $line = $(inner.format(inner.options.linkSelectorTemplate, {
357d7d00a41SKrystof Tulinger                        parent: inner.options.parent,
358d7d00a41SKrystof Tulinger                        n: line
359d7d00a41SKrystof Tulinger                    }));
360d7d00a41SKrystof Tulinger                    if ($line.length > 0) {
361d7d00a41SKrystof Tulinger                        // if there is such element identified with the line number
362d7d00a41SKrystof Tulinger                        // we can scroll to it
363d7d00a41SKrystof Tulinger                        $('html, body').animate({
364d7d00a41SKrystof Tulinger                            scrollTop: $(inner.format(inner.options.linkSelectorTemplate, {
365d7d00a41SKrystof Tulinger                                parent: inner.options.parent,
366d7d00a41SKrystof Tulinger                                n: line
367d7d00a41SKrystof Tulinger                            })).offset().top - $(inner.options.parent).offset().top
368d7d00a41SKrystof Tulinger                        }, inner.options.autoScrollDuration);
369d7d00a41SKrystof Tulinger                    }
370d7d00a41SKrystof Tulinger                }
371d7d00a41SKrystof Tulinger            }
372d7d00a41SKrystof Tulinger        }; // inner
373d7d00a41SKrystof Tulinger
374d7d00a41SKrystof Tulinger        this.init = function (options) {
375d7d00a41SKrystof Tulinger            if (inner.initialized) {
376d7d00a41SKrystof Tulinger                return this;
377d7d00a41SKrystof Tulinger            }
378d7d00a41SKrystof Tulinger            inner.options = $.extend(inner.defaults, options, {});
379d7d00a41SKrystof Tulinger
380d7d00a41SKrystof Tulinger            $(window).on("hashchange", inner.reload);
381d7d00a41SKrystof Tulinger            inner.reload();
382d7d00a41SKrystof Tulinger            inner.bindClickHandler();
383d7d00a41SKrystof Tulinger            inner.scroll();
384d7d00a41SKrystof Tulinger            inner.initialized = true;
385d7d00a41SKrystof Tulinger            return this;
386d7d00a41SKrystof Tulinger        };
387d7d00a41SKrystof Tulinger    };
388d7d00a41SKrystof Tulinger    $.hash = new ($.extend(hash, $.hash ? $.hash : {}))();
389d7d00a41SKrystof Tulinger}) (window, window.jQuery);
390d7d00a41SKrystof Tulinger
391d7d00a41SKrystof Tulinger/**
392d7d00a41SKrystof Tulinger * General on-demand script downloader
393d7d00a41SKrystof Tulinger */
394d7d00a41SKrystof Tulinger(function (window, document, $) {
395d7d00a41SKrystof Tulinger    const script = function () {
396d7d00a41SKrystof Tulinger        this.scriptsDownloaded = {};
397d7d00a41SKrystof Tulinger        this.defaults = {
398d7d00a41SKrystof Tulinger            contextPath: window.contextPath
399d7d00a41SKrystof Tulinger        };
400d7d00a41SKrystof Tulinger
401d7d00a41SKrystof Tulinger        this.options = $.extend(this.defaults, {});
402d7d00a41SKrystof Tulinger
403d7d00a41SKrystof Tulinger        this.loadScript = function (url) {
404d7d00a41SKrystof Tulinger            if (!/^[a-z]{3,5}:\/\//.test(url)) { // dummy test for remote prefix
405d7d00a41SKrystof Tulinger                url = this.options.contextPath + '/' + url;
406d7d00a41SKrystof Tulinger            }
407d7d00a41SKrystof Tulinger            if (url in this.scriptsDownloaded) {
408d7d00a41SKrystof Tulinger                return this.scriptsDownloaded[url];
409d7d00a41SKrystof Tulinger            }
410d7d00a41SKrystof Tulinger            this.scriptsDownloaded[url] = $.ajax({
411d7d00a41SKrystof Tulinger                url: url,
412d7d00a41SKrystof Tulinger                dataType: 'script',
413d7d00a41SKrystof Tulinger                cache: true,
414d7d00a41SKrystof Tulinger                timeout: 10000
415d7d00a41SKrystof Tulinger            }).fail(function () {
416d7d00a41SKrystof Tulinger                console.debug('Failed to download "' + url + '" module');
417d7d00a41SKrystof Tulinger            });
418d7d00a41SKrystof Tulinger            return this.scriptsDownloaded[url];
419d7d00a41SKrystof Tulinger        };
420d7d00a41SKrystof Tulinger    };
421d7d00a41SKrystof Tulinger    $.script = new ($.extend(script, $.script ? $.script : {}))();
422d7d00a41SKrystof Tulinger})(window, document, jQuery);
423d7d00a41SKrystof Tulinger
424d7d00a41SKrystof Tulinger/**
425d7d00a41SKrystof Tulinger * General window plugin
426d7d00a41SKrystof Tulinger *
427d7d00a41SKrystof Tulinger * This plugin allows you to create a new window inside the browser. The main
428d7d00a41SKrystof Tulinger * interface is create function.
429d7d00a41SKrystof Tulinger *
430d7d00a41SKrystof Tulinger * Usage:
431d7d00a41SKrystof Tulinger * $myWindow = $.window.create({
432d7d00a41SKrystof Tulinger *  // default options (later available via this.options)
433d7d00a41SKrystof Tulinger *  project: 'abcd', // not existing in window options and will be filled
434d7d00a41SKrystof Tulinger *  draggable: false, // override the window defaults
435d7d00a41SKrystof Tulinger *  // callbacks for events
436d7d00a41SKrystof Tulinger *  init: function ($window) {
437d7d00a41SKrystof Tulinger *      // called when creating the new window
438d7d00a41SKrystof Tulinger *      // you can modify the new window object - it's jquery object
439d7d00a41SKrystof Tulinger *      // you must return the modified window object
440d7d00a41SKrystof Tulinger *  },
441d7d00a41SKrystof Tulinger *  load: function ($window) {
442d7d00a41SKrystof Tulinger *      // called when the page is successfully loaded
443d7d00a41SKrystof Tulinger *      // you can attach some handlers and fill some options with DOM values
444d7d00a41SKrystof Tulinger *  },
445d7d00a41SKrystof Tulinger *  update: function(data) {
446d7d00a41SKrystof Tulinger *      // called when update is called on your window bypassing the data param
447d7d00a41SKrystof Tulinger *      // you can modify the window content or other DOM content
448d7d00a41SKrystof Tulinger *  }
449d7d00a41SKrystof Tulinger * }, {
450d7d00a41SKrystof Tulinger *      // context object - can contain other helper variables and functions
451d7d00a41SKrystof Tulinger *      // it's available in the callbacks as the 'this' variable
452d7d00a41SKrystof Tulinger *      // the window itself is available as this.$window
453d7d00a41SKrystof Tulinger *      modified: false,
454d7d00a41SKrystof Tulinger *      modify: function () {
455d7d00a41SKrystof Tulinger *          this.modified = true;
456d7d00a41SKrystof Tulinger *      },
457d7d00a41SKrystof Tulinger * })
458d7d00a41SKrystof Tulinger *
459d7d00a41SKrystof Tulinger * The new $myWindow object is jQuery object - you can call jQuery functions on it.
460d7d00a41SKrystof Tulinger * It doesn't really make sense to call all of the jQuery functions however
461d7d00a41SKrystof Tulinger * some of them might be useful: toggle, hide, show and so on.
462d7d00a41SKrystof Tulinger *
463d7d00a41SKrystof Tulinger * The window object also provides some useful functions like
464d7d00a41SKrystof Tulinger * $myWindow.error(message) to display an error in this.$errors element or
465d7d00a41SKrystof Tulinger * $myWindow.update(data) to trigger your update callback with given data or
466d7d00a41SKrystof Tulinger * $myWindow.move(position) to move the window to the given position
467d7d00a41SKrystof Tulinger *    if no position is given it may be determined from the mouse position
468d7d00a41SKrystof Tulinger *
469d7d00a41SKrystof Tulinger * For custom content in the window you can use body() function:
470d7d00a41SKrystof Tulinger * $myWindow.body().append($('<div>').addClass('important-div'))
471d7d00a41SKrystof Tulinger *
472d7d00a41SKrystof Tulinger * @author Kryštof Tulinger
473d7d00a41SKrystof Tulinger */
474d7d00a41SKrystof Tulinger(function (browserWindow, document, $, $script) {
475d7d00a41SKrystof Tulinger    const window = function () {
476d7d00a41SKrystof Tulinger        const Inner = function (options, context) {
477d7d00a41SKrystof Tulinger            const self = this;
478d7d00a41SKrystof Tulinger            // private
479d7d00a41SKrystof Tulinger            this.context = context;
480d7d00a41SKrystof Tulinger            this.callbacks = {
481d7d00a41SKrystof Tulinger                init: [],
482d7d00a41SKrystof Tulinger                load: [],
483d7d00a41SKrystof Tulinger                update: []
484d7d00a41SKrystof Tulinger            };
485d7d00a41SKrystof Tulinger            this.$window = undefined;
486d7d00a41SKrystof Tulinger            this.$errors = undefined;
487d7d00a41SKrystof Tulinger            this.clientX = 0;
488d7d00a41SKrystof Tulinger            this.clientY = 0;
489d7d00a41SKrystof Tulinger            this.pendingUpdates = [];
490d7d00a41SKrystof Tulinger
491d7d00a41SKrystof Tulinger            /**
492d7d00a41SKrystof Tulinger             * Default values for the window options.
493d7d00a41SKrystof Tulinger             */
494d7d00a41SKrystof Tulinger            this.defaults = {
495d7d00a41SKrystof Tulinger                title: 'Window',
496d7d00a41SKrystof Tulinger                appendDraggable: '#content',
497d7d00a41SKrystof Tulinger                draggable: true,
498d7d00a41SKrystof Tulinger                draggableScript: 'js/jquery-ui-1.12.1-draggable.min.js', // relative to context
499d7d00a41SKrystof Tulinger                contextPath: browserWindow.contextPath,
500d7d00a41SKrystof Tulinger                parent: undefined,
501d7d00a41SKrystof Tulinger                load: undefined,
502d7d00a41SKrystof Tulinger                init: undefined,
503d7d00a41SKrystof Tulinger                handlers: undefined
504d7d00a41SKrystof Tulinger            };
505d7d00a41SKrystof Tulinger
506d7d00a41SKrystof Tulinger            this.options = $.extend({}, this.defaults, options);
507d7d00a41SKrystof Tulinger
508d7d00a41SKrystof Tulinger            this.addCallback = function (name, callback, context) {
509d7d00a41SKrystof Tulinger                context = context || this.getSelfContext;
510d7d00a41SKrystof Tulinger                if (!this.callbacks || !$.isArray(this.callbacks[name])) {
511d7d00a41SKrystof Tulinger                    this.callbacks[name] = [];
512d7d00a41SKrystof Tulinger                }
513d7d00a41SKrystof Tulinger                this.callbacks[name].push({
514d7d00a41SKrystof Tulinger                    'callback': callback,
515d7d00a41SKrystof Tulinger                    'context': context
516d7d00a41SKrystof Tulinger                });
517d7d00a41SKrystof Tulinger            };
518d7d00a41SKrystof Tulinger
519d7d00a41SKrystof Tulinger            this.fire = function (name, args) {
520d7d00a41SKrystof Tulinger                if (!this.callbacks || !$.isArray(this.callbacks[name])) {
521d7d00a41SKrystof Tulinger                    return;
522d7d00a41SKrystof Tulinger                }
523d7d00a41SKrystof Tulinger
524d7d00a41SKrystof Tulinger                for (let i = 0; i < this.callbacks[name].length; i++) {
525d7d00a41SKrystof Tulinger                    this.$window = (this.callbacks[name][i].callback.apply(
526d7d00a41SKrystof Tulinger                            this.callbacks[name][i].context.call(this),
527d7d00a41SKrystof Tulinger                            args || [this.$window])) || this.$window;
528d7d00a41SKrystof Tulinger                }
529d7d00a41SKrystof Tulinger            };
530d7d00a41SKrystof Tulinger
531d7d00a41SKrystof Tulinger            this.getContext = function () {
532d7d00a41SKrystof Tulinger                return $.extend(this.context, {options: this.options});
533d7d00a41SKrystof Tulinger            };
534d7d00a41SKrystof Tulinger
535d7d00a41SKrystof Tulinger            this.getSelfContext = function () {
536d7d00a41SKrystof Tulinger                return this;
537d7d00a41SKrystof Tulinger            };
538d7d00a41SKrystof Tulinger
539d7d00a41SKrystof Tulinger            // private
540d7d00a41SKrystof Tulinger            this.cropPosition = function($w, position) {
541d7d00a41SKrystof Tulinger                const w = {
542d7d00a41SKrystof Tulinger                    height: $w.outerHeight(true),
543d7d00a41SKrystof Tulinger                    width: $w.outerWidth(true)
544d7d00a41SKrystof Tulinger                };
545d7d00a41SKrystof Tulinger                const bw = {
546d7d00a41SKrystof Tulinger                    height: $(browserWindow).outerHeight(true),
547d7d00a41SKrystof Tulinger                    width: $(browserWindow).outerWidth(true),
548d7d00a41SKrystof Tulinger                    yOffset: 0,
549d7d00a41SKrystof Tulinger                    xOffset: 0
550d7d00a41SKrystof Tulinger                };
551d7d00a41SKrystof Tulinger                position.top -= Math.max(0, position.top + w.height - bw.yOffset - bw.height + 20);
552d7d00a41SKrystof Tulinger                position.left -= Math.max(0, position.left + w.width - bw.xOffset - bw.width + 20);
553d7d00a41SKrystof Tulinger                return position;
554d7d00a41SKrystof Tulinger            };
555d7d00a41SKrystof Tulinger
556d7d00a41SKrystof Tulinger            this.determinePosition = function () {
557d7d00a41SKrystof Tulinger                const position = {
558d7d00a41SKrystof Tulinger                    top: this.clientY,
559d7d00a41SKrystof Tulinger                    left: this.clientX
560d7d00a41SKrystof Tulinger                };
561d7d00a41SKrystof Tulinger                return this.cropPosition(this.$window, position);
562d7d00a41SKrystof Tulinger            };
563d7d00a41SKrystof Tulinger
564d7d00a41SKrystof Tulinger            this.makeMeDraggable = function () {
565d7d00a41SKrystof Tulinger                if (!$script || typeof $script.loadScript !== 'function') {
566d7d00a41SKrystof Tulinger                    console.log("The window plugin requires $.script plugin when draggable option is 'true'");
567d7d00a41SKrystof Tulinger                    return;
568d7d00a41SKrystof Tulinger                }
569d7d00a41SKrystof Tulinger
570d7d00a41SKrystof Tulinger                $script.loadScript(this.options.draggableScript).done(function () {
571d7d00a41SKrystof Tulinger                    self.$window.draggable({
572d7d00a41SKrystof Tulinger                        appendTo: self.options.draggableAppendTo || $('body'),
573d7d00a41SKrystof Tulinger                        helper: 'clone',
574d7d00a41SKrystof Tulinger                        start: function () {
575d7d00a41SKrystof Tulinger                            $(this).hide();
576d7d00a41SKrystof Tulinger                        },
577d7d00a41SKrystof Tulinger                        stop: function (e, ui) {
578d7d00a41SKrystof Tulinger                            $(this).show().offset(ui.offset).css('position', 'fixed');
579d7d00a41SKrystof Tulinger                        },
580d7d00a41SKrystof Tulinger                        create: function (e, ui) {
581d7d00a41SKrystof Tulinger                            $(this).css('position', 'fixed');
582d7d00a41SKrystof Tulinger                        }
583d7d00a41SKrystof Tulinger                    });
584d7d00a41SKrystof Tulinger                });
585d7d00a41SKrystof Tulinger            };
586d7d00a41SKrystof Tulinger
587d7d00a41SKrystof Tulinger            this.addCallback('init', function ($window) {
588d7d00a41SKrystof Tulinger                let $close;
589d7d00a41SKrystof Tulinger                const $top = $("<div>").addClass('clearfix').
590d7d00a41SKrystof Tulinger                        append($("<div>").addClass("pull-left").append($("<b>").text(this.options.title || "Window"))).
591d7d00a41SKrystof Tulinger                        append($("<div>").addClass('pull-right').append($close = $('<a href="#" class="minimize">x</a>')));
592d7d00a41SKrystof Tulinger
593d7d00a41SKrystof Tulinger                const $header = $("<div>").addClass('window-header').append($top);
594d7d00a41SKrystof Tulinger
595d7d00a41SKrystof Tulinger                const $body = $("<div>").addClass("window-body").append(self.$errors = $('<div>').css('text-align', 'center'));
596d7d00a41SKrystof Tulinger
597d7d00a41SKrystof Tulinger                $window = $("<div>").
598d7d00a41SKrystof Tulinger                        addClass('window').
599d7d00a41SKrystof Tulinger                        addClass('diff_navigation_style').
600d7d00a41SKrystof Tulinger                        css('z-index', 15000).
601d7d00a41SKrystof Tulinger                        hide().
602d7d00a41SKrystof Tulinger                        append($header).
603d7d00a41SKrystof Tulinger                        append($body);
604d7d00a41SKrystof Tulinger
605d7d00a41SKrystof Tulinger                $close.click(function () {
606d7d00a41SKrystof Tulinger                    $window.hide();
607d7d00a41SKrystof Tulinger                    return false;
608d7d00a41SKrystof Tulinger                });
609d7d00a41SKrystof Tulinger
610d7d00a41SKrystof Tulinger                /**
611d7d00a41SKrystof Tulinger                 * Get the element for the window body.
612d7d00a41SKrystof Tulinger                 * This should be used to place your desired content.
613d7d00a41SKrystof Tulinger                 *
614d7d00a41SKrystof Tulinger                 * The returned object has a method {@code window()}
615d7d00a41SKrystof Tulinger                 * which returns the whole window.
616d7d00a41SKrystof Tulinger                 *
617d7d00a41SKrystof Tulinger                 * {@code $window} is equivalent to {@code $window.body().window()}
618d7d00a41SKrystof Tulinger                 *
619d7d00a41SKrystof Tulinger                 * @returns jQuery object of the window body
620d7d00a41SKrystof Tulinger                 */
621d7d00a41SKrystof Tulinger                $window.body = function () {
622d7d00a41SKrystof Tulinger                    $body.window = function () {
623d7d00a41SKrystof Tulinger                        return $window;
624d7d00a41SKrystof Tulinger                    };
625d7d00a41SKrystof Tulinger                    return $body;
626d7d00a41SKrystof Tulinger                };
627d7d00a41SKrystof Tulinger
628d7d00a41SKrystof Tulinger                /**
629d7d00a41SKrystof Tulinger                 * Display custom error message in the window
630d7d00a41SKrystof Tulinger                 * @param {string} msg message
631d7d00a41SKrystof Tulinger                 * @returns self
632d7d00a41SKrystof Tulinger                 */
633d7d00a41SKrystof Tulinger                $window.error = function (msg) {
634d7d00a41SKrystof Tulinger                    const $span = $("<p class='error'>" + msg + "</p>").
635d7d00a41SKrystof Tulinger                            animate({opacity: "0.2"}, 3000);
636d7d00a41SKrystof Tulinger                    $span.hide('slow', function () {
637d7d00a41SKrystof Tulinger                        $span.remove();
638d7d00a41SKrystof Tulinger                    });
639d7d00a41SKrystof Tulinger                    self.$errors.html($span);
640d7d00a41SKrystof Tulinger                    return this;
641d7d00a41SKrystof Tulinger                };
642d7d00a41SKrystof Tulinger
643d7d00a41SKrystof Tulinger                /**
644d7d00a41SKrystof Tulinger                 * Move the window to the position. If no position is given
645d7d00a41SKrystof Tulinger                 * it may be determined from the mouse position.
646d7d00a41SKrystof Tulinger                 *
647d7d00a41SKrystof Tulinger                 * @param {object} position object with top and left attributes
648d7d00a41SKrystof Tulinger                 * @returns self
649d7d00a41SKrystof Tulinger                 */
650d7d00a41SKrystof Tulinger                $window.move = function (position) {
651d7d00a41SKrystof Tulinger                    position = position || self.determinePosition();
652d7d00a41SKrystof Tulinger                    return this.css(position);
653d7d00a41SKrystof Tulinger                };
654d7d00a41SKrystof Tulinger
655d7d00a41SKrystof Tulinger                /**
656d7d00a41SKrystof Tulinger                 * Display or hide the window.
657d7d00a41SKrystof Tulinger                 *
658d7d00a41SKrystof Tulinger                 * We override this method from jquery to manually
659d7d00a41SKrystof Tulinger                 * trigger the hide() and show() methods
660d7d00a41SKrystof Tulinger                 * which may be used in the descendants.
661d7d00a41SKrystof Tulinger                 *
662d7d00a41SKrystof Tulinger                 * @returns self
663d7d00a41SKrystof Tulinger                 */
664d7d00a41SKrystof Tulinger                $window.toggle = function() {
665d7d00a41SKrystof Tulinger                    const action = this.is(':visible') ? this.hide : this.show;
666d7d00a41SKrystof Tulinger                    return action.apply(this, arguments);
667d7d00a41SKrystof Tulinger                };
668d7d00a41SKrystof Tulinger
669d7d00a41SKrystof Tulinger                /**
670d7d00a41SKrystof Tulinger                 * Toggle and move the window to the current mouse position
671d7d00a41SKrystof Tulinger                 *
672d7d00a41SKrystof Tulinger                 * @returns self
673d7d00a41SKrystof Tulinger                 */
674d7d00a41SKrystof Tulinger                $window.toggleAndMove = function () {
675d7d00a41SKrystof Tulinger                    return $window.toggle().move();
676d7d00a41SKrystof Tulinger                };
677d7d00a41SKrystof Tulinger
678d7d00a41SKrystof Tulinger                /**
679d7d00a41SKrystof Tulinger                 * Update the window with given data.
680d7d00a41SKrystof Tulinger                 *
681d7d00a41SKrystof Tulinger                 * @param {mixed} data
682d7d00a41SKrystof Tulinger                 * @returns {undefined}
683d7d00a41SKrystof Tulinger                 */
684d7d00a41SKrystof Tulinger                $window.update = function (data) {
685d7d00a41SKrystof Tulinger                    if (this.loaded) {
686d7d00a41SKrystof Tulinger                        self.fire('update', [data]);
687d7d00a41SKrystof Tulinger                    } else {
688d7d00a41SKrystof Tulinger                        self.pendingUpdates.push({data: data});
689d7d00a41SKrystof Tulinger                    }
690d7d00a41SKrystof Tulinger                    return this;
691d7d00a41SKrystof Tulinger                };
692d7d00a41SKrystof Tulinger
693d7d00a41SKrystof Tulinger                // insert window into context
694d7d00a41SKrystof Tulinger                this.context = $.extend(this.context, {$window: $window});
695d7d00a41SKrystof Tulinger
696d7d00a41SKrystof Tulinger                // set us as initialized
697d7d00a41SKrystof Tulinger                $window.initialized = true;
698d7d00a41SKrystof Tulinger                // set us as not loaded
699d7d00a41SKrystof Tulinger                $window.loaded = false;
700d7d00a41SKrystof Tulinger
701d7d00a41SKrystof Tulinger                return $window;
702d7d00a41SKrystof Tulinger            });
703d7d00a41SKrystof Tulinger
704d7d00a41SKrystof Tulinger            this.addCallback('load', function ($window) {
705d7d00a41SKrystof Tulinger                const that = this;
706d7d00a41SKrystof Tulinger                $(document).mousemove(function (e) {
707d7d00a41SKrystof Tulinger                    that.clientX = e.clientX;
708d7d00a41SKrystof Tulinger                    that.clientY = e.clientY;
709d7d00a41SKrystof Tulinger                });
710d7d00a41SKrystof Tulinger                $(document).keyup(function (e) {
711d7d00a41SKrystof Tulinger                    var key = e.keyCode;
712d7d00a41SKrystof Tulinger                    if (key === 27) { // esc
713d7d00a41SKrystof Tulinger                        that.$window.hide();
714d7d00a41SKrystof Tulinger                    }
715d7d00a41SKrystof Tulinger                    return true;
716d7d00a41SKrystof Tulinger                });
717d7d00a41SKrystof Tulinger            });
718d7d00a41SKrystof Tulinger
719d7d00a41SKrystof Tulinger            if (this.options.draggable) {
720d7d00a41SKrystof Tulinger                this.addCallback('load', this.makeMeDraggable);
721d7d00a41SKrystof Tulinger            }
722d7d00a41SKrystof Tulinger
723d7d00a41SKrystof Tulinger            this.addCallback('load', function ($window) {
724d7d00a41SKrystof Tulinger                this.$window.appendTo(this.options.parent ? $(this.options.parent) : $("body"));
725d7d00a41SKrystof Tulinger            });
726d7d00a41SKrystof Tulinger
727d7d00a41SKrystof Tulinger            if (this.options.init && typeof this.options.init === 'function') {
728d7d00a41SKrystof Tulinger                this.addCallback('init', this.options.init, this.getContext);
729d7d00a41SKrystof Tulinger            }
730d7d00a41SKrystof Tulinger
731d7d00a41SKrystof Tulinger            if (self.options.load && typeof self.options.load === 'function') {
732d7d00a41SKrystof Tulinger                this.addCallback('load', this.options.load, this.getContext);
733d7d00a41SKrystof Tulinger            }
734d7d00a41SKrystof Tulinger
735d7d00a41SKrystof Tulinger            if (self.options.update && typeof self.options.update === 'function') {
736d7d00a41SKrystof Tulinger                this.addCallback('update', this.options.update, this.getContext);
737d7d00a41SKrystof Tulinger            }
738d7d00a41SKrystof Tulinger
739d7d00a41SKrystof Tulinger            $(function () {
740d7d00a41SKrystof Tulinger                self.fire('load');
741d7d00a41SKrystof Tulinger                self.$window.loaded = true;
742d7d00a41SKrystof Tulinger
743d7d00a41SKrystof Tulinger                for (var i = 0; i < self.pendingUpdates.length; i++) {
744d7d00a41SKrystof Tulinger                    self.fire('update', [self.pendingUpdates[i].data]);
745d7d00a41SKrystof Tulinger                }
746d7d00a41SKrystof Tulinger                self.pendingUpdates = [];
747d7d00a41SKrystof Tulinger            });
748d7d00a41SKrystof Tulinger
749d7d00a41SKrystof Tulinger            this.fire('init');
750d7d00a41SKrystof Tulinger
751d7d00a41SKrystof Tulinger            return this.$window;
752d7d00a41SKrystof Tulinger        };
753d7d00a41SKrystof Tulinger
754d7d00a41SKrystof Tulinger        /**
755d7d00a41SKrystof Tulinger         * Create a window.
756d7d00a41SKrystof Tulinger         *
757d7d00a41SKrystof Tulinger         * @param {hash} options containing default options and callbacks
758d7d00a41SKrystof Tulinger         * @param {hash} context other helper variables and functions
759d7d00a41SKrystof Tulinger         * @returns new window object
760d7d00a41SKrystof Tulinger         */
761d7d00a41SKrystof Tulinger        this.create = function (options, context) {
762d7d00a41SKrystof Tulinger            return new Inner(options, context);
763d7d00a41SKrystof Tulinger        };
764d7d00a41SKrystof Tulinger    };
765d7d00a41SKrystof Tulinger    $.window = new ($.extend(window, $.window ? $.window : {}))();
766d7d00a41SKrystof Tulinger})(window, document, jQuery, jQuery.script);
767d7d00a41SKrystof Tulinger
768d7d00a41SKrystof Tulinger/**
769d7d00a41SKrystof Tulinger * Intelligence window plugin.
770d7d00a41SKrystof Tulinger *
771d7d00a41SKrystof Tulinger * Reworked to use Jquery in 2016
772d7d00a41SKrystof Tulinger */
773d7d00a41SKrystof Tulinger(function (browserWindow, document, $, $window) {
774d7d00a41SKrystof Tulinger    if (!$window || typeof $window.create !== 'function') {
775d7d00a41SKrystof Tulinger        console.log("The intelligenceWindow plugin requires $.window plugin");
776d7d00a41SKrystof Tulinger        return;
777d7d00a41SKrystof Tulinger    }
778d7d00a41SKrystof Tulinger
779d7d00a41SKrystof Tulinger    var intelliWindow = function () {
780d7d00a41SKrystof Tulinger        this.initialised = false;
781d7d00a41SKrystof Tulinger        this.init = function (options, context) {
782d7d00a41SKrystof Tulinger            $.intelliWindow = $window.create($.extend({
783d7d00a41SKrystof Tulinger                title: 'Intelligence window',
784d7d00a41SKrystof Tulinger                selector: 'a.intelliWindow-symbol',
785d7d00a41SKrystof Tulinger                google_url: 'https://www.google.com/search?q=',
786d7d00a41SKrystof Tulinger                project: undefined,
787d7d00a41SKrystof Tulinger                init: function ($window) {
788d7d00a41SKrystof Tulinger                    let $highlight, $unhighlight, $unhighlightAll, $prev, $next;
789d7d00a41SKrystof Tulinger
790d7d00a41SKrystof Tulinger                    let $firstList = $("<ul>").
791d7d00a41SKrystof Tulinger                            append($("<li>").append(
792d7d00a41SKrystof Tulinger                                    $highlight = $('<a href="#" title="Highlight">' +
793d7d00a41SKrystof Tulinger                                            '<span>Highlight</span> <b class="symbol-name"></b></a>'))).
794d7d00a41SKrystof Tulinger                            append($("<li>").append(
795d7d00a41SKrystof Tulinger                                    $unhighlight = $('<a href="#" title="Unhighlight">' +
796d7d00a41SKrystof Tulinger                                            '<span>Unhighlight</span> <b class="symbol-name"></b></a>'))).
797d7d00a41SKrystof Tulinger                            append($("<li>").append(
798d7d00a41SKrystof Tulinger                                    $unhighlightAll = $('<a href="#" title="Unhighlight all">' +
799d7d00a41SKrystof Tulinger                                            '<span>Unhighlight all</span></a>')));
800d7d00a41SKrystof Tulinger
801d7d00a41SKrystof Tulinger                    this.bindOnClick($highlight, this.highlight);
802d7d00a41SKrystof Tulinger                    this.bindOnClick($unhighlight, this.unhighlight);
803d7d00a41SKrystof Tulinger                    this.bindOnClick($unhighlightAll, this.unhighlightAll);
804d7d00a41SKrystof Tulinger
805d7d00a41SKrystof Tulinger                    let $secondList = $("<ul>").
806d7d00a41SKrystof Tulinger                            append($("<li>").append(
807d7d00a41SKrystof Tulinger                                    $('<a class="search-defs" href="#" target="_blank">' +
808d7d00a41SKrystof Tulinger                                            '<span>Search for definitions of</span> <b class="symbol-name"></b></a>'))).
809d7d00a41SKrystof Tulinger                            append($("<li>").append(
810d7d00a41SKrystof Tulinger                                    $('<a class="search-refs" href="#" target="_blank">' +
811d7d00a41SKrystof Tulinger                                            '<span>Search for references of</span> <b class="symbol-name"></b></a>'))).
812d7d00a41SKrystof Tulinger                            append($("<li>").append(
813d7d00a41SKrystof Tulinger                                    $('<a class="search-full" href="#" target="_blank">' +
814d7d00a41SKrystof Tulinger                                            '<span>Do a full search with</span> <b class="symbol-name"></b></a>'))).
815d7d00a41SKrystof Tulinger                            append($("<li>").append(
816d7d00a41SKrystof Tulinger                                    $('<a class="search-files" href="#" target="_blank">' +
817d7d00a41SKrystof Tulinger                                            '<span>Search for file names that contain</span> <b class="symbol-name"></b></a>')));
818d7d00a41SKrystof Tulinger
819d7d00a41SKrystof Tulinger                    let $thirdList = $("<ul>").
820d7d00a41SKrystof Tulinger                            append($("<li>").append(
821d7d00a41SKrystof Tulinger                                    $('<a class="search-google" href="#" target="_blank">' +
822d7d00a41SKrystof Tulinger                                            '<span>Google</span> <b class="symbol-name"></b></a>')));
823d7d00a41SKrystof Tulinger
824d7d00a41SKrystof Tulinger                    let $controls = $('<div class="pull-right">').
825d7d00a41SKrystof Tulinger                            append($next = $('<a href="#" title="next" class="pull-right">Next >></a>')).
826d7d00a41SKrystof Tulinger                            append('<span class="pull-right"> | </span>').
827d7d00a41SKrystof Tulinger                            append($prev = $('<a href="#" title="prev" class="pull-right"><< Prev </a>')).
828d7d00a41SKrystof Tulinger                            append($('<div class="clearfix">')).
829d7d00a41SKrystof Tulinger                            append(this.$errors = $('<span class="clearfix">'));
830d7d00a41SKrystof Tulinger
831d7d00a41SKrystof Tulinger                    this.bindOnClick($next, this.scrollToNextElement, 1);
832d7d00a41SKrystof Tulinger                    this.bindOnClick($prev, this.scrollToNextElement, -1);
833d7d00a41SKrystof Tulinger
834d7d00a41SKrystof Tulinger                    return $window.
835d7d00a41SKrystof Tulinger                            attr('id', 'intelli_win').
836d7d00a41SKrystof Tulinger                            addClass('intelli-window').
837d7d00a41SKrystof Tulinger                            body().
838d7d00a41SKrystof Tulinger                            append($controls).
839d7d00a41SKrystof Tulinger                            append($("<h2>").addClass('symbol-name')).
840d7d00a41SKrystof Tulinger                            append($("<span>").addClass('symbol-description')).
841d7d00a41SKrystof Tulinger                            append($("<hr>")).
842d7d00a41SKrystof Tulinger                            append($("<h5>").text("In current file")).
843d7d00a41SKrystof Tulinger                            append($firstList).
844d7d00a41SKrystof Tulinger                            append($("<h5>").text('In project "' + this.project + '"')).
845d7d00a41SKrystof Tulinger                            append($secondList).
846d7d00a41SKrystof Tulinger                            append($("<h5>").text("On Google")).
847d7d00a41SKrystof Tulinger                            append($thirdList).
848d7d00a41SKrystof Tulinger                            window();
849d7d00a41SKrystof Tulinger                },
850d7d00a41SKrystof Tulinger                load: function ($window) {
851d7d00a41SKrystof Tulinger                    const that = this;
852d7d00a41SKrystof Tulinger                    $(document).keypress(function (e) {
853d7d00a41SKrystof Tulinger                        if (textInputHasFocus()) {
854d7d00a41SKrystof Tulinger                            return true;
855d7d00a41SKrystof Tulinger                        }
856d7d00a41SKrystof Tulinger                        const key = e.which;
857d7d00a41SKrystof Tulinger                        switch (key) {
858d7d00a41SKrystof Tulinger                            case 49: // 1
859d7d00a41SKrystof Tulinger                                if (that.symbol) {
860d7d00a41SKrystof Tulinger                                    that.$window.toggleAndMove();
861d7d00a41SKrystof Tulinger                                }
862d7d00a41SKrystof Tulinger                                break;
863d7d00a41SKrystof Tulinger                            case 50: // 2
864d7d00a41SKrystof Tulinger                                if (that.symbol && that.unhighlight(that.symbol).length === 0) {
865d7d00a41SKrystof Tulinger                                     that.highlight(that.symbol, 1);
866d7d00a41SKrystof Tulinger                                }
867d7d00a41SKrystof Tulinger                                break;
868d7d00a41SKrystof Tulinger                            case 51: // 3
869d7d00a41SKrystof Tulinger                                if (that.symbol && that.unhighlight(that.symbol).length === 0) {
870d7d00a41SKrystof Tulinger                                     that.highlight(that.symbol, 2);
871d7d00a41SKrystof Tulinger                                }
872d7d00a41SKrystof Tulinger                                break;
873d7d00a41SKrystof Tulinger                            case 52: // 4
874d7d00a41SKrystof Tulinger                                if (that.symbol && that.unhighlight(that.symbol).length === 0) {
875d7d00a41SKrystof Tulinger                                     that.highlight(that.symbol, 3);
876d7d00a41SKrystof Tulinger                                }
877d7d00a41SKrystof Tulinger                                break;
878d7d00a41SKrystof Tulinger                            case 53: // 5
879d7d00a41SKrystof Tulinger                                if (that.symbol && that.unhighlight(that.symbol).length === 0) {
880d7d00a41SKrystof Tulinger                                    that.highlight(that.symbol, 4);
881d7d00a41SKrystof Tulinger                                }
882d7d00a41SKrystof Tulinger                                break;
883d7d00a41SKrystof Tulinger                            case 54: // 6
884d7d00a41SKrystof Tulinger                                if (that.symbol && that.unhighlight(that.symbol).length === 0) {
885d7d00a41SKrystof Tulinger                                    that.highlight(that.symbol, 5);
886d7d00a41SKrystof Tulinger                                }
887d7d00a41SKrystof Tulinger                                break;
888d7d00a41SKrystof Tulinger                            case 55: // 5
889d7d00a41SKrystof Tulinger                                if (that.symbol && that.unhighlight(that.symbol).length === 0) {
890d7d00a41SKrystof Tulinger                                    that.highlight(that.symbol, 6);
891d7d00a41SKrystof Tulinger                                }
892d7d00a41SKrystof Tulinger                                break;
893d7d00a41SKrystof Tulinger                            case 56: // 7
894d7d00a41SKrystof Tulinger                                that.unhighlightAll();
895d7d00a41SKrystof Tulinger                                break;
896d7d00a41SKrystof Tulinger                            case 110: // n
897d7d00a41SKrystof Tulinger                                that.scrollToNextElement(1);
898d7d00a41SKrystof Tulinger                                break;
899d7d00a41SKrystof Tulinger                            case 98: // b
900d7d00a41SKrystof Tulinger                                that.scrollToNextElement(-1);
901d7d00a41SKrystof Tulinger                                break;
902d7d00a41SKrystof Tulinger                            default:
903d7d00a41SKrystof Tulinger                        }
904d7d00a41SKrystof Tulinger                        return true;
905d7d00a41SKrystof Tulinger                    });
906d7d00a41SKrystof Tulinger                    this.getSymbols().mouseover(function () {
907d7d00a41SKrystof Tulinger                        that.changeSymbol($(this));
908d7d00a41SKrystof Tulinger                    });
909d7d00a41SKrystof Tulinger                    this.project = this.options.project || $("input[name='project']").val();
910d7d00a41SKrystof Tulinger                    this.contextPath = browserWindow.contextPath;
911d7d00a41SKrystof Tulinger                }
912d7d00a41SKrystof Tulinger            }, options || {}), $.extend({
913d7d00a41SKrystof Tulinger                symbol: undefined,
914d7d00a41SKrystof Tulinger                project: undefined,
915d7d00a41SKrystof Tulinger                $symbols: undefined,
916d7d00a41SKrystof Tulinger                $current: undefined,
917d7d00a41SKrystof Tulinger                $last_highlighted_current: $(),
918d7d00a41SKrystof Tulinger                $search_defs: undefined,
919d7d00a41SKrystof Tulinger                $search_refs: undefined,
920d7d00a41SKrystof Tulinger                $search_full: undefined,
921d7d00a41SKrystof Tulinger                $search_files: undefined,
922d7d00a41SKrystof Tulinger                $search_google: undefined,
923d7d00a41SKrystof Tulinger                changeSymbol: function ($el) {
924d7d00a41SKrystof Tulinger                    this.$current = $el;
925d7d00a41SKrystof Tulinger                    this.$last_highlighted_current = $el.hasClass("symbol-highlighted") ? $el : this.$last_highlighted_current;
926d7d00a41SKrystof Tulinger                    this.symbol = $el.text();
927d7d00a41SKrystof Tulinger                    this.place = $el.data("definition-place");
928d7d00a41SKrystof Tulinger                    this.$window.find('.hidden-on-start').show();
929d7d00a41SKrystof Tulinger                    this.$window.find(".symbol-name").text(this.symbol);
930d7d00a41SKrystof Tulinger                    this.$window.find(".symbol-description").text(this.getSymbolDescription(this.place));
931d7d00a41SKrystof Tulinger                    this.modifyLinks();
932d7d00a41SKrystof Tulinger                },
933d7d00a41SKrystof Tulinger                modifyLinks: function () {
934d7d00a41SKrystof Tulinger                    this.$search_defs = this.$search_defs || this.$window.find('.search-defs');
935d7d00a41SKrystof Tulinger                    this.$search_refs = this.$search_refs || this.$window.find('.search-refs');
936d7d00a41SKrystof Tulinger                    this.$search_full = this.$search_full || this.$window.find('.search-full');
937d7d00a41SKrystof Tulinger                    this.$search_files = this.$search_files || this.$window.find('.search-files');
938d7d00a41SKrystof Tulinger                    this.$search_google = this.$search_google || this.$window.find('.search-google');
939d7d00a41SKrystof Tulinger
940d7d00a41SKrystof Tulinger                    this.$search_defs.attr('href', this.getSearchLink('defs'));
941d7d00a41SKrystof Tulinger                    this.$search_refs.attr('href', this.getSearchLink('refs'));
942d7d00a41SKrystof Tulinger                    this.$search_full.attr('href', this.getSearchLink('full'));
943d7d00a41SKrystof Tulinger                    this.$search_files.attr('href', this.getSearchLink('path'));
944d7d00a41SKrystof Tulinger                    this.$search_google.attr('href', this.options.google_url + this.symbol);
945d7d00a41SKrystof Tulinger                },
946d7d00a41SKrystof Tulinger                getSearchLink: function (query) {
947d7d00a41SKrystof Tulinger                    return this.options.contextPath + '/search?' + query + '=' + this.symbol + '&project=' + this.project;
948d7d00a41SKrystof Tulinger                },
949d7d00a41SKrystof Tulinger                getSymbolDescription: function (place) {
950d7d00a41SKrystof Tulinger                    switch (place) {
951d7d00a41SKrystof Tulinger                        case "def":
952d7d00a41SKrystof Tulinger                            return "A declaration or definition.";
953d7d00a41SKrystof Tulinger                        case "defined-in-file":
954d7d00a41SKrystof Tulinger                            return "A symbol declared or defined in this file.";
955d7d00a41SKrystof Tulinger                        case "undefined-in-file":
956d7d00a41SKrystof Tulinger                            return "A symbol declared or defined elsewhere.";
957d7d00a41SKrystof Tulinger                        default:
958d7d00a41SKrystof Tulinger                            // should not happen
959d7d00a41SKrystof Tulinger                            return "Something I have no idea about.";
960d7d00a41SKrystof Tulinger                    }
961d7d00a41SKrystof Tulinger                },
962d7d00a41SKrystof Tulinger                getSymbols: function () {
963d7d00a41SKrystof Tulinger                    return (this.$symbols = this.$symbols || $(this.options.selector));
964d7d00a41SKrystof Tulinger                },
965d7d00a41SKrystof Tulinger                highlight: function (symbol, color) {
966d7d00a41SKrystof Tulinger                    if (this.$current.text() === symbol) {
967d7d00a41SKrystof Tulinger                        this.$last_highlighted_current = this.$current;
968d7d00a41SKrystof Tulinger                    }
969d7d00a41SKrystof Tulinger                    return this.getSymbols().filter(function () {
970d7d00a41SKrystof Tulinger                        return $(this).text() === symbol;
971d7d00a41SKrystof Tulinger                    }).addClass('symbol-highlighted').addClass('hightlight-color-' + (color || 1));
972d7d00a41SKrystof Tulinger                },
973d7d00a41SKrystof Tulinger                unhighlight: function (symbol) {
974d7d00a41SKrystof Tulinger                    if (this.$last_highlighted_current &&
975d7d00a41SKrystof Tulinger                            this.$last_highlighted_current.text() === symbol &&
976d7d00a41SKrystof Tulinger                            this.$last_highlighted_current.hasClass('symbol-highlighted')) {
977d7d00a41SKrystof Tulinger                        const i = this.getSymbols().index(this.$last_highlighted_current);
978d7d00a41SKrystof Tulinger                        this.$last_highlighted_jump = this.getSymbols().slice(0, i).filter('.symbol-highlighted').last();
979d7d00a41SKrystof Tulinger                    }
980d7d00a41SKrystof Tulinger                    return this.getSymbols().filter(".symbol-highlighted").filter(function () {
981d7d00a41SKrystof Tulinger                        return $(this).text() === symbol;
982d7d00a41SKrystof Tulinger                    }).removeClass('symbol-highlighted')
983d7d00a41SKrystof Tulinger                        .removeClass(function (index, className) {
984d7d00a41SKrystof Tulinger                            return (className.match(/(^|\s)hightlight-color-\S+/g) || []).join(' ');
985d7d00a41SKrystof Tulinger                        });
986d7d00a41SKrystof Tulinger                },
987d7d00a41SKrystof Tulinger                unhighlightAll: function () {
988d7d00a41SKrystof Tulinger                    this.$last_highlighted_current = undefined;
989d7d00a41SKrystof Tulinger                    return this.getSymbols().filter(".symbol-highlighted").
990d7d00a41SKrystof Tulinger                            removeClass("symbol-highlighted").
991d7d00a41SKrystof Tulinger                            removeClass(function (index, className) {
992d7d00a41SKrystof Tulinger                                return (className.match (/(^|\s)hightlight-color-\S+/g) || []).join(' ');
993d7d00a41SKrystof Tulinger                            });
994d7d00a41SKrystof Tulinger                },
995d7d00a41SKrystof Tulinger                scrollTop: function ($el) {
996d7d00a41SKrystof Tulinger                    if (this.options.scrollTop) {
997d7d00a41SKrystof Tulinger                        this.options.scrollTop($el);
998d7d00a41SKrystof Tulinger                    } else {
999d7d00a41SKrystof Tulinger                        $('html, body').stop().animate({
1000d7d00a41SKrystof Tulinger                            scrollTop: $el.offset().top - $("#src").offset().top
1001d7d00a41SKrystof Tulinger                        }, 500);
1002d7d00a41SKrystof Tulinger                    }
1003d7d00a41SKrystof Tulinger                },
1004d7d00a41SKrystof Tulinger                scrollToNextElement: function (direction) {
1005d7d00a41SKrystof Tulinger                    const UP = -1;
1006d7d00a41SKrystof Tulinger                    const DOWN = 1;
1007d7d00a41SKrystof Tulinger                    const $highlighted = this.getSymbols().filter(".symbol-highlighted");
1008d7d00a41SKrystof Tulinger                    let $el = $highlighted.length && this.$last_highlighted_current ? this.$last_highlighted_current : this.$current;
1009d7d00a41SKrystof Tulinger                    const indexOfCurrent = this.getSymbols().index($el);
1010d7d00a41SKrystof Tulinger
1011d7d00a41SKrystof Tulinger                    switch (direction) {
1012d7d00a41SKrystof Tulinger                        case DOWN:
1013d7d00a41SKrystof Tulinger                            $el = this.getSymbols().slice(indexOfCurrent + 1);
1014d7d00a41SKrystof Tulinger                            if ($highlighted.length) {
1015d7d00a41SKrystof Tulinger                                $el = $el.filter('.symbol-highlighted');
1016d7d00a41SKrystof Tulinger                            }
1017d7d00a41SKrystof Tulinger                            if (!$el.length) {
1018d7d00a41SKrystof Tulinger                                this.$window.error("This is the last occurence!");
1019d7d00a41SKrystof Tulinger                                return;
1020d7d00a41SKrystof Tulinger                            }
1021d7d00a41SKrystof Tulinger                            $el = $el.first();
1022d7d00a41SKrystof Tulinger                            break;
1023d7d00a41SKrystof Tulinger                        case UP:
1024d7d00a41SKrystof Tulinger                            $el = this.getSymbols().slice(0, indexOfCurrent);
1025d7d00a41SKrystof Tulinger                            if ($highlighted.length) {
1026d7d00a41SKrystof Tulinger                                $el = $el.filter('.symbol-highlighted');
1027d7d00a41SKrystof Tulinger                            }
1028d7d00a41SKrystof Tulinger                            if (!$el.length) {
1029d7d00a41SKrystof Tulinger                                this.$window.error("This is the first occurence!");
1030d7d00a41SKrystof Tulinger                                return;
1031d7d00a41SKrystof Tulinger                            }
1032d7d00a41SKrystof Tulinger                            $el = $el.last();
1033d7d00a41SKrystof Tulinger                            break;
1034d7d00a41SKrystof Tulinger                        default:
1035d7d00a41SKrystof Tulinger                            this.$window.error("Unknown direction");
1036d7d00a41SKrystof Tulinger                            return;
1037d7d00a41SKrystof Tulinger                    }
1038d7d00a41SKrystof Tulinger
1039d7d00a41SKrystof Tulinger                    this.scrollTop($el);
1040d7d00a41SKrystof Tulinger                    this.changeSymbol($el);
1041d7d00a41SKrystof Tulinger                },
1042d7d00a41SKrystof Tulinger                bindOnClick: function ($el, callback, param) {
1043d7d00a41SKrystof Tulinger                    const that = this;
1044d7d00a41SKrystof Tulinger                    $el.click(function (e) {
1045d7d00a41SKrystof Tulinger                        e.preventDefault();
1046d7d00a41SKrystof Tulinger                        callback.call(that, param || that.symbol);
1047d7d00a41SKrystof Tulinger                        return false;
1048d7d00a41SKrystof Tulinger                    });
1049d7d00a41SKrystof Tulinger                }
1050d7d00a41SKrystof Tulinger            }, context || {}));
1051d7d00a41SKrystof Tulinger            return $.intelliWindow;
1052d7d00a41SKrystof Tulinger        };
1053d7d00a41SKrystof Tulinger    };
1054d7d00a41SKrystof Tulinger    $.intelliWindow = new ($.extend(intelliWindow, $.intelliWindow ? $.intelliWindow : {}))();
1055d7d00a41SKrystof Tulinger})(window, document, jQuery, jQuery.window);
1056d7d00a41SKrystof Tulinger
1057d7d00a41SKrystof Tulinger/**
1058d7d00a41SKrystof Tulinger * Messages window plugin.
1059d7d00a41SKrystof Tulinger *
1060d7d00a41SKrystof Tulinger * @author Kryštof Tulinger
1061d7d00a41SKrystof Tulinger */
1062d7d00a41SKrystof Tulinger(function (browserWindow, document, $, $window) {
1063d7d00a41SKrystof Tulinger    if (!$window || typeof $window.create !== 'function') {
1064d7d00a41SKrystof Tulinger        console.log("The messagesWindow plugin requires $.window plugin");
1065d7d00a41SKrystof Tulinger        return;
1066d7d00a41SKrystof Tulinger    }
1067d7d00a41SKrystof Tulinger
1068d7d00a41SKrystof Tulinger    const messagesWindow = function () {
1069d7d00a41SKrystof Tulinger        this.init = function (options, context) {
1070d7d00a41SKrystof Tulinger            $.messagesWindow = $window.create($.extend({
1071d7d00a41SKrystof Tulinger                title: 'Messages Window',
1072d7d00a41SKrystof Tulinger                draggable: false,
1073d7d00a41SKrystof Tulinger                init: function ($window) {
1074d7d00a41SKrystof Tulinger                    return $window.
1075d7d00a41SKrystof Tulinger                            attr('id', 'messages_win').
1076d7d00a41SKrystof Tulinger                            addClass('messages-window').
1077d7d00a41SKrystof Tulinger                            addClass('diff_navigation_style').
1078d7d00a41SKrystof Tulinger                            css({top: '150px', right: '20px'}).
1079d7d00a41SKrystof Tulinger                            body().
1080d7d00a41SKrystof Tulinger                            append(this.$messages = $("<div>")).
1081d7d00a41SKrystof Tulinger                            window();
1082d7d00a41SKrystof Tulinger                },
1083d7d00a41SKrystof Tulinger                load: function ($window) {
1084d7d00a41SKrystof Tulinger                    $window.mouseenter(function () {
1085d7d00a41SKrystof Tulinger                        $window.show();
1086d7d00a41SKrystof Tulinger                    }).mouseleave(function () {
1087d7d00a41SKrystof Tulinger                        $window.hide();
1088d7d00a41SKrystof Tulinger                    });
1089d7d00a41SKrystof Tulinger
1090d7d00a41SKrystof Tulinger                    // simulate show/toggle and move
1091d7d00a41SKrystof Tulinger                    $.each(['show', 'toggle'], function () {
1092d7d00a41SKrystof Tulinger                        const old = $window[this];
1093d7d00a41SKrystof Tulinger                        $window[this] = function () {
1094d7d00a41SKrystof Tulinger                            return old.call($window).move();
1095d7d00a41SKrystof Tulinger                        };
1096d7d00a41SKrystof Tulinger                    });
1097d7d00a41SKrystof Tulinger                },
1098d7d00a41SKrystof Tulinger                update: function (data) {
1099d7d00a41SKrystof Tulinger                    this.$messages.empty();
1100d7d00a41SKrystof Tulinger                    for (let tag of data) {
1101d7d00a41SKrystof Tulinger                        if (!tag || tag.messages.length === 0) {
1102d7d00a41SKrystof Tulinger                            continue;
1103d7d00a41SKrystof Tulinger                        }
1104d7d00a41SKrystof Tulinger                        this.$messages.append($("<h5>").
1105d7d00a41SKrystof Tulinger                                addClass('message-group-caption').
1106d7d00a41SKrystof Tulinger                                text(tag.tag.charAt(0).toUpperCase() + tag.tag.slice(1)));
1107d7d00a41SKrystof Tulinger                        const $ul = $("<ul>").addClass('message-group limited');
1108d7d00a41SKrystof Tulinger                        for (let j = 0; j < tag.messages.length; j++) {
1109d7d00a41SKrystof Tulinger                            if (!tag.messages[j]) {
1110d7d00a41SKrystof Tulinger                                continue;
1111d7d00a41SKrystof Tulinger                            }
1112d7d00a41SKrystof Tulinger                            $ul.append(
1113d7d00a41SKrystof Tulinger                                $('<li>').
1114d7d00a41SKrystof Tulinger                                    addClass('message-group-item').
1115d7d00a41SKrystof Tulinger                                    addClass(tag.messages[j].messageLevel).
1116d7d00a41SKrystof Tulinger                                    attr('title', 'Expires on ' + tag.messages[j].expiration).
1117d7d00a41SKrystof Tulinger                                    html(tag.messages[j].created + ': ' + tag.messages[j].text)
1118d7d00a41SKrystof Tulinger                            );
1119d7d00a41SKrystof Tulinger                        }
1120d7d00a41SKrystof Tulinger                        this.$messages.append($ul);
1121d7d00a41SKrystof Tulinger                    }
1122d7d00a41SKrystof Tulinger                }
1123d7d00a41SKrystof Tulinger            }, options || {}), $.extend({
1124d7d00a41SKrystof Tulinger                $messages: $()
1125d7d00a41SKrystof Tulinger            }, context || {}));
1126d7d00a41SKrystof Tulinger            return $.messagesWindow;
1127d7d00a41SKrystof Tulinger        };
1128d7d00a41SKrystof Tulinger    };
1129d7d00a41SKrystof Tulinger    $.messagesWindow = new ($.extend(messagesWindow, $.messagesWindow ? $.messagesWindow : {}))();
1130d7d00a41SKrystof Tulinger})(window, document, jQuery, jQuery.window);
1131d7d00a41SKrystof Tulinger
1132d7d00a41SKrystof Tulinger/**
1133d7d00a41SKrystof Tulinger * Scopes window plugin.
1134d7d00a41SKrystof Tulinger *
1135d7d00a41SKrystof Tulinger * @author Kryštof Tulinger
1136d7d00a41SKrystof Tulinger */
1137d7d00a41SKrystof Tulinger(function (browserWindow, document, $, $window) {
1138d7d00a41SKrystof Tulinger    if (!$window || typeof $window.create !== 'function') {
1139d7d00a41SKrystof Tulinger        console.log("The scopesWindow plugin requires $.window plugin");
1140d7d00a41SKrystof Tulinger        return;
1141d7d00a41SKrystof Tulinger    }
1142d7d00a41SKrystof Tulinger
1143d7d00a41SKrystof Tulinger    const scopesWindow = function () {
1144d7d00a41SKrystof Tulinger        this.init = function (options, context) {
1145d7d00a41SKrystof Tulinger            $.scopesWindow = $window.create($.extend({
1146d7d00a41SKrystof Tulinger                title: 'Scopes Window',
1147d7d00a41SKrystof Tulinger                draggable: false,
1148d7d00a41SKrystof Tulinger                init: function ($window) {
1149d7d00a41SKrystof Tulinger                    return $window.
1150d7d00a41SKrystof Tulinger                            attr('id', 'scopes_win').
1151d7d00a41SKrystof Tulinger                            addClass('scopes-window').
1152d7d00a41SKrystof Tulinger                            addClass('diff_navigation_style').
1153d7d00a41SKrystof Tulinger                            css({top: '150px', right: '20px'}).
1154d7d00a41SKrystof Tulinger                            body().
1155d7d00a41SKrystof Tulinger                            append(this.$scopes = $("<div>")).
1156d7d00a41SKrystof Tulinger                            window();
1157d7d00a41SKrystof Tulinger                },
1158d7d00a41SKrystof Tulinger                load: function ($window) {
1159d7d00a41SKrystof Tulinger                    $window.hide().css('top', $("#content").offset().top + 10 + 'px');
1160d7d00a41SKrystof Tulinger
1161d7d00a41SKrystof Tulinger                    // override the hide and show to throw an event and run
1162d7d00a41SKrystof Tulinger                    // scope_on_scroll() for update
1163d7d00a41SKrystof Tulinger                    $.each(['hide', 'show'], function () {
1164d7d00a41SKrystof Tulinger                        const event = this;
1165d7d00a41SKrystof Tulinger                        const old = $window[event];
1166d7d00a41SKrystof Tulinger                        $window[event] = function () {
1167d7d00a41SKrystof Tulinger                            var $toReturn = old.call($window).trigger(event);
1168d7d00a41SKrystof Tulinger                            if (!scope_on_scroll || typeof scope_on_scroll !== 'function') {
1169d7d00a41SKrystof Tulinger                                console.debug("[scopesWindow]: The scope_on_scroll() is not a function at this point.");
1170d7d00a41SKrystof Tulinger                                return $toReturn;
1171d7d00a41SKrystof Tulinger                            }
1172d7d00a41SKrystof Tulinger                            scope_on_scroll();
1173d7d00a41SKrystof Tulinger                            return $toReturn;
1174d7d00a41SKrystof Tulinger                        };
1175d7d00a41SKrystof Tulinger                    });
1176d7d00a41SKrystof Tulinger
1177d7d00a41SKrystof Tulinger                    $('.scopes-toggle').click(function () {
1178d7d00a41SKrystof Tulinger                        $window.toggle();
1179d7d00a41SKrystof Tulinger                        return false;
1180d7d00a41SKrystof Tulinger                    });
1181d7d00a41SKrystof Tulinger                },
1182d7d00a41SKrystof Tulinger                update: function (data) {
1183d7d00a41SKrystof Tulinger                    if(!this.$window.is(':visible') && !this.$window.data('shown-once')) {
1184d7d00a41SKrystof Tulinger                        this.$window.show().data('shown-once', true);
1185d7d00a41SKrystof Tulinger                    }
1186d7d00a41SKrystof Tulinger                    this.$scopes.empty();
1187d7d00a41SKrystof Tulinger                    this.$scopes.html(this.buildLink(data.id, data.link));
1188d7d00a41SKrystof Tulinger                    this.$window.trigger('update');
1189d7d00a41SKrystof Tulinger                }
1190d7d00a41SKrystof Tulinger            }, options || {}), $.extend({
1191d7d00a41SKrystof Tulinger                $scopes: $(),
1192d7d00a41SKrystof Tulinger                buildLink: function (href, name) {
1193d7d00a41SKrystof Tulinger                    return $('<a>').attr('href', '#' + href).attr('title', name).html(name);
1194d7d00a41SKrystof Tulinger                }
1195d7d00a41SKrystof Tulinger            }, context || {}));
1196d7d00a41SKrystof Tulinger            return $.scopesWindow;
1197d7d00a41SKrystof Tulinger        };
1198d7d00a41SKrystof Tulinger    };
1199d7d00a41SKrystof Tulinger    $.scopesWindow = new ($.extend(scopesWindow, $.scopesWindow ? $.scopesWindow : {}))();
1200d7d00a41SKrystof Tulinger})(window, document, jQuery, jQuery.window);
1201d7d00a41SKrystof Tulinger
1202d7d00a41SKrystof Tulinger/**
1203d7d00a41SKrystof Tulinger * Navigate window plugin.
1204d7d00a41SKrystof Tulinger *
1205d7d00a41SKrystof Tulinger * @author Kryštof Tulinger
1206d7d00a41SKrystof Tulinger */
1207d7d00a41SKrystof Tulinger(function (browserWindow, document, $, $window) {
1208d7d00a41SKrystof Tulinger    if (!$window || typeof $window.create !== 'function') {
1209d7d00a41SKrystof Tulinger        console.log("The navigateWindow plugin requires $.window plugin");
1210d7d00a41SKrystof Tulinger        return;
1211d7d00a41SKrystof Tulinger    }
1212d7d00a41SKrystof Tulinger
1213d7d00a41SKrystof Tulinger    const navigateWindow = function () {
1214d7d00a41SKrystof Tulinger        this.init = function (options, context) {
1215d7d00a41SKrystof Tulinger            $.navigateWindow = $window.create($.extend({
1216d7d00a41SKrystof Tulinger                title: 'Navigate Window',
1217d7d00a41SKrystof Tulinger                draggable: false,
1218d7d00a41SKrystof Tulinger                init: function ($window) {
1219d7d00a41SKrystof Tulinger                    return $window.
1220d7d00a41SKrystof Tulinger                            attr('id', 'navigate_win').
1221d7d00a41SKrystof Tulinger                            addClass('navigate-window').
1222d7d00a41SKrystof Tulinger                            addClass('diff_navigation_style').
1223d7d00a41SKrystof Tulinger                            addClass('diff_navigation_style').
1224d7d00a41SKrystof Tulinger                            css({top: '150px', right: '20px', height: this.defaultHeight + 'px'}).
1225d7d00a41SKrystof Tulinger                            body().
1226d7d00a41SKrystof Tulinger                            append(this.$content).
1227d7d00a41SKrystof Tulinger                            window();
1228d7d00a41SKrystof Tulinger                },
1229d7d00a41SKrystof Tulinger                load: function ($window) {
1230d7d00a41SKrystof Tulinger                    const that = this;
1231d7d00a41SKrystof Tulinger                    $window.css('top', this.getTopOffset() + 10 + 'px');
1232d7d00a41SKrystof Tulinger
1233d7d00a41SKrystof Tulinger                    if ($.scopesWindow && $.scopesWindow.initialized) {
1234d7d00a41SKrystof Tulinger                        $.scopesWindow.on('show', function () {
1235d7d00a41SKrystof Tulinger                            setTimeout(function () {
1236d7d00a41SKrystof Tulinger                                that.updatePosition($window);
1237d7d00a41SKrystof Tulinger                            }, 100);
1238d7d00a41SKrystof Tulinger                        }).on('hide', function () {
1239d7d00a41SKrystof Tulinger                            that.updatePosition($window);
1240d7d00a41SKrystof Tulinger                        }).on('update', function () {
1241d7d00a41SKrystof Tulinger                            that.updatePosition($window);
1242d7d00a41SKrystof Tulinger                        });
1243d7d00a41SKrystof Tulinger
1244d7d00a41SKrystof Tulinger                        if ($.scopesWindow.is(':visible')) {
1245d7d00a41SKrystof Tulinger                            setTimeout(function () {
1246d7d00a41SKrystof Tulinger                                that.updatePosition($window);
1247d7d00a41SKrystof Tulinger                            }, 100);
1248d7d00a41SKrystof Tulinger                        }
1249d7d00a41SKrystof Tulinger                    }
1250d7d00a41SKrystof Tulinger
1251d7d00a41SKrystof Tulinger                    if ($('[data-navigate-window-enabled="true"]').length) {
1252d7d00a41SKrystof Tulinger                        $window.show();
1253d7d00a41SKrystof Tulinger                    }
1254d7d00a41SKrystof Tulinger
1255d7d00a41SKrystof Tulinger                    // override and show to throw an event and update position
1256d7d00a41SKrystof Tulinger                    $.each(['show'], function () {
1257d7d00a41SKrystof Tulinger                        const event = this;
1258d7d00a41SKrystof Tulinger                        const old = $window[event];
1259d7d00a41SKrystof Tulinger                        $window[event] = function () {
1260d7d00a41SKrystof Tulinger                            return that.updatePosition(old.call($window).trigger(event));
1261d7d00a41SKrystof Tulinger                        };
1262d7d00a41SKrystof Tulinger                    });
1263d7d00a41SKrystof Tulinger
1264d7d00a41SKrystof Tulinger                    $(browserWindow).resize(function () {
1265d7d00a41SKrystof Tulinger                        that.updatePosition($window);
1266d7d00a41SKrystof Tulinger                    });
1267d7d00a41SKrystof Tulinger                    that.updatePosition($window);
1268d7d00a41SKrystof Tulinger                },
1269d7d00a41SKrystof Tulinger                update: function (data) {
1270d7d00a41SKrystof Tulinger                    let $ul;
1271d7d00a41SKrystof Tulinger                    this.$content.empty();
1272d7d00a41SKrystof Tulinger                    for (let i = 0; i < data.length; i++) {
1273d7d00a41SKrystof Tulinger                        this.$content.append($('<h4>').text(data[i][0]));
1274d7d00a41SKrystof Tulinger                        if (data[i][2].length === 0) {
1275d7d00a41SKrystof Tulinger                            continue;
1276d7d00a41SKrystof Tulinger                        }
1277d7d00a41SKrystof Tulinger                        this.$content.append($ul = $('<ul>'));
1278d7d00a41SKrystof Tulinger                        for (let j = 0; j < data[i][2].length; j++) {
1279d7d00a41SKrystof Tulinger                            $ul.append($('<li>').append(this.buildLink(data[i][2][j][1], data[i][2][j][0], data[i][1])));
1280d7d00a41SKrystof Tulinger                        }
1281d7d00a41SKrystof Tulinger                    }
1282d7d00a41SKrystof Tulinger                    this.updatePosition(this.$window);
1283d7d00a41SKrystof Tulinger                }
1284d7d00a41SKrystof Tulinger            }, options || {
1285d7d00a41SKrystof Tulinger            }), $.extend({
1286d7d00a41SKrystof Tulinger                $content: $('<div>'),
1287d7d00a41SKrystof Tulinger                defaultHeight: 480,
1288d7d00a41SKrystof Tulinger                buildLink: function (href, name, c) {
1289d7d00a41SKrystof Tulinger                    return $('<a>').attr('href', '#' + href).attr('title', this.escapeHtml(name)).addClass(c).html(this.escapeHtml(name)).click(lnshow);
1290d7d00a41SKrystof Tulinger                },
1291d7d00a41SKrystof Tulinger                getTopOffset: function () {
1292d7d00a41SKrystof Tulinger                    return $("#content").offset().top;
1293d7d00a41SKrystof Tulinger                },
1294d7d00a41SKrystof Tulinger                updatePosition: function ($w) {
1295d7d00a41SKrystof Tulinger                    if (!$w.is(':visible')) {
1296d7d00a41SKrystof Tulinger                        /**
1297d7d00a41SKrystof Tulinger                         * If the window is not visible then this
1298d7d00a41SKrystof Tulinger                         * function is expensive as
1299d7d00a41SKrystof Tulinger                         * <a href="http://api.jquery.com/outerheight/">documented</a>
1300d7d00a41SKrystof Tulinger                         * under additional notes.
1301d7d00a41SKrystof Tulinger                         */
1302d7d00a41SKrystof Tulinger                        return $w;
1303d7d00a41SKrystof Tulinger                    }
1304d7d00a41SKrystof Tulinger
1305d7d00a41SKrystof Tulinger                    const a = {};
1306d7d00a41SKrystof Tulinger                    a.top = this.getTopOffset() + 10;
1307d7d00a41SKrystof Tulinger                    if ($.scopesWindow &&
1308d7d00a41SKrystof Tulinger                            $.scopesWindow.initialized &&
1309d7d00a41SKrystof Tulinger                            $.scopesWindow.is(':visible')) {
1310d7d00a41SKrystof Tulinger                        a.top = $.scopesWindow.position().top + $.scopesWindow.outerHeight() + 20;
1311d7d00a41SKrystof Tulinger                    }
1312d7d00a41SKrystof Tulinger                    a.height = Math.min(parseFloat($w.css('max-height')) || this.defaultHeight, $(browserWindow).outerHeight() - a.top - ($w.outerHeight(true) - $w.height()) - 20);
1313d7d00a41SKrystof Tulinger
1314d7d00a41SKrystof Tulinger                    if (a.height == $w.height() && a.top == this.getTopOffset()) {
1315d7d00a41SKrystof Tulinger                        return $w;
1316d7d00a41SKrystof Tulinger                    }
1317d7d00a41SKrystof Tulinger
1318d7d00a41SKrystof Tulinger                    if (this.$content.children().length === 0) {
1319d7d00a41SKrystof Tulinger                        // the window is empty
1320d7d00a41SKrystof Tulinger                        delete a.height;
1321d7d00a41SKrystof Tulinger                    }
1322d7d00a41SKrystof Tulinger
1323d7d00a41SKrystof Tulinger                    return $w.stop().animate(a);
1324d7d00a41SKrystof Tulinger                },
1325d7d00a41SKrystof Tulinger                escapeHtml: function (html) {
1326d7d00a41SKrystof Tulinger                    return html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1327d7d00a41SKrystof Tulinger                }
1328d7d00a41SKrystof Tulinger            }, context || {}));
1329d7d00a41SKrystof Tulinger            return $.navigateWindow;
1330d7d00a41SKrystof Tulinger        };
1331d7d00a41SKrystof Tulinger    };
1332d7d00a41SKrystof Tulinger    $.navigateWindow = new ($.extend(navigateWindow, $.navigateWindow ? $.navigateWindow : {}))();
1333d7d00a41SKrystof Tulinger})(window, document, jQuery, jQuery.window);
1334d7d00a41SKrystof Tulinger
1335d7d00a41SKrystof Tulingerfunction init_scopes() {
1336d7d00a41SKrystof Tulinger    $.scopesWindow.init();
1337d7d00a41SKrystof Tulinger    $(window).scroll(scope_on_scroll);
1338d7d00a41SKrystof Tulinger}
1339d7d00a41SKrystof Tulinger
1340d7d00a41SKrystof Tulingerfunction init_results_autohide() {
1341d7d00a41SKrystof Tulinger    $("#sbox input[type='submit']").click(function (e) {
1342d7d00a41SKrystof Tulinger        $("#footer").not(".main_page").hide(); // footer
1343d7d00a41SKrystof Tulinger        $("#results > .message-group").hide(); // messages
1344d7d00a41SKrystof Tulinger        $("#results > p.suggestions").hide(); // suggestions
1345d7d00a41SKrystof Tulinger        $("#results > p.pagetitle").hide(); // description
1346d7d00a41SKrystof Tulinger        $("#results > p.slider").hide(); // pagination
1347d7d00a41SKrystof Tulinger        $("#results > h3").hide(); // error
1348d7d00a41SKrystof Tulinger        $("#results > table, #results > ul").hide(); // results + empty
1349d7d00a41SKrystof Tulinger        $("#results > table + p, #results > ul + p").hide(); // results + empty timing
1350d7d00a41SKrystof Tulinger    });
1351d7d00a41SKrystof Tulinger}
1352d7d00a41SKrystof Tulinger
1353d7d00a41SKrystof Tulingerfunction init_searchable_option_list() {
1354d7d00a41SKrystof Tulinger    function init_sol_on_type_combobox() {
1355d7d00a41SKrystof Tulinger        const $type = $('#type');
1356d7d00a41SKrystof Tulinger        if ($type.length === 0) {
1357d7d00a41SKrystof Tulinger            return;
1358d7d00a41SKrystof Tulinger        }
1359d7d00a41SKrystof Tulinger        /**
1360d7d00a41SKrystof Tulinger         * Has to be here because otherwise the offset()
1361d7d00a41SKrystof Tulinger         * takes the original long &lt;select&gt; box and the max-height
1362d7d00a41SKrystof Tulinger         * does not work then.
1363d7d00a41SKrystof Tulinger         */
1364d7d00a41SKrystof Tulinger        $type.searchableOptionList({
1365d7d00a41SKrystof Tulinger            texts: {
1366d7d00a41SKrystof Tulinger                searchplaceholder: 'Click here to restrict the file type'
1367d7d00a41SKrystof Tulinger            },
1368d7d00a41SKrystof Tulinger            maxHeight: $type.offset().top + 'px',
1369d7d00a41SKrystof Tulinger            /**
1370d7d00a41SKrystof Tulinger             * Defined in menu.jsp just next to the original &lt;select&gt;
1371d7d00a41SKrystof Tulinger             */
1372d7d00a41SKrystof Tulinger            resultsContainer: $("#type-select-container")
1373d7d00a41SKrystof Tulinger        });
1374d7d00a41SKrystof Tulinger    }
1375d7d00a41SKrystof Tulinger    const searchableOptionListOptions = {
1376d7d00a41SKrystof Tulinger        maxHeight: '300px',
1377d7d00a41SKrystof Tulinger        showSelectionBelowList: false,
1378d7d00a41SKrystof Tulinger        showSelectAll: false,
1379d7d00a41SKrystof Tulinger        maxShow: 30,
1380d7d00a41SKrystof Tulinger        resultsContainer: $("#ltbl"),
1381d7d00a41SKrystof Tulinger        numSelectedItem: $("#nn"),
1382d7d00a41SKrystof Tulinger        quickDeleteForm: $("#sbox"),
1383d7d00a41SKrystof Tulinger        quickDeletePermit: checkIsOnSearchPage,
1384d7d00a41SKrystof Tulinger        texts: {
1385d7d00a41SKrystof Tulinger            searchplaceholder: 'Click here to select project(s)'
1386d7d00a41SKrystof Tulinger        },
1387d7d00a41SKrystof Tulinger        events: {
1388d7d00a41SKrystof Tulinger            onInitialized: function () {
1389d7d00a41SKrystof Tulinger                if ($.messagesWindow.initialized) {
1390d7d00a41SKrystof Tulinger                    this.$selectionContainer.find("[data-messages]").mouseenter(function () {
1391d7d00a41SKrystof Tulinger                        var data = $(this).data('messages') || [];
1392d7d00a41SKrystof Tulinger                        $.messagesWindow.update(data);
1393d7d00a41SKrystof Tulinger                        $.messagesWindow.show();
1394d7d00a41SKrystof Tulinger                    }).mouseleave(function (e) {
1395d7d00a41SKrystof Tulinger                        $.messagesWindow.hide();
1396d7d00a41SKrystof Tulinger                    });
1397d7d00a41SKrystof Tulinger                }
1398d7d00a41SKrystof Tulinger            },
1399d7d00a41SKrystof Tulinger            // override the default onScroll positioning event if necessary
1400d7d00a41SKrystof Tulinger            onScroll: function () {
1401d7d00a41SKrystof Tulinger
1402d7d00a41SKrystof Tulinger                const posY = this.$input.offset().top - this.config.scrollTarget.scrollTop() + this.$input.outerHeight() + 1;
1403d7d00a41SKrystof Tulinger                let selectionContainerWidth = this.$innerContainer.outerWidth(false) - parseInt(this.$selectionContainer.css('border-left-width'), 10) - parseInt(this.$selectionContainer.css('border-right-width'), 10);
1404d7d00a41SKrystof Tulinger
1405d7d00a41SKrystof Tulinger                if (this.$innerContainer.css('display') !== 'block') {
1406d7d00a41SKrystof Tulinger                    // container has a certain width
1407d7d00a41SKrystof Tulinger                    // make selection container a bit wider
1408d7d00a41SKrystof Tulinger                    selectionContainerWidth = Math.ceil(selectionContainerWidth * 1.2);
1409d7d00a41SKrystof Tulinger                } else {
1410d7d00a41SKrystof Tulinger                    // no border radius on top
1411d7d00a41SKrystof Tulinger                    this.$selectionContainer.css('border-top-right-radius', 'initial');
1412d7d00a41SKrystof Tulinger
1413d7d00a41SKrystof Tulinger                    if (this.$actionButtons) {
1414d7d00a41SKrystof Tulinger                        this.$actionButtons.css('border-top-right-radius', 'initial');
1415d7d00a41SKrystof Tulinger                    }
1416d7d00a41SKrystof Tulinger                }
1417d7d00a41SKrystof Tulinger
1418d7d00a41SKrystof Tulinger                this.$selectionContainer.
1419d7d00a41SKrystof Tulinger                        css('top', Math.floor(posY)).
1420d7d00a41SKrystof Tulinger                        css('left', Math.floor(this.$container.offset().left)).
1421d7d00a41SKrystof Tulinger                        css('width', selectionContainerWidth);
1422d7d00a41SKrystof Tulinger            },
1423d7d00a41SKrystof Tulinger            onRendered: init_sol_on_type_combobox
1424d7d00a41SKrystof Tulinger        }
1425d7d00a41SKrystof Tulinger    };
1426d7d00a41SKrystof Tulinger
1427d7d00a41SKrystof Tulinger    const $project = $('#project');
1428d7d00a41SKrystof Tulinger    if ($project.length === 1) {
1429d7d00a41SKrystof Tulinger        $project.searchableOptionList(searchableOptionListOptions);
1430d7d00a41SKrystof Tulinger    } else {
1431d7d00a41SKrystof Tulinger        init_sol_on_type_combobox();
1432d7d00a41SKrystof Tulinger    }
1433d7d00a41SKrystof Tulinger}
1434d7d00a41SKrystof Tulinger
1435d7d00a41SKrystof Tulingerfunction init_history_input() {
1436d7d00a41SKrystof Tulinger    $('input[data-revision-path]').click(function () {
1437d7d00a41SKrystof Tulinger        const $this = $(this);
1438d7d00a41SKrystof Tulinger        $("a.more").each(function () {
1439d7d00a41SKrystof Tulinger            $(this).attr('href', setParameter($(this).attr('href'), 'r1', $this.data('revision-1')));
1440d7d00a41SKrystof Tulinger            $(this).attr('href', setParameter($(this).attr('href'), 'r2', $this.data('revision-2')));
1441d7d00a41SKrystof Tulinger        });
1442d7d00a41SKrystof Tulinger
1443d7d00a41SKrystof Tulinger        const $revisions = $('input[data-revision-path]');
1444d7d00a41SKrystof Tulinger
1445d7d00a41SKrystof Tulinger        // change the correct revision on every element
1446d7d00a41SKrystof Tulinger        // (every element keeps a track which revision is selected)
1447d7d00a41SKrystof Tulinger        $revisions.filter("[data-diff-revision='r1']").data('revision-2', $this.data('revision-2'));
1448d7d00a41SKrystof Tulinger        $revisions.filter("[data-diff-revision='r2']").data('revision-1', $this.data('revision-1'));
1449d7d00a41SKrystof Tulinger
1450d7d00a41SKrystof Tulinger        // set the correct revision for the form submission
1451d7d00a41SKrystof Tulinger        $("#input_" + $this.data('diff-revision')).val($this.data('revision-path'));
1452d7d00a41SKrystof Tulinger
1453d7d00a41SKrystof Tulinger        // enable all input
1454d7d00a41SKrystof Tulinger        $revisions.prop('disabled', false);
1455d7d00a41SKrystof Tulinger        // uncheck all input in my column
1456d7d00a41SKrystof Tulinger        $revisions.filter("[data-diff-revision='" + $this.data('diff-revision') + "']").prop('checked', false);
1457d7d00a41SKrystof Tulinger        // set me as checked
1458d7d00a41SKrystof Tulinger        $this.prop('checked', true);
1459d7d00a41SKrystof Tulinger
1460d7d00a41SKrystof Tulinger        // disable from top to r2
1461d7d00a41SKrystof Tulinger        let index = Math.max($revisions.index($("input[data-revision-path][data-diff-revision='r2']:checked")), 0);
1462d7d00a41SKrystof Tulinger        $revisions.slice(0, index).filter("[data-diff-revision='r1']").prop('disabled', true);
1463d7d00a41SKrystof Tulinger
1464d7d00a41SKrystof Tulinger        // disable from bottom to r1
1465d7d00a41SKrystof Tulinger        index = Math.max($revisions.index($("input[data-revision-path][data-diff-revision='r1']:checked")), index);
1466d7d00a41SKrystof Tulinger        $revisions.slice(index + 1).filter("[data-diff-revision='r2']").prop('disabled', true);
1467d7d00a41SKrystof Tulinger    });
1468d7d00a41SKrystof Tulinger}
1469d7d00a41SKrystof Tulinger
1470d7d00a41SKrystof Tulingerfunction init_tablesorter() {
1471d7d00a41SKrystof Tulinger    $("#dirlist").tablesorter({
1472d7d00a41SKrystof Tulinger        sortList: [[0, 0]],
1473d7d00a41SKrystof Tulinger        cancelSelection: true,
1474d7d00a41SKrystof Tulinger        sortReset : true,
1475d7d00a41SKrystof Tulinger        sortRestart : true,
1476d7d00a41SKrystof Tulinger        sortInitialOrder: "desc",
1477d7d00a41SKrystof Tulinger        headers: {
1478d7d00a41SKrystof Tulinger            1: {
1479d7d00a41SKrystof Tulinger                sorter: 'text',
1480d7d00a41SKrystof Tulinger                sortInitialOrder: "asc"
1481d7d00a41SKrystof Tulinger            },
1482d7d00a41SKrystof Tulinger            3: {
1483d7d00a41SKrystof Tulinger                sorter: 'dates'
1484d7d00a41SKrystof Tulinger            },
1485d7d00a41SKrystof Tulinger            4: {
1486d7d00a41SKrystof Tulinger                sorter: 'groksizes'
1487d7d00a41SKrystof Tulinger            }
1488d7d00a41SKrystof Tulinger        }
1489d7d00a41SKrystof Tulinger    });
1490d7d00a41SKrystof Tulinger}
1491d7d00a41SKrystof Tulinger
1492d7d00a41SKrystof Tulingerfunction init_markdown_converter() {
1493d7d00a41SKrystof Tulinger    let converter = null;
1494d7d00a41SKrystof Tulinger    $('[data-markdown]').each(function () {
1495d7d00a41SKrystof Tulinger        var $that = $(this);
1496d7d00a41SKrystof Tulinger        $.script.loadScript('webjars/xss/1.0.8/dist/xss.min.js').done(function () {
1497d7d00a41SKrystof Tulinger            $.script.loadScript('webjars/showdown/1.9.1/dist/showdown.min.js').done(function () {
1498d7d00a41SKrystof Tulinger                $that.find('.markdown-content[data-markdown-download]').each(function () {
1499d7d00a41SKrystof Tulinger                    var $dataMarkdownDownloadEl = $(this);
1500d7d00a41SKrystof Tulinger                    if (converter === null) {
1501d7d00a41SKrystof Tulinger                        converter = new showdown.Converter();
1502d7d00a41SKrystof Tulinger                        converter.setOption('tables', true);
1503d7d00a41SKrystof Tulinger                        converter.setOption('strikethrough', true);
1504d7d00a41SKrystof Tulinger                        converter.setOption('tasklists', true);
1505d7d00a41SKrystof Tulinger                        converter.setOption('simplifiedAutoLink', true);
1506d7d00a41SKrystof Tulinger                        converter.setOption('parseImgDimension', true);
1507d7d00a41SKrystof Tulinger                        converter.setOption('literalMidWordUnderscores', true);
1508d7d00a41SKrystof Tulinger                    }
1509d7d00a41SKrystof Tulinger
1510d7d00a41SKrystof Tulinger                    $.ajax({
1511d7d00a41SKrystof Tulinger                        url: $(this).data('markdown-download'),
1512d7d00a41SKrystof Tulinger                        dataType: 'text',
1513d7d00a41SKrystof Tulinger                        timeout: 5000,
1514d7d00a41SKrystof Tulinger                        mimeType: 'text/plain'
1515d7d00a41SKrystof Tulinger                    }).done(function (payload) {
1516d7d00a41SKrystof Tulinger                        $dataMarkdownDownloadEl.html(filterXSS(converter.makeHtml(payload))).show();
1517d7d00a41SKrystof Tulinger                        $that.addClass('markdown').find('[data-markdown-original]').hide();
1518d7d00a41SKrystof Tulinger                    });
1519d7d00a41SKrystof Tulinger                });
1520d7d00a41SKrystof Tulinger            });
1521d7d00a41SKrystof Tulinger        });
1522d7d00a41SKrystof Tulinger    });
1523d7d00a41SKrystof Tulinger}
1524d7d00a41SKrystof Tulinger
1525d7d00a41SKrystof Tulingerwindow.onload = function () {
1526d7d00a41SKrystof Tulinger    for (let i in document.pageReady) {
1527d7d00a41SKrystof Tulinger        document.pageReady[i]();
1528d7d00a41SKrystof Tulinger    }
1529d7d00a41SKrystof Tulinger};
1530d7d00a41SKrystof Tulinger
1531d7d00a41SKrystof Tulinger$(document).ready(function () {
1532d7d00a41SKrystof Tulinger    for (let i in this.domReady) {
1533d7d00a41SKrystof Tulinger        document.domReady[i]();
1534d7d00a41SKrystof Tulinger    }
1535d7d00a41SKrystof Tulinger
1536d7d00a41SKrystof Tulinger    /**
1537d7d00a41SKrystof Tulinger     * Initialize scope scroll event to display scope information correctly when
1538d7d00a41SKrystof Tulinger     * the element comes into the viewport.
1539d7d00a41SKrystof Tulinger     */
1540d7d00a41SKrystof Tulinger    $('#src').each(function () {
1541d7d00a41SKrystof Tulinger        init_scopes();
1542d7d00a41SKrystof Tulinger    });
1543d7d00a41SKrystof Tulinger
1544d7d00a41SKrystof Tulinger    /**
1545d7d00a41SKrystof Tulinger     * Initialize table sorter on every directory listing.
1546d7d00a41SKrystof Tulinger     */
1547d7d00a41SKrystof Tulinger    init_tablesorter();
1548d7d00a41SKrystof Tulinger
1549d7d00a41SKrystof Tulinger    /**
1550d7d00a41SKrystof Tulinger     * Initialize intelligence window plugin. Presence of #contextpath indicates
1551d7d00a41SKrystof Tulinger     * that we use the code view.
1552d7d00a41SKrystof Tulinger     */
1553d7d00a41SKrystof Tulinger    $("#contextpath").each(function () {
1554d7d00a41SKrystof Tulinger        $.intelliWindow.init();
1555d7d00a41SKrystof Tulinger        return false;
1556d7d00a41SKrystof Tulinger    });
1557d7d00a41SKrystof Tulinger
1558d7d00a41SKrystof Tulinger    /**
1559d7d00a41SKrystof Tulinger     * Initialize the messages plugin to display
1560d7d00a41SKrystof Tulinger     * message onhover on every affected element.
1561d7d00a41SKrystof Tulinger     */
1562d7d00a41SKrystof Tulinger    $.messagesWindow.init();
1563d7d00a41SKrystof Tulinger
1564d7d00a41SKrystof Tulinger    /**
1565d7d00a41SKrystof Tulinger     * Attaches a onhover listener to display messages for affected elements.
1566d7d00a41SKrystof Tulinger     */
1567d7d00a41SKrystof Tulinger    if ($.messagesWindow.initialized) {
1568d7d00a41SKrystof Tulinger        $("[data-messages]").mouseenter(function () {
1569d7d00a41SKrystof Tulinger            const data = $(this).data('messages') || [];
1570d7d00a41SKrystof Tulinger            $.messagesWindow.update(data);
1571d7d00a41SKrystof Tulinger            $.messagesWindow.show();
1572d7d00a41SKrystof Tulinger        }).mouseleave(function (e) {
1573d7d00a41SKrystof Tulinger            $.messagesWindow.hide();
1574d7d00a41SKrystof Tulinger        });
1575d7d00a41SKrystof Tulinger    }
1576d7d00a41SKrystof Tulinger
1577d7d00a41SKrystof Tulinger    /**
1578d7d00a41SKrystof Tulinger     * Initialize spaces plugin which automatically inserts a single space between
1579d7d00a41SKrystof Tulinger     * the line number and the following text. It strongly relies on the fact
1580d7d00a41SKrystof Tulinger     * that the line numbers are stored in 'name' attribute on each line link.
1581d7d00a41SKrystof Tulinger     */
1582d7d00a41SKrystof Tulinger    $.spaces.init();
1583d7d00a41SKrystof Tulinger
1584d7d00a41SKrystof Tulinger    /**
1585d7d00a41SKrystof Tulinger     * Initialize the window hash management. Mainly this allows users to select
1586d7d00a41SKrystof Tulinger     * multiple lines of code and use that url to send it to somebody else.
1587d7d00a41SKrystof Tulinger     */
1588d7d00a41SKrystof Tulinger    $.hash.init({parent: "pre"});
1589d7d00a41SKrystof Tulinger
1590d7d00a41SKrystof Tulinger    /**
1591d7d00a41SKrystof Tulinger     * After hitting the search button, the results or projects are temporarily hidden
1592d7d00a41SKrystof Tulinger     * until the new page is loaded. That helps to distinguish if search is being in process.
1593d7d00a41SKrystof Tulinger     */
1594d7d00a41SKrystof Tulinger    init_results_autohide();
1595d7d00a41SKrystof Tulinger
1596d7d00a41SKrystof Tulinger    /**
1597d7d00a41SKrystof Tulinger     * Initialize the new project picker
1598d7d00a41SKrystof Tulinger     */
1599d7d00a41SKrystof Tulinger    init_searchable_option_list();
1600d7d00a41SKrystof Tulinger
1601d7d00a41SKrystof Tulinger    /**
1602d7d00a41SKrystof Tulinger     * Initialize the history input picker.
1603d7d00a41SKrystof Tulinger     * Checkboxes are automatically covered with a click event and automatically
1604d7d00a41SKrystof Tulinger     * colored as disabled or checked.
1605d7d00a41SKrystof Tulinger     *
1606d7d00a41SKrystof Tulinger     * Also works for paging where it stores the actual selected revision range in the
1607d7d00a41SKrystof Tulinger     * pagination links.
1608d7d00a41SKrystof Tulinger     */
1609d7d00a41SKrystof Tulinger    init_history_input();
1610d7d00a41SKrystof Tulinger
1611d7d00a41SKrystof Tulinger    /**
1612d7d00a41SKrystof Tulinger     * Initialize the markdown converter.
1613d7d00a41SKrystof Tulinger     *
1614d7d00a41SKrystof Tulinger     * WARNING: The converter is not XSS safe. If you're not sure about what
1615d7d00a41SKrystof Tulinger     * could occur in the readmes then rather comment out this.
1616d7d00a41SKrystof Tulinger     */
1617d7d00a41SKrystof Tulinger    init_markdown_converter();
1618d7d00a41SKrystof Tulinger
1619d7d00a41SKrystof Tulinger    restoreFocusAfterSearchSubmit();
1620d7d00a41SKrystof Tulinger});
1621d7d00a41SKrystof Tulinger
1622d7d00a41SKrystof Tulinger/**
1623d7d00a41SKrystof Tulinger * Get a parameter value from the URL.
1624d7d00a41SKrystof Tulinger *
1625d7d00a41SKrystof Tulinger * @param p the name of the parameter
1626d7d00a41SKrystof Tulinger * @return the decoded value of parameter p
1627d7d00a41SKrystof Tulinger */
1628d7d00a41SKrystof Tulingerfunction getParameter(p) {
1629d7d00a41SKrystof Tulinger    // First split up the parameter list. That is, transform from
1630d7d00a41SKrystof Tulinger    //       ?a=b&c=d
1631d7d00a41SKrystof Tulinger    // to
1632d7d00a41SKrystof Tulinger    //       [ ["a", "b"], ["c","d"] ]
1633d7d00a41SKrystof Tulinger    if (getParameter.params === undefined) {
1634d7d00a41SKrystof Tulinger        getParameter.params = window.location.search.substr(1).split("&").map(
1635d7d00a41SKrystof Tulinger                function (x) { return x.split("="); });
1636d7d00a41SKrystof Tulinger    }
1637d7d00a41SKrystof Tulinger    const params = getParameter.params;
1638d7d00a41SKrystof Tulinger    // Then look for the parameter.
1639d7d00a41SKrystof Tulinger    for (let i in params) {
1640d7d00a41SKrystof Tulinger        if (params[i][0] === p && params[i].length > 1) {
1641d7d00a41SKrystof Tulinger            return decodeURIComponent(params[i][1]);
1642d7d00a41SKrystof Tulinger        }
1643d7d00a41SKrystof Tulinger    }
1644d7d00a41SKrystof Tulinger    return undefined;
1645d7d00a41SKrystof Tulinger}
1646d7d00a41SKrystof Tulinger
1647d7d00a41SKrystof Tulinger/**
1648d7d00a41SKrystof Tulinger * Set parameter in the given url.
1649d7d00a41SKrystof Tulinger * @param string url
1650d7d00a41SKrystof Tulinger * @param string p parameter name
1651d7d00a41SKrystof Tulinger * @param string v parameter value
1652d7d00a41SKrystof Tulinger * @returns string the modified url
1653d7d00a41SKrystof Tulinger */
1654d7d00a41SKrystof Tulingerfunction setParameter(url, p, v) {
1655d7d00a41SKrystof Tulinger    const base = url.substr(0, url.indexOf('?'));
1656d7d00a41SKrystof Tulinger    const params = url.substr(base.length + 1).split("&").map(
1657d7d00a41SKrystof Tulinger            function (x) {
1658d7d00a41SKrystof Tulinger                return x.split("=");
1659d7d00a41SKrystof Tulinger            });
1660d7d00a41SKrystof Tulinger    let found = false;
1661d7d00a41SKrystof Tulinger    for (let i in params) {
1662d7d00a41SKrystof Tulinger        if (params[i][0] === p && params[i].length > 1) {
1663d7d00a41SKrystof Tulinger            params[i][1] = encodeURIComponent(v);
1664d7d00a41SKrystof Tulinger            found = true;
1665d7d00a41SKrystof Tulinger        }
1666d7d00a41SKrystof Tulinger    }
1667d7d00a41SKrystof Tulinger    if (!found) {
1668d7d00a41SKrystof Tulinger        params.push([p, encodeURIComponent(v)]);
1669d7d00a41SKrystof Tulinger    }
1670d7d00a41SKrystof Tulinger
1671d7d00a41SKrystof Tulinger    return base + '?' + params.map(function (x) {
1672d7d00a41SKrystof Tulinger        return x[0] + '=' + x[1];
1673d7d00a41SKrystof Tulinger    }).join('&');
1674d7d00a41SKrystof Tulinger}
1675d7d00a41SKrystof Tulinger
1676d7d00a41SKrystof Tulingerfunction domReadyMast() {
1677d7d00a41SKrystof Tulinger    if (!window.location.hash) {
1678d7d00a41SKrystof Tulinger        const h = getParameter("h");
1679d7d00a41SKrystof Tulinger        if (h && h !== "") {
1680d7d00a41SKrystof Tulinger            window.location.hash = h;
1681d7d00a41SKrystof Tulinger        }
1682d7d00a41SKrystof Tulinger    }
1683d7d00a41SKrystof Tulinger    if (document.annotate) {
1684d7d00a41SKrystof Tulinger        $('a.r').tooltip({
1685d7d00a41SKrystof Tulinger            content: function () {
1686d7d00a41SKrystof Tulinger                const element = $(this);
1687d7d00a41SKrystof Tulinger                const title = element.attr("title") || "";
1688d7d00a41SKrystof Tulinger                const parts = title.split(/<br\/>(?=[a-zA-Z0-9]+:)/g);
1689d7d00a41SKrystof Tulinger                if (parts.length <= 0) {
1690d7d00a41SKrystof Tulinger                    return "";
1691d7d00a41SKrystof Tulinger                }
1692d7d00a41SKrystof Tulinger                const $el = $("<dl>");
1693d7d00a41SKrystof Tulinger                for (let i = 0; i < parts.length; i++) {
1694d7d00a41SKrystof Tulinger                    const definitions = parts[i].split(":");
1695d7d00a41SKrystof Tulinger                    if (definitions.length < 2) {
1696d7d00a41SKrystof Tulinger                        continue;
1697d7d00a41SKrystof Tulinger                    }
1698d7d00a41SKrystof Tulinger                    $("<dt>").text(definitions.shift().trim()).appendTo($el);
1699d7d00a41SKrystof Tulinger                    const $dd = $("<dd>");
1700d7d00a41SKrystof Tulinger                    $.each(definitions.join(":").split("<br/>"), function (i, el) {
1701d7d00a41SKrystof Tulinger                        $dd.append(escapeHtml(el.trim()));
1702d7d00a41SKrystof Tulinger                        $dd.append($("<br/>"));
1703d7d00a41SKrystof Tulinger                    });
1704d7d00a41SKrystof Tulinger                    $dd.appendTo($el);
1705d7d00a41SKrystof Tulinger                }
1706d7d00a41SKrystof Tulinger                return $el;
1707d7d00a41SKrystof Tulinger            }
1708d7d00a41SKrystof Tulinger        });
1709d7d00a41SKrystof Tulinger
1710d7d00a41SKrystof Tulinger        $("#toggle-annotate-by-javascript").css('display', 'inline');
1711d7d00a41SKrystof Tulinger        $("#toggle-annotate").hide();
1712d7d00a41SKrystof Tulinger    }
1713d7d00a41SKrystof Tulinger}
1714d7d00a41SKrystof Tulinger
1715d7d00a41SKrystof Tulingerfunction pageReadyMast() {
1716d7d00a41SKrystof Tulinger}
1717d7d00a41SKrystof Tulinger
1718d7d00a41SKrystof Tulingerfunction domReadyMenu(minisearch) {
1719d7d00a41SKrystof Tulinger    if (getSettingsValue('suggester-enabled') === 'false') {
1720d7d00a41SKrystof Tulinger        return;
1721d7d00a41SKrystof Tulinger    }
1722d7d00a41SKrystof Tulinger
1723d7d00a41SKrystof Tulinger    $.ajax({
1724d7d00a41SKrystof Tulinger        // cannot use "/api/v1/configuration/suggester" because of security
1725d7d00a41SKrystof Tulinger        url: window.contextPath + "/api/v1/suggest/config",
1726d7d00a41SKrystof Tulinger        dataType: "json",
1727d7d00a41SKrystof Tulinger        success: function(config) {
1728d7d00a41SKrystof Tulinger            if (config.enabled) {
1729d7d00a41SKrystof Tulinger                initAutocomplete(config, minisearch);
1730d7d00a41SKrystof Tulinger            }
1731d7d00a41SKrystof Tulinger        },
1732d7d00a41SKrystof Tulinger        error: function(xhr, ajaxOptions, error) {
1733d7d00a41SKrystof Tulinger            console.log('Could not get autocomplete configuration, probably disabled');
1734d7d00a41SKrystof Tulinger        }
1735d7d00a41SKrystof Tulinger    });
1736d7d00a41SKrystof Tulinger}
1737d7d00a41SKrystof Tulinger
1738d7d00a41SKrystof Tulingerfunction initAutocomplete(config, minisearch) {
1739d7d00a41SKrystof Tulinger    if (minisearch) {
1740d7d00a41SKrystof Tulinger        initMinisearchAutocomplete(config);
1741d7d00a41SKrystof Tulinger    } else {
1742d7d00a41SKrystof Tulinger        initAutocompleteForField("full", "full", config);
1743d7d00a41SKrystof Tulinger        initAutocompleteForField("defs", "defs", config);
1744d7d00a41SKrystof Tulinger        initAutocompleteForField("refs", "refs", config);
1745d7d00a41SKrystof Tulinger        initAutocompleteForField("path", "path", config);
1746d7d00a41SKrystof Tulinger        initAutocompleteForField("hist", "hist", config);
1747d7d00a41SKrystof Tulinger    }
1748d7d00a41SKrystof Tulinger}
1749d7d00a41SKrystof Tulinger
1750d7d00a41SKrystof Tulingerfunction initMinisearchAutocomplete(config) {
1751d7d00a41SKrystof Tulinger    if (config.allowedFields && config.allowedFields.indexOf('full') < 0) {
1752d7d00a41SKrystof Tulinger        return;
1753d7d00a41SKrystof Tulinger    }
1754d7d00a41SKrystof Tulinger
1755d7d00a41SKrystof Tulinger    let project = '';
1756d7d00a41SKrystof Tulinger
1757d7d00a41SKrystof Tulinger    var projectElem = $('#minisearch-project');
1758d7d00a41SKrystof Tulinger    if (projectElem) {
1759d7d00a41SKrystof Tulinger        project = projectElem.val();
1760d7d00a41SKrystof Tulinger    }
1761d7d00a41SKrystof Tulinger
1762d7d00a41SKrystof Tulinger    const pathElem = $('#minisearch-path');
1763d7d00a41SKrystof Tulinger
1764d7d00a41SKrystof Tulinger    initAutocompleteForField('search', 'full', config, function (input, field) {
1765d7d00a41SKrystof Tulinger        const caretPos = input.caret();
1766d7d00a41SKrystof Tulinger        if (!(typeof caretPos === 'number')) {
1767d7d00a41SKrystof Tulinger            console.error("Suggest: could not get caret position");
1768d7d00a41SKrystof Tulinger            return;
1769d7d00a41SKrystof Tulinger        }
1770d7d00a41SKrystof Tulinger        return {
1771d7d00a41SKrystof Tulinger            projects: [project],
1772d7d00a41SKrystof Tulinger            field: field,
1773d7d00a41SKrystof Tulinger            full: input.val(),
1774d7d00a41SKrystof Tulinger            path: pathElem.is(':checked') ? pathElem.val() : '',
1775d7d00a41SKrystof Tulinger            caret: caretPos
1776d7d00a41SKrystof Tulinger        };
1777d7d00a41SKrystof Tulinger    }, 'search');
1778d7d00a41SKrystof Tulinger}
1779d7d00a41SKrystof Tulinger
1780d7d00a41SKrystof Tulingerfunction initAutocompleteForField(inputId, field, config, dataFunction, errorElemId) {
1781d7d00a41SKrystof Tulinger    if (config.allowedFields && config.allowedFields.indexOf(field) < 0) {
1782d7d00a41SKrystof Tulinger        return;
1783d7d00a41SKrystof Tulinger    }
1784d7d00a41SKrystof Tulinger
1785d7d00a41SKrystof Tulinger    let text;
1786d7d00a41SKrystof Tulinger    let identifier;
1787d7d00a41SKrystof Tulinger    let time;
1788d7d00a41SKrystof Tulinger    let partialResult;
1789d7d00a41SKrystof Tulinger
1790d7d00a41SKrystof Tulinger    const input = $("#" + inputId);
1791d7d00a41SKrystof Tulinger
1792d7d00a41SKrystof Tulinger    if (!dataFunction) {
1793d7d00a41SKrystof Tulinger        dataFunction = getAutocompleteMenuData;
1794d7d00a41SKrystof Tulinger    }
1795d7d00a41SKrystof Tulinger    if (!errorElemId) {
1796d7d00a41SKrystof Tulinger        errorElemId = 'full';
1797d7d00a41SKrystof Tulinger    }
1798d7d00a41SKrystof Tulinger    const errorElem = $('#' + errorElemId);
1799d7d00a41SKrystof Tulinger
1800d7d00a41SKrystof Tulinger    input.autocomplete({
1801d7d00a41SKrystof Tulinger        source: function(request, response) {
1802d7d00a41SKrystof Tulinger            $.ajax({
1803d7d00a41SKrystof Tulinger                url: window.contextPath + "/api/v1/suggest",
1804d7d00a41SKrystof Tulinger                dataType: "json",
1805d7d00a41SKrystof Tulinger                data: dataFunction(input, field),
1806d7d00a41SKrystof Tulinger                success: function(data) {
1807d7d00a41SKrystof Tulinger                    hideError(errorElem);
1808d7d00a41SKrystof Tulinger
1809d7d00a41SKrystof Tulinger                    text = data.queryText;
1810d7d00a41SKrystof Tulinger                    identifier = data.identifier;
1811d7d00a41SKrystof Tulinger                    time = data.time;
1812d7d00a41SKrystof Tulinger                    partialResult = data.partialResult;
1813d7d00a41SKrystof Tulinger
1814d7d00a41SKrystof Tulinger                    response(data.suggestions);
1815d7d00a41SKrystof Tulinger                },
1816d7d00a41SKrystof Tulinger                error: function(xhr, ajaxOptions, error) {
1817d7d00a41SKrystof Tulinger                    input.autocomplete("close");
1818d7d00a41SKrystof Tulinger                    response(undefined); // to remove loading indicator
1819d7d00a41SKrystof Tulinger
1820d7d00a41SKrystof Tulinger                    showError(xhr.responseJSON.message, errorElem);
1821d7d00a41SKrystof Tulinger                },
1822d7d00a41SKrystof Tulinger                statusCode: {
1823d7d00a41SKrystof Tulinger                    404: function() {
1824d7d00a41SKrystof Tulinger                        response(); // do not show anything
1825d7d00a41SKrystof Tulinger                    }
1826d7d00a41SKrystof Tulinger                }
1827d7d00a41SKrystof Tulinger            });
1828d7d00a41SKrystof Tulinger        },
1829d7d00a41SKrystof Tulinger        create: function () {
1830d7d00a41SKrystof Tulinger            $(this).data('ui-autocomplete')._renderItem = function (ul, item) {
1831d7d00a41SKrystof Tulinger                const listItem = getSuggestionListItem(item, config);
1832d7d00a41SKrystof Tulinger
1833d7d00a41SKrystof Tulinger                return listItem.appendTo(ul);
1834d7d00a41SKrystof Tulinger            };
1835d7d00a41SKrystof Tulinger
1836d7d00a41SKrystof Tulinger            $(this).data('ui-autocomplete')._renderMenu = function (ul, items) {
1837d7d00a41SKrystof Tulinger                const _this = this;
1838d7d00a41SKrystof Tulinger                $.each(items, function(index, item) {
1839d7d00a41SKrystof Tulinger                    _this._renderItemData(ul, item);
1840d7d00a41SKrystof Tulinger                });
1841d7d00a41SKrystof Tulinger                if (config.showTime) {
1842d7d00a41SKrystof Tulinger                    $("<li>", {
1843d7d00a41SKrystof Tulinger                        "class": "ui-state-disabled",
1844d7d00a41SKrystof Tulinger                        style: 'padding-left: 5px;',
1845d7d00a41SKrystof Tulinger                        text: time + ' ms'
1846d7d00a41SKrystof Tulinger                    }).appendTo(ul);
1847d7d00a41SKrystof Tulinger                }
1848d7d00a41SKrystof Tulinger                if (partialResult) {
1849d7d00a41SKrystof Tulinger                    $("<li>", {
1850d7d00a41SKrystof Tulinger                        "class": "ui-state-disabled",
1851d7d00a41SKrystof Tulinger                        style: 'padding-left: 5px;',
1852d7d00a41SKrystof Tulinger                        text: 'Partial result due to timeout'
1853d7d00a41SKrystof Tulinger                    }).appendTo(ul);
1854d7d00a41SKrystof Tulinger                }
1855d7d00a41SKrystof Tulinger            };
1856d7d00a41SKrystof Tulinger        },
1857d7d00a41SKrystof Tulinger        focus: function (event, ui) {
1858d7d00a41SKrystof Tulinger            if (ui.item.selectable === false) {
1859d7d00a41SKrystof Tulinger                event.preventDefault();
1860d7d00a41SKrystof Tulinger                return;
1861d7d00a41SKrystof Tulinger            }
1862d7d00a41SKrystof Tulinger            if (event.originalEvent.originalEvent.type.indexOf('key') === 0) { // replace value only on key events
1863d7d00a41SKrystof Tulinger                replaceValueWithSuggestion(input, text, identifier, ui.item.phrase);
1864d7d00a41SKrystof Tulinger            }
1865d7d00a41SKrystof Tulinger
1866d7d00a41SKrystof Tulinger            event.preventDefault(); // to prevent the movement of the caret to the end
1867d7d00a41SKrystof Tulinger        },
1868d7d00a41SKrystof Tulinger        select: function (event, ui) {
1869d7d00a41SKrystof Tulinger            replaceValueWithSuggestion(input, text, identifier, ui.item.phrase);
1870d7d00a41SKrystof Tulinger
1871d7d00a41SKrystof Tulinger            event.preventDefault(); // to prevent the movement of the caret to the end
1872d7d00a41SKrystof Tulinger        },
1873d7d00a41SKrystof Tulinger        response: function (event, ui) {
1874d7d00a41SKrystof Tulinger            if (!ui.content) {
1875d7d00a41SKrystof Tulinger                // error occurred
1876d7d00a41SKrystof Tulinger                return;
1877d7d00a41SKrystof Tulinger            }
1878d7d00a41SKrystof Tulinger            if (ui.content.length === 0 && !partialResult) {
1879d7d00a41SKrystof Tulinger                const noMatchesFoundResult = {phrase: 'No matches found', selectable: false};
1880d7d00a41SKrystof Tulinger                ui.content.push(noMatchesFoundResult);
1881d7d00a41SKrystof Tulinger            }
1882d7d00a41SKrystof Tulinger        },
1883d7d00a41SKrystof Tulinger        minLength: config.minChars
1884d7d00a41SKrystof Tulinger    }).click(function() {
1885d7d00a41SKrystof Tulinger        $(this).autocomplete('search', $(this).val());
1886d7d00a41SKrystof Tulinger    }).keyup(function(e) {
1887d7d00a41SKrystof Tulinger        if (e.keyCode === 37 || e.keyCode === 39) { // left or right arrow key
1888d7d00a41SKrystof Tulinger            $(this).autocomplete('search', $(this).val());
1889d7d00a41SKrystof Tulinger        }
1890d7d00a41SKrystof Tulinger        // try to refresh on empty input (error might go away) except when pressed esc key
1891d7d00a41SKrystof Tulinger        if (input.val() === "" && e.keyCode !== 27) {
1892d7d00a41SKrystof Tulinger            $(this).autocomplete('search', ' ');
1893d7d00a41SKrystof Tulinger        }
1894d7d00a41SKrystof Tulinger    });
1895d7d00a41SKrystof Tulinger}
1896d7d00a41SKrystof Tulinger
1897d7d00a41SKrystof Tulingerfunction getAutocompleteMenuData(input, field) {
1898d7d00a41SKrystof Tulinger    const caretPos = input.caret();
1899d7d00a41SKrystof Tulinger    if (!Number.isInteger(caretPos)) {
1900d7d00a41SKrystof Tulinger        console.error("Suggest: could not get caret position");
1901d7d00a41SKrystof Tulinger        return;
1902d7d00a41SKrystof Tulinger    }
1903d7d00a41SKrystof Tulinger    return {
1904d7d00a41SKrystof Tulinger        projects: getSelectedProjectNames(),
1905d7d00a41SKrystof Tulinger        field: field,
1906d7d00a41SKrystof Tulinger        full: $('#full').val(),
1907d7d00a41SKrystof Tulinger        defs: $('#defs').val(),
1908d7d00a41SKrystof Tulinger        refs: $('#refs').val(),
1909d7d00a41SKrystof Tulinger        path: $('#path').val(),
1910d7d00a41SKrystof Tulinger        hist: $('#hist').val(),
1911d7d00a41SKrystof Tulinger        type: $('#type').val(),
1912d7d00a41SKrystof Tulinger        caret: caretPos
1913d7d00a41SKrystof Tulinger    };
1914d7d00a41SKrystof Tulinger}
1915d7d00a41SKrystof Tulinger
1916d7d00a41SKrystof Tulingerfunction replaceValueWithSuggestion(input, queryText, identifier, suggestion) {
1917d7d00a41SKrystof Tulinger    const pos = queryText.indexOf(identifier);
1918d7d00a41SKrystof Tulinger    const phrase = escapeLuceneCharacters(suggestion);
1919d7d00a41SKrystof Tulinger    input.val(queryText.replace(identifier, phrase));
1920d7d00a41SKrystof Tulinger    input.caret(pos + phrase.length);
1921d7d00a41SKrystof Tulinger}
1922d7d00a41SKrystof Tulinger
1923d7d00a41SKrystof Tulingerfunction showError(errorText, errorElem) {
1924d7d00a41SKrystof Tulinger    const parent = errorElem.parent();
1925d7d00a41SKrystof Tulinger
1926d7d00a41SKrystof Tulinger    parent.css('position', 'relative');
1927d7d00a41SKrystof Tulinger
1928d7d00a41SKrystof Tulinger    let span = parent.find('#autocomplete-error')[0];
1929d7d00a41SKrystof Tulinger    if (!span) {
1930d7d00a41SKrystof Tulinger        span = $("<span>", {
1931d7d00a41SKrystof Tulinger            "class": "note-error important-note important-note-rounded",
1932d7d00a41SKrystof Tulinger            style: "right: -10px; position: absolute; top: 0px;",
1933d7d00a41SKrystof Tulinger            text: "!",
1934d7d00a41SKrystof Tulinger            id: 'autocomplete-error'
1935d7d00a41SKrystof Tulinger        });
1936d7d00a41SKrystof Tulinger
1937d7d00a41SKrystof Tulinger        span.appendTo(parent);
1938d7d00a41SKrystof Tulinger    } else {
1939d7d00a41SKrystof Tulinger        span = $(span);
1940d7d00a41SKrystof Tulinger        span.off("mouseenter mouseleave");
1941d7d00a41SKrystof Tulinger    }
1942d7d00a41SKrystof Tulinger
1943d7d00a41SKrystof Tulinger    span.hover(function() { // mouse in
1944d7d00a41SKrystof Tulinger        $.messagesWindow.empty();
1945d7d00a41SKrystof Tulinger        $.messagesWindow.append(escapeHtml(errorText));
1946d7d00a41SKrystof Tulinger        $.messagesWindow.show();
1947d7d00a41SKrystof Tulinger    }, function() { // mouse out
1948d7d00a41SKrystof Tulinger        $.messagesWindow.hide();
1949d7d00a41SKrystof Tulinger    });
1950d7d00a41SKrystof Tulinger}
1951d7d00a41SKrystof Tulinger
1952d7d00a41SKrystof Tulingerfunction hideError(errorElem) {
1953d7d00a41SKrystof Tulinger    const parent = errorElem.parent();
1954d7d00a41SKrystof Tulinger    const span = parent.find('#autocomplete-error')[0];
1955d7d00a41SKrystof Tulinger    if (span) {
1956d7d00a41SKrystof Tulinger        span.remove();
1957d7d00a41SKrystof Tulinger    }
1958d7d00a41SKrystof Tulinger}
1959d7d00a41SKrystof Tulinger
1960d7d00a41SKrystof Tulingerfunction getSuggestionListItem(itemData, config) {
1961d7d00a41SKrystof Tulinger    if (itemData.selectable === false) {
1962d7d00a41SKrystof Tulinger        return $("<li>", {
1963d7d00a41SKrystof Tulinger            "class": "ui-state-disabled",
1964d7d00a41SKrystof Tulinger            text: itemData.phrase
1965d7d00a41SKrystof Tulinger        });
1966d7d00a41SKrystof Tulinger    }
1967d7d00a41SKrystof Tulinger
1968d7d00a41SKrystof Tulinger    const listItem = $("<li>", {
1969d7d00a41SKrystof Tulinger        "class": "ui-menu-item",
1970d7d00a41SKrystof Tulinger        style: "display: block;"
1971d7d00a41SKrystof Tulinger    });
1972d7d00a41SKrystof Tulinger    const listItemChild = $("<div>", {
1973d7d00a41SKrystof Tulinger        "class": "ui-menu-item-wrapper",
1974d7d00a41SKrystof Tulinger        style: "height: 20px; padding: 0;",
1975d7d00a41SKrystof Tulinger        tabindex: "-1"
1976d7d00a41SKrystof Tulinger    });
1977d7d00a41SKrystof Tulinger
1978d7d00a41SKrystof Tulinger    listItemChild.appendTo(listItem);
1979d7d00a41SKrystof Tulinger
1980d7d00a41SKrystof Tulinger    $("<span>", {
1981d7d00a41SKrystof Tulinger        text: itemData.phrase,
1982d7d00a41SKrystof Tulinger        style: "float: left; padding-left: 5px; max-height: 20px;"
1983d7d00a41SKrystof Tulinger    }).appendTo(listItemChild);
1984d7d00a41SKrystof Tulinger
1985d7d00a41SKrystof Tulinger    let projectInfoText = "";
1986d7d00a41SKrystof Tulinger    if (config.showProjects) {
1987d7d00a41SKrystof Tulinger        if (itemData.projects.length > 1) {
1988d7d00a41SKrystof Tulinger            projectInfoText = 'Found in ' + itemData.projects.length + ' projects';
1989d7d00a41SKrystof Tulinger        } else {
1990d7d00a41SKrystof Tulinger            projectInfoText = itemData.projects[0];
1991d7d00a41SKrystof Tulinger        }
1992d7d00a41SKrystof Tulinger    }
1993d7d00a41SKrystof Tulinger
1994d7d00a41SKrystof Tulinger    let score = "";
1995d7d00a41SKrystof Tulinger    if (config.showScores) {
1996d7d00a41SKrystof Tulinger        score = ' (' + itemData.score + ')';
1997d7d00a41SKrystof Tulinger    }
1998d7d00a41SKrystof Tulinger    $("<span>", {
1999d7d00a41SKrystof Tulinger        text: projectInfoText + score,
2000d7d00a41SKrystof Tulinger        style: "float: right; color: #999999; font-style: italic; padding-right: 5px;"
2001d7d00a41SKrystof Tulinger    }).appendTo(listItemChild);
2002d7d00a41SKrystof Tulinger
2003d7d00a41SKrystof Tulinger    return listItem;
2004d7d00a41SKrystof Tulinger}
2005d7d00a41SKrystof Tulinger
2006d7d00a41SKrystof Tulingerfunction escapeLuceneCharacters(term) {
2007d7d00a41SKrystof Tulinger    // must escape: + - && || ! ( ) { } [ ] ^ " ~ * ? : \
2008d7d00a41SKrystof Tulinger    const pattern = /([\+\-\!\(\)\{\}\[\]\^\"\~\*\?\:\\]|&&|\|\|)/g;
2009d7d00a41SKrystof Tulinger
2010d7d00a41SKrystof Tulinger    return term.replace(pattern, "\\$1");
2011d7d00a41SKrystof Tulinger}
2012d7d00a41SKrystof Tulinger
2013d7d00a41SKrystof Tulingerfunction domReadyHistory() {
2014d7d00a41SKrystof Tulinger    // start state should ALWAYS be: first row: r1 hidden, r2 checked ;
2015d7d00a41SKrystof Tulinger    // second row: r1 clicked, (r2 hidden)(optionally)
2016d7d00a41SKrystof Tulinger    // I cannot say what will happen if they are not like that, togglediffs
2017d7d00a41SKrystof Tulinger    // will go mad !
2018d7d00a41SKrystof Tulinger    togglerevs();
2019d7d00a41SKrystof Tulinger    toggleProjectInfo();
2020d7d00a41SKrystof Tulinger}
2021d7d00a41SKrystof Tulinger
2022d7d00a41SKrystof Tulingerfunction get_annotations() {
2023d7d00a41SKrystof Tulinger    let link = window.location.pathname + "?a=true";
2024d7d00a41SKrystof Tulinger    if (document.rev && document.rev()) {
2025d7d00a41SKrystof Tulinger        link += "&r=" + encodeURIComponent(document.rev());
2026d7d00a41SKrystof Tulinger    }
2027d7d00a41SKrystof Tulinger    if (window.location.hash) {
2028d7d00a41SKrystof Tulinger        // If a line is highlighted when "annotate" is clicked, we want to
2029d7d00a41SKrystof Tulinger        // preserve the highlighting, but we don't want the page to scroll
2030d7d00a41SKrystof Tulinger        // to the highlighted line. So put the line number in a URL parameter
2031d7d00a41SKrystof Tulinger        // instead of in the hash.
2032d7d00a41SKrystof Tulinger        link += "&h=";
2033d7d00a41SKrystof Tulinger        link += window.location.hash.substring(1, window.location.hash.length);
2034d7d00a41SKrystof Tulinger    }
2035d7d00a41SKrystof Tulinger    window.location = link;
2036d7d00a41SKrystof Tulinger}
2037d7d00a41SKrystof Tulinger
2038d7d00a41SKrystof Tulingerfunction toggle_annotations() {
2039d7d00a41SKrystof Tulinger    $(document.body).toggleClass("blame-hidden");
2040d7d00a41SKrystof Tulinger}
2041d7d00a41SKrystof Tulinger
2042d7d00a41SKrystof Tulinger/** list.jsp */
2043d7d00a41SKrystof Tulinger
2044d7d00a41SKrystof Tulinger/**
2045d7d00a41SKrystof Tulinger * Initialize defaults for list.jsp
2046d7d00a41SKrystof Tulinger */
2047d7d00a41SKrystof Tulingerfunction pageReadyList() {
2048d7d00a41SKrystof Tulinger    document.highlight_count = 0;
2049d7d00a41SKrystof Tulinger    $.navigateWindow.init();
2050d7d00a41SKrystof Tulinger    if (typeof get_sym_list === 'function') {
2051d7d00a41SKrystof Tulinger        $.navigateWindow.update(get_sym_list());
2052d7d00a41SKrystof Tulinger    }
2053d7d00a41SKrystof Tulinger    $('#navigate').click(function () {
2054d7d00a41SKrystof Tulinger        $.navigateWindow.toggle();
2055d7d00a41SKrystof Tulinger        return false;
2056d7d00a41SKrystof Tulinger    });
2057d7d00a41SKrystof Tulinger}
2058d7d00a41SKrystof Tulinger
2059d7d00a41SKrystof Tulinger/**
2060d7d00a41SKrystof Tulinger * Toggle the display of line numbers.
2061d7d00a41SKrystof Tulinger */
2062d7d00a41SKrystof Tulingerfunction lntoggle() {
2063d7d00a41SKrystof Tulinger    $(document.body).toggleClass("lines-hidden");
2064d7d00a41SKrystof Tulinger    $('.fold-space, .fold-icon, .unfold-icon').toggle();
2065d7d00a41SKrystof Tulinger}
2066d7d00a41SKrystof Tulinger
2067d7d00a41SKrystof Tulingerfunction lnshow() {
2068d7d00a41SKrystof Tulinger    $(document.body).removeClass("lines-hidden");
2069d7d00a41SKrystof Tulinger    $('.fold-space, .fold-icon, .unfold-icon').show();
2070d7d00a41SKrystof Tulinger}
2071d7d00a41SKrystof Tulinger
2072d7d00a41SKrystof Tulinger/* ------ Highlighting ------ */
2073d7d00a41SKrystof Tulinger
2074d7d00a41SKrystof Tulinger/**
2075d7d00a41SKrystof Tulinger *  Highlight keywords by changing the style of matching tags.
2076d7d00a41SKrystof Tulinger */
2077d7d00a41SKrystof Tulingerfunction highlightKeyword(keyword) {
2078d7d00a41SKrystof Tulinger    const high_colors = [ "#ffff66", "#ffcccc", "#ccccff", "#99ff99", "#cc66ff" ];
2079d7d00a41SKrystof Tulinger    const pattern = "a:contains('" + keyword + "')";
2080d7d00a41SKrystof Tulinger    $(pattern).css({
2081d7d00a41SKrystof Tulinger        'text-decoration' : 'underline',
2082d7d00a41SKrystof Tulinger        'background-color' : high_colors[document.highlight_count % high_colors.length],
2083d7d00a41SKrystof Tulinger        'font-weight' : 'bold'
2084d7d00a41SKrystof Tulinger    });
2085d7d00a41SKrystof Tulinger    document.highlight_count++;
2086d7d00a41SKrystof Tulinger}
2087d7d00a41SKrystof Tulinger//Test: HighlightKeyword('timeval');
2088d7d00a41SKrystof Tulinger
2089d7d00a41SKrystof Tulinger/**
2090d7d00a41SKrystof Tulinger * Highlight the text given as value of the element with the ID "input_highlight" .
2091d7d00a41SKrystof Tulinger * @see HighlightKeyword
2092d7d00a41SKrystof Tulinger */
2093d7d00a41SKrystof Tulingerfunction add_highlight() {
2094d7d00a41SKrystof Tulinger    const tbox = document.getElementById('input_highlight');
2095d7d00a41SKrystof Tulinger    highlightKeyword(tbox.value);
2096d7d00a41SKrystof Tulinger}
2097d7d00a41SKrystof Tulinger
2098d7d00a41SKrystof Tulingerfunction toggle_filelist() {
2099d7d00a41SKrystof Tulinger    const $a = $('div.filelist');
2100d7d00a41SKrystof Tulinger    const $b = $('div.filelist-hidden');
2101d7d00a41SKrystof Tulinger    $a.toggle().toggleClass('filelist').toggleClass('filelist-hidden');
2102d7d00a41SKrystof Tulinger    $b.toggle().toggleClass('filelist').toggleClass('filelist-hidden');
2103d7d00a41SKrystof Tulinger}
2104d7d00a41SKrystof Tulinger
2105d7d00a41SKrystof Tulingerfunction toggle_revtags() {
2106d7d00a41SKrystof Tulinger    const $a = $('tr.revtags, span.revtags');
2107d7d00a41SKrystof Tulinger    const $b = $('tr.revtags-hidden, span.revtags-hidden');
2108d7d00a41SKrystof Tulinger    $a.toggle().toggleClass('revtags').toggleClass('revtags-hidden');
2109d7d00a41SKrystof Tulinger    $b.toggle().toggleClass('revtags').toggleClass('revtags-hidden');
2110d7d00a41SKrystof Tulinger}
2111d7d00a41SKrystof Tulinger
2112d7d00a41SKrystof Tulinger/**
2113d7d00a41SKrystof Tulinger *  Function to toggle message length presentation
2114d7d00a41SKrystof Tulinger */
2115d7d00a41SKrystof Tulingerfunction toggleCommon(closestType) {
2116d7d00a41SKrystof Tulinger  $(".rev-toggle-a").click(function() {
2117d7d00a41SKrystof Tulinger    const toggleState = $(this).closest(closestType).attr("data-toggle-state");
2118d7d00a41SKrystof Tulinger    const thisCell = $(this).closest("td");
2119d7d00a41SKrystof Tulinger
2120d7d00a41SKrystof Tulinger    if (toggleState === "less") {
2121d7d00a41SKrystof Tulinger      $(this).closest(closestType).attr("data-toggle-state", "more");
2122d7d00a41SKrystof Tulinger      thisCell.find(".rev-message-summary").addClass("rev-message-hidden");
2123d7d00a41SKrystof Tulinger      thisCell.find(".rev-message-full").removeClass("rev-message-hidden");
2124d7d00a41SKrystof Tulinger      $(this).html("... show less");
2125d7d00a41SKrystof Tulinger    }
2126d7d00a41SKrystof Tulinger    else if (toggleState === "more") {
2127d7d00a41SKrystof Tulinger      $(this).closest(closestType).attr("data-toggle-state", "less");
2128d7d00a41SKrystof Tulinger      thisCell.find(".rev-message-full").addClass("rev-message-hidden");
2129d7d00a41SKrystof Tulinger      thisCell.find(".rev-message-summary").removeClass("rev-message-hidden");
2130d7d00a41SKrystof Tulinger      $(this).html("show more ...");
2131d7d00a41SKrystof Tulinger    }
2132d7d00a41SKrystof Tulinger
2133d7d00a41SKrystof Tulinger    return false;
2134d7d00a41SKrystof Tulinger  });
2135d7d00a41SKrystof Tulinger}
2136d7d00a41SKrystof Tulinger
2137d7d00a41SKrystof Tulinger/**
2138d7d00a41SKrystof Tulinger *  Function to toggle revision message length for long revision messages
2139d7d00a41SKrystof Tulinger */
2140d7d00a41SKrystof Tulingerfunction togglerevs() {
2141d7d00a41SKrystof Tulinger  $(".rev-toggle-a").click(toggleCommon("p"));
2142d7d00a41SKrystof Tulinger}
2143d7d00a41SKrystof Tulinger/**
2144d7d00a41SKrystof Tulinger *  Function to toggle project info message length
2145d7d00a41SKrystof Tulinger */
2146d7d00a41SKrystof Tulingerfunction toggleProjectInfo() {
2147d7d00a41SKrystof Tulinger  $(".rev-toggle-a").click(toggleCommon("span"));
2148d7d00a41SKrystof Tulinger}
2149d7d00a41SKrystof Tulinger
2150d7d00a41SKrystof Tulingerfunction selectAllProjects() {
2151d7d00a41SKrystof Tulinger    if ($("#project").data(SearchableOptionList.prototype.DATA_KEY)) {
2152d7d00a41SKrystof Tulinger        $("#project").searchableOptionList().selectAll();
2153d7d00a41SKrystof Tulinger    } else {
2154d7d00a41SKrystof Tulinger        $("#project option").prop('selected', true);
2155d7d00a41SKrystof Tulinger    }
2156d7d00a41SKrystof Tulinger}
2157d7d00a41SKrystof Tulinger
2158d7d00a41SKrystof Tulingerfunction invertAllProjects() {
2159d7d00a41SKrystof Tulinger    if ($("#project").data(SearchableOptionList.prototype.DATA_KEY)) {
2160d7d00a41SKrystof Tulinger        $("#project").searchableOptionList().invert();
2161d7d00a41SKrystof Tulinger    } else {
2162d7d00a41SKrystof Tulinger        $("#project option").each(function () {
2163d7d00a41SKrystof Tulinger            $(this).prop('selected', !$(this).prop('selected'));
2164d7d00a41SKrystof Tulinger        });
2165d7d00a41SKrystof Tulinger    }
2166d7d00a41SKrystof Tulinger}
2167d7d00a41SKrystof Tulinger
2168d7d00a41SKrystof Tulingerfunction deselectAllProjects() {
2169d7d00a41SKrystof Tulinger    if ($("#project").data(SearchableOptionList.prototype.DATA_KEY)) {
2170d7d00a41SKrystof Tulinger        $("#project").searchableOptionList().deselectAll();
2171d7d00a41SKrystof Tulinger    } else {
2172d7d00a41SKrystof Tulinger        $("#project option").prop('selected', false);
2173d7d00a41SKrystof Tulinger    }
2174d7d00a41SKrystof Tulinger}
2175d7d00a41SKrystof Tulinger
2176d7d00a41SKrystof Tulingerfunction clearSearchFrom() {
2177d7d00a41SKrystof Tulinger    $("#sbox input[type='text']").each(function () {
2178d7d00a41SKrystof Tulinger        $(this).val("");
2179d7d00a41SKrystof Tulinger    });
2180d7d00a41SKrystof Tulinger    $("#type").searchableOptionList().selectRadio("");
2181d7d00a41SKrystof Tulinger}
2182d7d00a41SKrystof Tulinger
2183d7d00a41SKrystof Tulingerfunction getSelectedProjectNames() {
2184d7d00a41SKrystof Tulinger    try {
2185d7d00a41SKrystof Tulinger        return $.map($("#project").searchableOptionList().getSelection().filter("[name='project']"), function (item) {
2186d7d00a41SKrystof Tulinger            return $(item).attr("value");
2187d7d00a41SKrystof Tulinger        });
2188d7d00a41SKrystof Tulinger    } catch (e) { // happens when projects are not enabled
2189d7d00a41SKrystof Tulinger        return [];
2190d7d00a41SKrystof Tulinger    }
2191d7d00a41SKrystof Tulinger}
2192d7d00a41SKrystof Tulinger
2193d7d00a41SKrystof Tulinger/**
2194d7d00a41SKrystof Tulinger * Fold or unfold a function definition.
2195d7d00a41SKrystof Tulinger */
2196d7d00a41SKrystof Tulingerfunction fold(id) {
2197d7d00a41SKrystof Tulinger    $('#' + id + '_fold_icon').
2198d7d00a41SKrystof Tulinger            children().
2199d7d00a41SKrystof Tulinger            first().
2200d7d00a41SKrystof Tulinger            toggleClass('unfold-icon').
2201d7d00a41SKrystof Tulinger            toggleClass('fold-icon');
2202d7d00a41SKrystof Tulinger    $('#' + id + '_fold').toggle('fold');
2203d7d00a41SKrystof Tulinger}
2204d7d00a41SKrystof Tulinger
2205d7d00a41SKrystof Tulingerlet scope_timeout = null;
2206d7d00a41SKrystof Tulinger/**
2207d7d00a41SKrystof Tulinger * Function that is called when the #content div element is scrolled. Checks
2208d7d00a41SKrystof Tulinger * if the top of the page is inside a function scope. If so, update the
2209d7d00a41SKrystof Tulinger * scope element to show the name of the function and a link to its definition.
2210d7d00a41SKrystof Tulinger */
2211d7d00a41SKrystof Tulingerfunction scope_on_scroll() {
2212d7d00a41SKrystof Tulinger    if($.scopesWindow && $.scopesWindow.initialized && !$.scopesWindow.is(':visible')) {
2213d7d00a41SKrystof Tulinger        return;
2214d7d00a41SKrystof Tulinger    }
2215d7d00a41SKrystof Tulinger    if (scope_timeout !== null) {
2216d7d00a41SKrystof Tulinger        clearTimeout(scope_timeout);
2217d7d00a41SKrystof Tulinger        scope_timeout = null;
2218d7d00a41SKrystof Tulinger    }
2219d7d00a41SKrystof Tulinger    scope_timeout = setTimeout(function () {
2220d7d00a41SKrystof Tulinger        const y = $('#whole_header').outerHeight() + 2;
2221d7d00a41SKrystof Tulinger        const c = document.elementFromPoint(15, y + 1);
2222d7d00a41SKrystof Tulinger
2223d7d00a41SKrystof Tulinger        if ($(c).is('.l, .hl')) {
2224d7d00a41SKrystof Tulinger            const $par = $(c).closest('.scope-body, .scope-head');
2225d7d00a41SKrystof Tulinger
2226d7d00a41SKrystof Tulinger            if (!$par.length) {
2227d7d00a41SKrystof Tulinger                return;
2228d7d00a41SKrystof Tulinger            }
2229d7d00a41SKrystof Tulinger
2230d7d00a41SKrystof Tulinger            const $head = $par.hasClass('scope-body') ? $par.prev() : $par;
2231d7d00a41SKrystof Tulinger            const $sig = $head.children().first();
2232d7d00a41SKrystof Tulinger            if ($.scopesWindow.initialized) {
2233d7d00a41SKrystof Tulinger                $.scopesWindow.update({
2234d7d00a41SKrystof Tulinger                    'id': $head.attr('id'),
2235d7d00a41SKrystof Tulinger                    'link': $sig.html()
2236d7d00a41SKrystof Tulinger                });
2237d7d00a41SKrystof Tulinger            }
2238d7d00a41SKrystof Tulinger        }
2239d7d00a41SKrystof Tulinger        scope_timeout = null;
2240d7d00a41SKrystof Tulinger    }, 150);
2241d7d00a41SKrystof Tulinger}
2242d7d00a41SKrystof Tulinger
2243d7d00a41SKrystof Tulinger/**
2244d7d00a41SKrystof Tulinger * Determines whether current page is search page = list with queried documents.
2245d7d00a41SKrystof Tulinger * @returns true if on search page, false otherwise
2246d7d00a41SKrystof Tulinger */
2247d7d00a41SKrystof Tulingerfunction isOnSearchPage() {
2248d7d00a41SKrystof Tulinger    return $(document.documentElement).hasClass('search');
2249d7d00a41SKrystof Tulinger}
2250d7d00a41SKrystof Tulinger
2251d7d00a41SKrystof Tulingerfunction checkIsOnSearchPage() {
2252d7d00a41SKrystof Tulinger    if (isOnSearchPage()) {
2253d7d00a41SKrystof Tulinger        $('#xrd').val("1"); // no redirect
2254d7d00a41SKrystof Tulinger        return true;
2255d7d00a41SKrystof Tulinger    }
2256d7d00a41SKrystof Tulinger    return false;
2257d7d00a41SKrystof Tulinger}
2258d7d00a41SKrystof Tulinger
2259d7d00a41SKrystof Tulinger/**
2260d7d00a41SKrystof Tulinger * Preprocess the searched projects in the form with:
2261d7d00a41SKrystof Tulinger *
2262d7d00a41SKrystof Tulinger * <ol>
2263d7d00a41SKrystof Tulinger *  <li>For all project search -> replace the projects with simple searchall parameter</li>
2264d7d00a41SKrystof Tulinger *  <li>For group search -> replace all projects in a group by the group parameter</li>
2265d7d00a41SKrystof Tulinger * </ol>
2266d7d00a41SKrystof Tulinger * @param form the form containing the checkboxes
2267d7d00a41SKrystof Tulinger */
2268d7d00a41SKrystof Tulingerfunction preprocess_searched_projects(form) {
2269d7d00a41SKrystof Tulinger    const sol = $('#project').searchableOptionList();
2270d7d00a41SKrystof Tulinger
2271d7d00a41SKrystof Tulinger    const $sel = sol.$selectionContainer;
2272d7d00a41SKrystof Tulinger
2273d7d00a41SKrystof Tulinger    /*
2274d7d00a41SKrystof Tulinger     * For all project search check if all project checkbox are checked and then uncheck them (they
2275d7d00a41SKrystof Tulinger     * would appear in the url) and add a hidden checkbox with searchall name.
2276d7d00a41SKrystof Tulinger     */
2277d7d00a41SKrystof Tulinger    const allProjectsSearch = $.makeArray($sel.find('.sol-checkbox[name=project]')).every(function (checkbox) {
2278d7d00a41SKrystof Tulinger        return $(checkbox).is(':checked');
2279d7d00a41SKrystof Tulinger    });
2280d7d00a41SKrystof Tulinger
2281d7d00a41SKrystof Tulinger    if (allProjectsSearch && $('#search_all_projects').length === 0) {
2282d7d00a41SKrystof Tulinger        $sel.find('.sol-checkbox').prop('checked', false);
2283d7d00a41SKrystof Tulinger        const $input = $('<input>');
2284d7d00a41SKrystof Tulinger        const $all = $input.
2285d7d00a41SKrystof Tulinger            attr({
2286d7d00a41SKrystof Tulinger                id: 'search_all_projects',
2287d7d00a41SKrystof Tulinger                type: 'checkbox',
2288d7d00a41SKrystof Tulinger                value: true,
2289d7d00a41SKrystof Tulinger                name: 'searchall'
2290d7d00a41SKrystof Tulinger            }).
2291d7d00a41SKrystof Tulinger            prop('checked', true).
2292d7d00a41SKrystof Tulinger            css('display', 'none');
2293d7d00a41SKrystof Tulinger        $all.appendTo($(form));
2294d7d00a41SKrystof Tulinger        return;
2295d7d00a41SKrystof Tulinger    }
2296d7d00a41SKrystof Tulinger
2297d7d00a41SKrystof Tulinger    /*
2298d7d00a41SKrystof Tulinger     * For selecting groups instead of projects, ommit the "Other" group. Loop over
2299d7d00a41SKrystof Tulinger     * all project checkbox in a group and when all of them are checked, uncheck them (they
2300d7d00a41SKrystof Tulinger     * would appear in the URL) and then check the group checkbox.
2301d7d00a41SKrystof Tulinger     */
2302d7d00a41SKrystof Tulinger    $sel.find('.sol-optiongroup').each(function () {
2303d7d00a41SKrystof Tulinger        const $el = $(this);
2304d7d00a41SKrystof Tulinger
2305d7d00a41SKrystof Tulinger        // handle "Other" group for ungrouped projects
2306d7d00a41SKrystof Tulinger        if ($el.find('.sol-optiongroup-label').text() === 'Other') {
2307d7d00a41SKrystof Tulinger            $el.find('.sol-checkbox[name=group]').prop('checked', false);
2308d7d00a41SKrystof Tulinger            return;
2309d7d00a41SKrystof Tulinger        }
2310d7d00a41SKrystof Tulinger
2311d7d00a41SKrystof Tulinger        const checkboxs = $el.find('.sol-option .sol-checkbox');
2312d7d00a41SKrystof Tulinger        for (let i = 0; i < checkboxs.length; i++) {
2313d7d00a41SKrystof Tulinger            const checkbox = $(checkboxs[i]);
2314d7d00a41SKrystof Tulinger            if (!checkbox.is(":checked")) {
2315d7d00a41SKrystof Tulinger                return;
2316d7d00a41SKrystof Tulinger            }
2317d7d00a41SKrystof Tulinger        }
2318d7d00a41SKrystof Tulinger
2319d7d00a41SKrystof Tulinger        $el.find('.sol-checkbox[name=group]').prop('checked', true);
2320d7d00a41SKrystof Tulinger        for (let j = 0; j < checkboxs.length; j++) {
2321d7d00a41SKrystof Tulinger            const cb = $(checkboxs[j]);
2322d7d00a41SKrystof Tulinger            cb.prop('checked', false);
2323d7d00a41SKrystof Tulinger        }
2324d7d00a41SKrystof Tulinger    });
2325d7d00a41SKrystof Tulinger}
2326d7d00a41SKrystof Tulinger
2327d7d00a41SKrystof Tulinger/**
2328d7d00a41SKrystof Tulinger * Handles submit on search form.
2329d7d00a41SKrystof Tulinger *
2330d7d00a41SKrystof Tulinger * If submit was initiated by pressing the return key when focus was
2331d7d00a41SKrystof Tulinger * in a text field then `si` attribute will be added to the form.
2332d7d00a41SKrystof Tulinger *
2333d7d00a41SKrystof Tulinger * @param {HTMLFormElement} form
2334d7d00a41SKrystof Tulinger */
2335d7d00a41SKrystof Tulingerfunction searchSubmit(form) {
2336d7d00a41SKrystof Tulinger    let submitInitiator = '';
2337d7d00a41SKrystof Tulinger    if (textInputHasFocus()) {
2338d7d00a41SKrystof Tulinger        submitInitiator = document.activeElement.getAttribute('id');
2339d7d00a41SKrystof Tulinger    }
2340d7d00a41SKrystof Tulinger    if (submitInitiator) {
2341d7d00a41SKrystof Tulinger        const input = document.createElement('INPUT');
2342d7d00a41SKrystof Tulinger        input.setAttribute('name', 'si');
2343d7d00a41SKrystof Tulinger        input.value = submitInitiator;
2344d7d00a41SKrystof Tulinger        input.type = 'hidden';
2345d7d00a41SKrystof Tulinger        form.appendChild(input);
2346d7d00a41SKrystof Tulinger    }
2347d7d00a41SKrystof Tulinger
2348d7d00a41SKrystof Tulinger    // replace all projects search with searchall parameter
2349d7d00a41SKrystof Tulinger    // select groups instead of projects if all projects in one group are selected
2350d7d00a41SKrystof Tulinger    preprocess_searched_projects(form);
2351d7d00a41SKrystof Tulinger}
2352d7d00a41SKrystof Tulinger
2353d7d00a41SKrystof Tulinger/**
2354d7d00a41SKrystof Tulinger * Restores focus on page load
2355d7d00a41SKrystof Tulinger *
2356d7d00a41SKrystof Tulinger * @see #searchSubmit
2357d7d00a41SKrystof Tulinger */
2358d7d00a41SKrystof Tulingerfunction restoreFocusAfterSearchSubmit() {
2359d7d00a41SKrystof Tulinger    const siParam = getParameter('si');
2360d7d00a41SKrystof Tulinger    if (siParam) {
2361d7d00a41SKrystof Tulinger        const $input = $('input[type=text][id="' + siParam + '"]');
2362d7d00a41SKrystof Tulinger        if ($input.length === 1) {
2363d7d00a41SKrystof Tulinger            $input[0].selectionStart = $input.val().length;
2364d7d00a41SKrystof Tulinger            $input[0].selectionEnd = $input[0].selectionStart;
2365d7d00a41SKrystof Tulinger            $input.focus();
2366d7d00a41SKrystof Tulinger        }
2367d7d00a41SKrystof Tulinger    }
2368d7d00a41SKrystof Tulinger}
2369d7d00a41SKrystof Tulinger
2370d7d00a41SKrystof Tulinger/**
2371d7d00a41SKrystof Tulinger * @return {boolean} true if focus is on a input[type=text] element
2372d7d00a41SKrystof Tulinger */
2373d7d00a41SKrystof Tulingerfunction textInputHasFocus() {
2374d7d00a41SKrystof Tulinger    return !!document.activeElement &&
2375d7d00a41SKrystof Tulinger        document.activeElement.nodeName === 'INPUT' &&
2376d7d00a41SKrystof Tulinger        document.activeElement.type === 'text';
2377d7d00a41SKrystof Tulinger}
2378d7d00a41SKrystof Tulinger
2379d7d00a41SKrystof Tulingerfunction escapeHtml(string) { // taken from https://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
2380d7d00a41SKrystof Tulinger    const htmlEscapeMap = {
2381d7d00a41SKrystof Tulinger        '&': '&amp;',
2382d7d00a41SKrystof Tulinger        '<': '&lt;',
2383d7d00a41SKrystof Tulinger        '>': '&gt;',
2384d7d00a41SKrystof Tulinger        '"': '&quot;',
2385d7d00a41SKrystof Tulinger        "'": '&#39;',
2386d7d00a41SKrystof Tulinger        '/': '&#x2F;',
2387d7d00a41SKrystof Tulinger        '`': '&#x60;',
2388d7d00a41SKrystof Tulinger        '=': '&#x3D;'
2389d7d00a41SKrystof Tulinger    };
2390d7d00a41SKrystof Tulinger    return String(string).replace(/[&<>"'`=\/]/g, function (s) {
2391d7d00a41SKrystof Tulinger        return htmlEscapeMap[s];
2392d7d00a41SKrystof Tulinger    });
2393d7d00a41SKrystof Tulinger}
2394d7d00a41SKrystof Tulinger
2395d7d00a41SKrystof Tulinger/**
2396d7d00a41SKrystof Tulinger * Returns user-specific local settings for a provided key.
2397d7d00a41SKrystof Tulinger * @param key settings key
2398d7d00a41SKrystof Tulinger * @returns {string} settings value or {@code undefined} if not set
2399d7d00a41SKrystof Tulinger */
2400d7d00a41SKrystof Tulingerfunction getSettingsValue(key) {
2401d7d00a41SKrystof Tulinger    return localStorage.getItem(key);
2402d7d00a41SKrystof Tulinger}
2403d7d00a41SKrystof Tulinger
2404d7d00a41SKrystof Tulinger/**
2405d7d00a41SKrystof Tulinger * Event listener which stores user-specific settings change for an {@code input} element.
2406d7d00a41SKrystof Tulinger * @param el settings {@code input} element
2407d7d00a41SKrystof Tulinger */
2408d7d00a41SKrystof Tulingerfunction onSettingsValueChange(el) {
2409d7d00a41SKrystof Tulinger    let value = getSettingsInputValue(el);
2410d7d00a41SKrystof Tulinger    localStorage.setItem(el.name, value);
2411d7d00a41SKrystof Tulinger}
2412d7d00a41SKrystof Tulinger
2413d7d00a41SKrystof Tulinger/**
2414d7d00a41SKrystof Tulinger * Decodes a settings value from a settings {@code input} element.
2415d7d00a41SKrystof Tulinger * @param el settings {@code input} element
2416d7d00a41SKrystof Tulinger * @returns {string|*} settings value
2417d7d00a41SKrystof Tulinger */
2418d7d00a41SKrystof Tulingerfunction getSettingsInputValue(el) {
2419d7d00a41SKrystof Tulinger    if (el.type === 'checkbox') {
2420d7d00a41SKrystof Tulinger        if (el.checked) {
2421d7d00a41SKrystof Tulinger            return el.dataset.checkedValue;
2422d7d00a41SKrystof Tulinger        } else {
2423d7d00a41SKrystof Tulinger            return el.dataset.uncheckedValue;
2424d7d00a41SKrystof Tulinger        }
2425d7d00a41SKrystof Tulinger    } else {
2426d7d00a41SKrystof Tulinger        return el.value;
2427d7d00a41SKrystof Tulinger    }
2428d7d00a41SKrystof Tulinger}
2429d7d00a41SKrystof Tulinger
2430d7d00a41SKrystof Tulinger/**
2431d7d00a41SKrystof Tulinger * Resets all settings elements with class {@code local-setting} to their default values.
2432d7d00a41SKrystof Tulinger */
2433d7d00a41SKrystof Tulingerfunction resetAllSettings() {
2434d7d00a41SKrystof Tulinger    for (const el of document.getElementsByClassName('local-setting')) {
2435d7d00a41SKrystof Tulinger        setDefaultSettingsValue(el);
2436d7d00a41SKrystof Tulinger        onSettingsValueChange(el);
2437d7d00a41SKrystof Tulinger    }
2438d7d00a41SKrystof Tulinger}
2439d7d00a41SKrystof Tulinger
2440d7d00a41SKrystof Tulinger/**
2441d7d00a41SKrystof Tulinger * Sets a default value for a settings {@code input} element.
2442d7d00a41SKrystof Tulinger * @param el settings {@code input} element
2443d7d00a41SKrystof Tulinger */
2444d7d00a41SKrystof Tulingerfunction setDefaultSettingsValue(el) {
2445d7d00a41SKrystof Tulinger    setSettingsInputValue(el, el.dataset.defaultValue);
2446d7d00a41SKrystof Tulinger}
2447d7d00a41SKrystof Tulinger
2448d7d00a41SKrystof Tulinger/**
2449d7d00a41SKrystof Tulinger * Sets the settings {@code input} element value to the provided one.
2450d7d00a41SKrystof Tulinger * @param el element to change
2451d7d00a41SKrystof Tulinger * @param value value to set
2452d7d00a41SKrystof Tulinger */
2453d7d00a41SKrystof Tulingerfunction setSettingsInputValue(el, value) {
2454d7d00a41SKrystof Tulinger    if (el.type === 'checkbox') {
2455d7d00a41SKrystof Tulinger        el.checked = el.dataset.checkedValue === value;
2456d7d00a41SKrystof Tulinger    } else {
2457d7d00a41SKrystof Tulinger        el.value = value;
2458d7d00a41SKrystof Tulinger    }
2459d7d00a41SKrystof Tulinger}
2460d7d00a41SKrystof Tulinger
2461d7d00a41SKrystof Tulinger/**
2462d7d00a41SKrystof Tulinger * Initializes all settings elements with {@code local-setting} class.
2463d7d00a41SKrystof Tulinger */
2464d7d00a41SKrystof Tulingerfunction initSettings() {
2465d7d00a41SKrystof Tulinger    for (const el of document.getElementsByClassName('local-setting')) {
2466d7d00a41SKrystof Tulinger        const value = getSettingsValue(el.name);
2467d7d00a41SKrystof Tulinger        if (value) {
2468d7d00a41SKrystof Tulinger            setSettingsInputValue(el, value);
2469d7d00a41SKrystof Tulinger        } else {
2470d7d00a41SKrystof Tulinger            setDefaultSettingsValue(el);
2471d7d00a41SKrystof Tulinger        }
2472d7d00a41SKrystof Tulinger    }
2473d7d00a41SKrystof Tulinger}
2474