File size: 6,853 Bytes
046723b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
(function ($) {
    /**
     * debounce
     * @param {integer} milliseconds This param indicates the number of milliseconds
     *     to wait after the last call before calling the original function.
     * @param {object} What "this" refers to in the returned function.
     * @return {function} This returns a function that when called will wait the
     *     indicated number of milliseconds after the last call before
     *     calling the original function.
     */
    Function.prototype.debounce = function (milliseconds, context) {
        var baseFunction = this,
            timer = null,
            wait = milliseconds;

        return function () {
            var self = context || this,
                args = arguments;

            function complete() {
                baseFunction.apply(self, args);
                timer = null;
            }

            if (timer) {
                clearTimeout(timer);
            }

            timer = setTimeout(complete, wait);
        };
    };

    /**
     * throttle
     * @param {integer} milliseconds This param indicates the number of milliseconds
     *     to wait between calls before calling the original function.
     * @param {object} What "this" refers to in the returned function.
     * @return {function} This returns a function that when called will wait the
     *     indicated number of milliseconds between calls before
     *     calling the original function.
     */
    Function.prototype.throttle = function (milliseconds, context) {
        var baseFunction = this,
            lastEventTimestamp = null,
            limit = milliseconds;

        return function () {
            var self = context || this,
                args = arguments,
                now = Date.now();

            if (!lastEventTimestamp || now - lastEventTimestamp >= limit) {
                lastEventTimestamp = now;
                baseFunction.apply(self, args);
            }
        };
    };

    $.fn.highlightLines = function (configurations) {
        return this.each(function () {
            const $pre = $(this);
            const textContent = $pre.text();
            const lines = textContent.split(/\r?\n/); // Handles both \n and \r\n line endings

            // Build a map of line numbers to styles
            const lineStyles = {};

            configurations.forEach(config => {
                const {color, lines: lineNumbers} = config;
                lineNumbers.forEach(lineNumber => {
                    lineStyles[lineNumber] = color;
                });
            });

            // Function to escape HTML characters
            function escapeHtml(text) {
                return text.replace(/[&<>"'`=\/]/g, function (s) {
                    return "&#" + s.charCodeAt(0) + ";";
                });
            }

            // Process each line
            const processedLines = lines.map((line, index) => {
                const lineNumber = index + 1; // Line numbers start at 1
                const escapedLine = escapeHtml(line);
                const color = lineStyles[lineNumber];

                if (color) {
                    // Wrap the line in a span with inline style
                    return `<span style="background-color: ${color}">${escapedLine}</span>`;
                } else {
                    return escapedLine;
                }
            });

            // Join the lines back together
            const newContent = processedLines.join('\n');

            // Set the new content as HTML
            $pre.html(newContent);
        });
    };
    $.fn.miniTabs = function (tabsConfig, options) {
        const settings = {
            tabClass: 'minitab',
            tabsContainerClass: 'minitabs',
            activeClass: 'active',
            ...(options || {})
        };

        return this.each(function () {
            const $wrapper = $(this);
            const $contents = $wrapper.find('div[id]').hide();
            const $tabsContainer = $('<div>', {class: settings.tabsContainerClass}).prependTo($wrapper);

            // Generate tabs
            Object.entries(tabsConfig).forEach(([tabTitle, contentSelector], index) => {
                const $content = $wrapper.find(contentSelector);
                if (index === 0) $content.show(); // Show first content by default

                $('<a>', {
                    class: `${settings.tabClass}${index === 0 ? ` ${settings.activeClass}` : ''}`,
                    text: tabTitle,
                    'data-target': contentSelector
                }).appendTo($tabsContainer);
            });

            // Tab click event
            $tabsContainer.on('click', `.${settings.tabClass}`, function (e) {
                e.preventDefault();
                const $tab = $(this);
                const target = $tab.data('target');

                // Update active tab
                $tabsContainer.find(`.${settings.tabClass}`).removeClass(settings.activeClass);
                $tab.addClass(settings.activeClass);

                // Show/hide content
                $contents.hide();
                $wrapper.find(target).show();
            });
        });
    };

    // Object to store ongoing requests by namespace
    const requests = {};

    $.abortiveSingularAjax = function (options) {
        const namespace = options.namespace || 'default';

        // Abort the current request in this namespace if it's still ongoing
        if (requests[namespace]) {
            requests[namespace].abort();
        }

        // Start a new AJAX request and store its reference in the correct namespace
        requests[namespace] = $.ajax(options);

        // Return the current request in case it's needed
        return requests[namespace];
    };
})(jQuery);



function toggleOpacity(checkboxSelector, fieldSelector, inverted) {
    const checkbox = document.querySelector(checkboxSelector);
    const fields = document.querySelectorAll(fieldSelector);

    function updateOpacity() {
        const opacityValue = !checkbox.checked ? (inverted ? 0.6 : 1) : (inverted ? 1 : 0.6);
        fields.forEach(field => {
            field.style.opacity = opacityValue;
        });
    }

    // Initial setup
    updateOpacity();
    checkbox.addEventListener('change', updateOpacity);
}

function toggleVisibility(checkboxSelector, fieldSelector, inverted) {
    const checkbox = document.querySelector(checkboxSelector);
    const fields = document.querySelectorAll(fieldSelector);

    function updateOpacity() {
        const opacityValue = !checkbox.checked ? (inverted ? 'none' : 'block') : (inverted ? 'block' : 'none');
        fields.forEach(field => {
            field.style.display = opacityValue;
        });
    }

    // Initial setup
    updateOpacity();
    checkbox.addEventListener('change', updateOpacity);
}