PageSourceSearch

https://adsh.al/modules/AdvancedSearch/asset/js/global.js?v=3.4.15

js adsh.al collected 2026-10-03 00:53:07 UTC 15,918 bytes, 392 lines download raw bytes

1/**
2 * Adapted for modules AdvancedResourceTemplate and AdvancedSearch.
3 * Contains fixes pulled on github.
4 */
5
6var Omeka = {
7    openSidebar : function(sidebar) {
8        sidebar.addClass('active');
9        this.reserveSidebarSpace();
10        sidebar.trigger('o:sidebar-opened');
11        if ($('.active.sidebar').length > 1) {
12            var highestIndex = 3; // The CSS currently defines the default sidebar z-index as 3.
13            $('.active.sidebar').each(function() {
14                var currentIndex = parseInt($(this).css('zIndex'), 10);
15                if (currentIndex > highestIndex) {
16                    highestIndex = currentIndex;
17                }
18            });
19            sidebar.css('zIndex', highestIndex + 1);
20        }
21    },
22
23    closeSidebar : function(sidebar) {
24        sidebar.removeClass('active');
25        this.reserveSidebarSpace();
26        sidebar.trigger('o:sidebar-closed');
27    },
28
29    reserveSidebarSpace: function() {
30        var openSidebars = $('.active.sidebar, .always-open.sidebar').length
31            - $('.section:not(.active) .active.sidebar, .section:not(.active) .always-open.sidebar').length;
32        $('body').toggleClass('sidebar-open', openSidebars > 0);
33    },
34
35    populateSidebarContent : function(sidebar, url, data) {
36        var sidebarContent = sidebar.find('.sidebar-content');
37        sidebar.addClass('loading');
38        sidebarContent.empty();
39        $.get(url, data)
40            .done(function(data) {
41                sidebarContent.html(data);
42                $(sidebar).trigger('o:sidebar-content-loaded');
43            })
44            .fail(function() {
45                sidebarContent.html('<p>' + Omeka.jsTranslate('Something went wrong') + '</p>');
46            })
47            .always(function () {
48                sidebar.removeClass('loading');
49            });
50    },
51
52    switchActiveSection: function (section) {
53        var closedSection = $('.section.active');
54        var sectionId = '#' + section.attr('id');
55        $('.section.active, .section-nav li.active').removeClass('active');
56        section.addClass('active');
57        $('.section-nav a[href="' + sectionId + '"]').parent().addClass('active');
58        if (!$('body').hasClass('no-section-hashes')) {
59            history.replaceState(null, document.title, sectionId);
60        }
61        this.reserveSidebarSpace();
62        if (!closedSection.is(section)) {
63            if (closedSection.length > 0) {
64                closedSection.trigger('o:section-closed');
65            }
66            section.trigger('o:section-opened');
67        }
68    },
69
70    filterSelector : function() {
71        var filter = $(this).val().toLowerCase();
72        var selector = $(this).closest('.selector');
73        var totalCount = 0;
74        selector.find('li.selector-parent').each(function() {
75            var parent = $(this);
76            var count = 0;
77            parent.find('li.selector-child').each(function() {
78                var child = $(this);
79                var label = child.data('child-search').toLowerCase();
80                if ((label.indexOf(filter) < 0) || (child.hasClass('added'))) {
81                    // Label doesn't contain the filter string. Hide the child.
82                    child.addClass('filter-hidden');
83                } else {
84                    // Label contains the filter string. Show the child.
85                    child.removeClass('filter-hidden');
86                    totalCount++;
87                    count++;
88                }
89            });
90            if (count > 0) {
91                parent.removeClass('empty');
92            } else {
93                parent.addClass('empty');
94            }
95            parent.children('span.selector-child-count').text(count);
96        });
97        if (filter == '') {
98            selector.find('li.selector-parent').removeClass('show');
99            $('.filter-match').removeClass('filter-match');
100        }
101        selector.find('span.selector-total-count').text(totalCount);
102    },
103
104    updateSearch: function () {
105        var checkedOption = $("#advanced-options input[type='radio']:checked ");
106        $("#search-form").attr("action", checkedOption.data('action'));
107        $("#search-form > input[type='text']").attr("placeholder", checkedOption.data('inputPlaceholder')).attr("aria-label", checkedOption.data('inputPlaceholder'));
108    },
109
110    scrollTo: function(wrapper) {
111        if (wrapper.length) {
112            $('html, body').animate({
113                scrollTop: (wrapper.offset().top -100)
114            },200);
115        }
116    },
117
118    markDirty: function(form) {
119        $(form).data('omekaFormDirty', true);
120    },
121
122    fixIframeAspect: function () {
123        $('iframe').each(function () {
124            var aspect = $(this).attr('height') / $(this).attr('width');
125            $(this).height($(this).width() * aspect);
126        });
127    },
128
129    framerateCallback: function(callback) {
130        var waiting = false;
131        callback = callback.bind(this);
132        return function () {
133            if (!waiting) {
134                waiting = true;
135                window.requestAnimationFrame(function () {
136                    callback();
137                    waiting = false;
138                });
139            }
140        }
141    },
142
143    warnIfUnsaved: function() {
144        var setSubmittedFlag = function () {
145            $(this).data('omekaFormSubmitted', true);
146        };
147
148        var setOriginalData = function () {
149            $(this).data('omekaFormOriginalData', $(this).serialize());
150        };
151
152        var formsToCheck = $('form[method=POST]:not(.disable-unsaved-warning)');
153        formsToCheck.on('o:form-loaded', setOriginalData);
154        formsToCheck.each(function () {
155            var form = $(this);
156            form.trigger('o:form-loaded');
157            form.submit(setSubmittedFlag);
158        });
159
160        $(window).on('beforeunload', function() {
161            var preventNav = false;
162            formsToCheck.each(function () {
163                var form = $(this);
164                var originalData = form.data('omekaFormOriginalData');
165                var hasFile = false;
166                if (form.data('omekaFormSubmitted')) {
167                    return;
168                }
169
170                form.trigger('o:before-form-unload');
171
172                form.find('input[type=file]').each(function () {
173                    if (this.files.length) {
174                        hasFile = true;
175                        return false;
176                    }
177                });
178
179                if (form.data('omekaFormDirty')
180                    || (originalData && originalData !== form.serialize())
181                    || hasFile
182                ) {
183                    preventNav = true;
184                    return false;
185                }
186            });
187
188            if (preventNav) {
189                return 'You have unsaved changes.';
190            }
191        });
192    },
193
194    manageSelectedActions: function() {
195        var selectedOptions = $('#batch-form .batch-inputs [value$=selected]');
196        if ($('.batch-edit td input[type="checkbox"]:checked').length > 0) {
197            selectedOptions.removeAttr('disabled');
198        } else {
199            selectedOptions.attr('disabled', true);
200            $('.batch-actions-select').val('default');
201            $('.batch-actions .active').removeClass('active');
202            $('.batch-actions .default').addClass('active');
203        }
204    },
205
206    initializeSelector : function(tableId, selectorId) {
207        var table = $(tableId);
208        var existingRowData = table.data('existing-rows') || [];
209        var rowTemplate = $($.parseHTML(table.data('rowTemplate')));
210        var selector = $(selectorId);
211        var totalCount = selector.find('.resources-available').data('all-resources-count');
212        var selectorCount = selector.find('.selector-total-count');
213
214        var parentToggle = function(e) {
215            e.stopPropagation();
216            if ($(this).children('li')) {
217                $(this).toggleClass('show');
218            }
219        }
220
221        var appendRow = function(id) {
222            if (table.find(".resource-id[value='" + id + "']").length) {
223                return;
224            }
225            var tableRow = rowTemplate.clone();
226            var selectorRow = selector.find('[data-resource-id="' + id + '"]');
227            tableRow.find('.resource-id').val(id);
228            tableRow.find('.data-value').each(function() {
229                var tableRowCell = $(this);
230                var tableRowKey = tableRowCell.data('row-key');
231                var tableRowValue = selectorRow.data(tableRowKey);
232                tableRowCell.text(tableRowValue);
233            });
234            selectorRow.addClass('added');
235            table.append(tableRow).removeClass('empty').trigger('appendRow');
236            updateResourceCount(id);
237        }
238
239        var updateResourceCount = function(id) {
240            var resource = selector.find('[data-resource-id="' + id + '"]');
241            var resourceParent = resource.parents('.selector-parent');
242            var childCount = resourceParent.find('.selector-child-count').first();
243            if (resource.hasClass('added')) {
244                var newTotalCount = parseInt(selectorCount.text()) - 1;
245                var newChildCount = parseInt(childCount.text()) - 1;
246            } else {
247                var newTotalCount = parseInt(selectorCount.text()) + 1;
248                var newChildCount = parseInt(childCount.text()) + 1;
249            }
250            selectorCount.text(newTotalCount);
251            childCount.text(newChildCount);
252            var currentRows = table.find('.resource-row').length;
253            if (totalCount - currentRows == 0) {
254                selector.find('.resources-available').addClass('empty');
255            } else {
256                selector.find('.resources-available').removeClass('empty');
257            }
258            if (newChildCount == 0) {
259                resourceParent.addClass('empty');
260            } else {
261                resourceParent.removeClass('empty');
262            }
263        }
264
265        if (existingRowData.length > 0) {
266            $.each(existingRowData, function() {
267                appendRow(this.id);
268            });
269            table.removeClass('empty');
270        }
271
272        // Add the selected resource to the edit panel.
273        $(selectorId + ' .selector-child').on('click', function(e) {
274            e.stopPropagation();
275            var selectorRow = $(this);
276            var selectorParent = selectorRow.parents('.selector-parent');
277            selectorParent.unbind('click');
278            appendRow(selectorRow.data('resource-id'));
279            selectorParent.bind('click', parentToggle);
280            Omeka.scrollTo(table.find('.resource-row:last-child'));
281        });
282
283        // Remove a resource from the edit panel.
284        table.on('click', '.o-icon-delete', function(e) {
285            e.preventDefault();
286            var row = $(this).closest('.resource-row');
287            var resourceId = row.find('.resource-id').val();
288            selector.find('[data-resource-id="' + resourceId + '"]').removeClass('added');
289            row.remove();
290            updateResourceCount(resourceId);
291            if ($('.resource-row').length < 1) {
292                table.addClass('empty');
293            }
294        });
295    },
296
297
298    // @see http://stackoverflow.com/questions/7035825/regular-expression-for-a-language-tag-as-defined-by-bcp47
299    // Removes `|[A-Za-z]{4}|[A-Za-z]{5,8}` from the "language" portion because,
300    // while in the spec, it does not represent current usage.
301    langIsValid: function(lang) {
302        return lang.match(/^(((en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|n
302o-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((([A-Za-z]{2,3}(-([A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?))(-([A-Za-z]{4}))?(-([A-Za-z]{2}|[0-9]{3}))?(-([A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-([0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(x(-[A-Za-z0-9]{1,8})+))?)|(x(-[A-Za-z0-9]{1,8})+))$/);
303    },
304
305    // Index of property search values.
306    propertySearchIndex: null,
307
308    // Prepare the search form. Must be called any time the form is loaded.
309    prepareSearchForm: function(form) {
310        // The property values need an index.
311        Omeka.propertySearchIndex = $('#property-queries .value').length;
312        // Prepare the multi-value templates used for duplicating values.
313        $('.multi-value.field').each(function() {
314            var field = $(this);
315            var value = field.find('.value').first().clone();
316            var valueHtml = value.wrap('<div></div>').parent().html();
317            field.data('field-template', valueHtml);
318        });
319        form.find('.query-type').each(Omeka.disableQueryTextInput);
320    },
321
322    // Disable query text according to query type.
323    disableQueryTextInput: function() {
324        var queryType = $(this);
325        var queryText = queryType.siblings('.query-text');
326        queryText.prop('disabled', ['ex', 'nex', 'exs', 'nexs', 'exm', 'nexm', 'lex', 'nlex', 'tpl', 'ntpl', 'tpr', 'ntpr', 'tpu', 'ntpu'].includes(queryType.val()));
327    },
328
329    // Clean the search query of empty or otherwise unneeded inputs.
330    cleanSearchQuery: function(form) {
331        form.find(':input').each(function(index) {
332            const input = $(this);
333            const inputName = input.attr('name');
334            const inputValue = input.val();
335            if (inputName && '' === inputValue) {
336                const inputNames = [
337                    'fulltext_search',
338                    'resource_class_id[]',
339                    'resource_template_id[]',
340                    'item_set_id[]',
341                    'site_id',
342                    'owner_id',
343                    'media_type',
344                    'sort_by',
345                    'sort_order',
346                    'is_public',
347                    'has_media',
348                    'id',
349                ];
350                if (inputNames.includes(inputName)) {
351                    input.prop('name', '');
352                } else {
353                    const match = inputName.match(/property\[(\d+)\]\[text\]/);
354                    if (match) {
355                        const propertyType = form.find(`[name="property[${match[1]}][type]"]`);
356                        if (['eq', 'neq', 'in', 'nin', 'res', 'nres', 'list', 'nlist', 'sw', 'nsw', 'ew', 'new', 'near', 'nnear', 'lres', 'nlres', 'tp', 'ntp', 'dtp', 'ndtp', 'gt', 'gte', 'lte', 'lt']
357                            .includes(propertyType.val())
358                        ) {
359                            form.find(`[name="property[${match[1]}][joiner]"]`).prop('name', '');
360                            form.find(`[name="property[${match[1]}][property]"]`).prop('name', '');
361                            form.find(`[name="property[${match[1]}][text]"]`).prop('name', '');
362                            propertyType.prop('name', '');
363                        }
364                    }
365                }
366            }
367        });
368    },
369
370    closeOpenPageActionsMenu: function(e) {
371        var button = $('.page-action-menu .collapse');
372        if (button.length > 0) {
373            button.click();
374        }
375    }
376};
377
378$(document).ready(function() {
379        // Set classes for expandable/collapsible content.
380        $(document).on('click', 'a.expand, a.collapse', function(e) {
381            e.preventDefault();
382            var toggle = $(this);
383            toggle.toggleClass('collapse').toggleClass('expand');
384            if (toggle.hasClass('expand')) {
385                toggle.attr('aria-label', Omeka.jsTranslate('Expand')).attr('title', Omeka.jsTranslate('Expand'));
386                toggle.trigger('o:collapsed');
387            } else {
388                toggle.attr('aria-label', Omeka.jsTranslate('Collapse')).attr('title', Omeka.jsTranslate('Collapse'));
389                toggle.trigger('o:expanded');
390            }
391        });
392});

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