PageSourceSearch

https://www.landwirtschaft-bw.de/site/pbs-bw-rebrush2024/resourceCached/259/pluginLib/pluginLib.415974911.js

js landwirtschaft-bw.de collected 2026-10-09 22:10:19 UTC 24,635 bytes, 772 lines download raw bytes

1(function($) {
2    $.fn.autosubmit = function() {
3        this.submit(function(event) {
4            event.preventDefault();
5            var form = $(this);
6
7            $('<input>').attr({
8                type : 'hidden',
9                id : 'isExtended',
10                name : 'isExtended',
11                value : 'true'
12            }).appendTo(form);
13            $('<input>').attr({
14                type : 'hidden',
15                id : 'performSearchAfterFilter',
16                name : 'performSearchAfterFilter',
17                value : 'false'
18            }).appendTo(form);
19            $.ajax({
20                type : 'POST',
21                url : form.attr('action'),
22                data : form.serialize()
23            }).done(function(data) {
24                var query = form.find('input[name="query"]').val(),
25                    token = form.find('input[name="viewSecurityToken"]').val(),
26                    urlParams = '';
27                query = encodeURIComponent(query);
28
29                if(window.location.href.indexOf('?')>0) {
30                    var params = window.location.href.substring(window.location.href.indexOf('?')+1).split('&');
31                    for(var i=0;i<params.length;i++) {
32                        if (params[i] && params[i] !== 'cached' && params[i].indexOf('viewSecurityToken=') && params[i].indexOf('query=')) {
33                            urlParams += params[i] + '&';
34                        }
35                    }
36                }
37
38                window.location.replace(window.location.href.split('?')[0] + '?' + urlParams + 'cached&viewSecurityToken=' + token + '&query=' + query);
39            }).fail(function(data) {});
40        });
41        return this;
42    }
43})(jQuery)
44
45function search_addFinishParam(button, formId) {
46    $('<input>').attr({
47        type : 'hidden',
48        id : 'finishParam',
49        name : 'finishParam',
50        value : button.value
51    }).appendTo($('form[name=' + formId + ']'));
52}
53
54function search_addFinishParamFromPagination(link, formId) {
55    let pageValue = $(link).data('page');
56    $('<input>').attr({
57        type: 'hidden',
58        name: 'finishParam',
59        value: pageValue
60    }).appendTo($('form[name=' + formId + ']'));
61
62    const $searchForm = $('#searchForm');
63    const $pageInput = $searchForm.find('input[name="page"]');
64
65    try {
66        pageValue = JSON.parse(pageValue.replace(/'/g, '"')).page;
67        $pageInput.val(pageValue);
68
69        $searchForm.submit();
70    } catch (error) {
71        console.error('Fehler beim Verarbeiten des Pagination-Buttons:', error);
72    }
73}
74
75$(function () {
76    initSorting();
77    initMimetype();
78    processUrlParams();
79});
80
81function initSorting() {
82    const $sortButtons = $('.sort-links__link');
83    const $searchForm = $('#searchForm');
84    const $sortInput = $searchForm.find('input[name="sort"]');
85    const $orderInput = $searchForm.find('input[name="order"]');
86
87    $sortButtons.on('click', function () {
88        try {
89            const sortParams = JSON.parse($(this).val().replace(/'/g, '"'));
90            $sortInput.val(sortParams.sort);
91            $orderInput.val(sortParams.order);
92            $searchForm.submit();
93        } catch (error) {
94            console.error('Fehler beim Verarbeiten des Sortier-Buttons:', error);
95        }
96    });
97}
98
99function initMimetype() {
100    function ensureDefaultMimetypes() {
101        const defaultMimetypes = ['documents', 'text'];
102        const mimetypesSelect = $('#mimetypes');
103
104        if (localStorage.getItem('noMimetypesSelected') === 'true') {
105            return;
106        }
107        if (!mimetypesSelect.val() || mimetypesSelect.val().length === 0) {
108            mimetypesSelect.val(defaultMimetypes);
109        }
110    }
111
112    ensureDefaultMimetypes();
113
114    $('#searchForm').on('submit', function () {
115        var mimetypesSelect = $('#mimetypes');
116        if (!mimetypesSelect.val() || mimetypesSelect.val().length === 0) {
117            localStorage.setItem('noMimetypesSelected', 'true');
118        } else {
119            localStorage.removeItem('noMimetypesSelected');
120        }
121        ensureDefaultMimetypes();
122    });
123}
124
125function processUrlParams() {
126    const urlParams = new URLSearchParams(window.location.search);
127    const $queryInput = $('input[name="query"]');
128
129    if (urlParams.has('queryString')) {
130        const queryValue = urlParams.get('queryString').trim();
131        urlParams.delete('queryString');
132        $queryInput.val(queryValue);
133
134        const newUrl = urlParams.toString() ? window.location.pathname + '?' + urlParams.toString() : window.location.pathname;
135
136        window.history.replaceState({}, '', newUrl);
137
138        setTimeout(function() {
139            $('#submitSearch').click();
140        }, 10);
141    }
142}
143
144var CMSSearchObject = function() {
145    return {
146        hideExtended : function(id) {
147            var elem = $('#' + id);
148            if (elem == null) {
149                return;
150            }
151
152            elem.hide();
153        },
154        showExtended : function(id, rid, rid2) {
155            var elem = $('#' + id);
156            if (elem == null) {
157                return;
158            }
159
160            elem.show();
161            var r = $('#' + rid);
162            if (r) {
163                r.remove();
164            }
165            r = $('#' + rid2);
166            if (r) {
167                r.remove();
168            }
169        },
170        toggleDisabled : function(id, active) {
171            var elem = $('#' + id);
172            if (elem == null) {
173                return;
174            }
175
176            elem.attr('disabled', active);
177        },
178        toggle : function(id, show) {
179            var elem = $('#' + id);
180            if (elem == null) {
181                return;
182            }
183
184            if (show) {
185                elem.toggle(true);
186                elem.find('*').attr('disabled', false);
187            } else {
188                elem.toggle(false);
189                elem.find('*').attr('disabled', true);
190            }
191        }
192    }
193}();
194/**
195 * overwrite of jquery-ui autocomplete plugin
196 * makes the input query term bold to difference from completed term part
197 */
198jQuery.ui.autocomplete.prototype._renderItem = function(ul, item) {
199	var t = item.label.replace(new RegExp('(' + this.term + ')', 'gi'), "<b>$1</b>");
200	return jQuery("<li></li>").data("item.autocomplete", item).append("<a>" + t + "</a>").appendTo(ul);
201};
202
203/**
204 * global cache for autocomplete in pbsearch
205 */
206var pbsearch = pbsearch || {};
207pbsearch.autocompleteCache = {};
208
209/**
210 * initialize jquery-ui autocomplete
211 * Performs ajax calls to "search-autocomplete" to get the autocompleted terms.
212 * Using the global autocompleteCache for caching requested terms.
213 */
214jQuery.widget("pbsearch.pbsearch_autocomplete", {
215	options: {
216		url: null,
217		minLength: 3,
218		delay: 300,
219		maxTerms: 5,
220		rows: 20,
221		avoidParallelRequests: true,
222		cache: function() {
223			return pbsearch.autocompleteCache;
224		},
225		messages: {
226        	noResults: '',
227        	results: function() {}
228    	},
229    	afterSource: function(me) {
230    		delete me.requestOngoing;
231			var term = me.latestTermWhileOngoing;
232			delete me.latestTermWhileOngoing;
233			if(term) {
234				me.search(term);
235			}
236    	},
237		source: function(request, response) {
238			var me = this,
239			term = request.term.replace(new RegExp('AND', 'g'), '').replace(new RegExp('OR', 'g'), '').replace(/\s\s+/g, ' '),
240			cache = this.options.cache();
241			if (term in cache) {
242				response(cache[term]);
243				return;
244			}
245			if(this.options.maxTerms<term.split(' ').length) {
246				// we reached max terms, do not load new source
247				return;
248			}
249
250			if(me.options.avoidParallelRequests && me.requestOngoing) {
251				me.latestTermWhileOngoing = request.term;
252				return;
253			}
254
255			var matcher = new RegExp( jQuery.ui.autocomplete.escapeRegex(term), "i" );
256			me.requestOngoing = true;
257			jQuery.ajax({
258				type: 'POST',
259				url: me.options.url,
260				data: {'query': jQuery(this.element[0]).val(), 'rows': me.options.rows},
261				success: function(data, textStatus, xhr) {
262					cache[term] = data.searchResult;
263					response(data.searchResult);
264					me.options.afterSource(me);
265				},
266				failure: function() {
267					me.options.afterSource(me);
268				}
269			});
270		}
271	},
272	_create: function() {
273		jQuery(this.element).autocomplete(this.options);
274	}
275});
276function highlightSearchTermObj(searchterm, doc, id, textColor, backgroundColor, clazz) {
277	var obj = new Object();
278	obj.highlight = function () {
279		if (doc.all) {
280			obj.highlightIE();
281		} else {
282			obj.highlightGecko();
283		}
284	};
285	obj.highlightIE = function () {
286		var singleterms = obj.getSingleTerms(searchterm);
287		doc.body.focus();
288		for(var i=0; i<singleterms.length; i++) {
289			var elem = null;
290			if (id) {
291				elem = doc.getElementById(id);
292				var r = doc.selection.createRange();
293				if(elem!=null) {
294					r.moveToElementText(elem);
295				}
296				obj.highlightIERange(r);
297			} else if(clazz) {
298				var elems = $("."+clazz);
299				if(elems && elems.length>0) {
300					for(var j=0;j<elems.length;j++) {
301						var r = doc.selection.createRange();
302						r.moveToElementText(elems[j]);
303						obj.highlightIERange(r, singleterms[i], elems[j]);
304					}
305					return;
306				}
307			}
308			obj.highlightIERange(doc.selection.createRange());
309		}
310	};
311	obj.highlightIERange = function (r, term, elem) {
312		r.collapse(true);
313		var count = 0,
314			termfound = false;
315			
316		while(count < 100 && r.findText(term, 10000000, 0)) {
317			if (elem != null && hasParent(r.parentElement(), elem)==false) {
318				break;
319			}
320			r.execCommand("ForeColor", false, textColor);
321			r.execCommand("BackColor", false, backgroundColor);
322			r.collapse(false);
323			if(termfound == false) {
324				r.scrollIntoView();
325				termfound = true;
326			}
327			count++;
328		}
329	};
330	obj.highlightGecko = function () {
331		var elem;
332		var elems;
333		if (id) {
334			elem = doc.getElementById(id);
335		} else if(clazz) {
336			elems = $("."+clazz);
337		} else {
338			elem = doc.getElementsByTagName('body')[0];
339		}
340		if (!elem && !elems) return;
341		var singleterms = obj.getSingleTerms(searchterm);
342		for (var i=0;i<singleterms.length;i++) {
343			if(elems) {
344				for(var j=0;j<elems.length;j++) {
345					obj.elemSearchAndReplaceTerm(singleterms[i], elems[j]);
346				}
347			} else {
348				obj.elemSearchAndReplaceTerm(singleterms[i], elem);
349			}
350		}
351	};
352	obj.elemSearchAndReplaceTerm = function (singleterm, elem) {
353		var childs = elem.childNodes;
354		var texts = new Array();
355		var i;
356		if(childs) {
357			for (i=0;i<childs.length;i++) {
358				if (childs[i].nodeType==3) {
359					if (childs[i].nodeValue != null) {
360						texts[texts.length] = childs[i];
361					}
362				} else {
363					obj.elemSearchAndReplaceTerm(singleterm, childs[i]);
364				}
365			}
366			for (i=0;i<texts.length;i++) {
367				obj.replaceTermText(singleterm, texts[i]);
368			}
369		}
370	};
371	obj.replaceTermText = function(singleterm, elem) {
372		var val = elem.nodeValue;
373		var index = val.toLowerCase().indexOf(singleterm);
374		if (index != -1) {
375				var newNode = doc.createElement("span");
376				var newText1 = null;
377				var newText2 = null;
378				var textHigh = val.substr(index, singleterm.length);
379				if (index>0) {
380					newText1 = doc.createTextNode(val.substring(0, index));
381				}
382				if (index + 1 < val.length) {
383					newText2 = doc.createTextNode(val.substring(index+singleterm.length, val.length));
384				}
385				newNode.style.backgroundColor=backgroundColor;
386				newNode.style.color = textColor;
387				newNode.innerHTML = textHigh;
388				if (newText1 != null) {
389					elem.parentNode.insertBefore(newText1, elem);
390					obj.replaceTermText(singleterm, newText1);
391				}
392				elem.parentNode.insertBefore(newNode, elem);
393				if (newText2 != null) {
394					elem.parentNode.insertBefore(newText2, elem);
395					obj.replaceTermText(singleterm, newText2);
396				}
397			elem.parentNode.removeChild(elem);
398		}
399	};
400	obj.getSingleTerms = function(searchterm) {
401		var singletermsRet = new Array();
402		while(searchterm.indexOf('*') != -1) {
403			searchterm = searchterm.replace("*", " ");
404		}
405		while(searchterm.indexOf('?') != -1) {
406			searchterm = searchterm.replace("?", " ");
407		}
408		var singleterms = searchterm.split(" ");
409		var quot = null;
410		for(i=0; i<singleterms.length; i++) {
411			if(singleterms[i]!=null && singleterms[i].length > 0) {
412				if(singleterms[i] == 'AND' || singleterms[i] == 'OR' || singleterms[i].indexOf('-')==0) {
413					continue;
414				}
415				singleterms[i] = unescapeUnicode(singleterms[i]).toLowerCase();
416				singleterms[i] = singleterms[i].replace(/&amp;/gi, "&");
417				singleterms[i] = singleterms[i].replace(/&lt;/gi, "<");
418				singleterms[i] = singleterms[i].replace(/&gt;/gi, ">");
419				singleterms[i] = singleterms[i].replace(/&quot;/gi, "\"");
420				singleterms[i] = singleterms[i].replace(/&uuml;/gi, "\u00fc");
421				singleterms[i] = singleterms[i].replace(/&ouml;/gi, "\u00f6");
422				singleterms[i] = singleterms[i].replace(/&auml;/gi, "\u00e4");
423				singleterms[i] = singleterms[i].replace(/&szlig;/gi, "\u00df");
424				if(singleterms[i].indexOf("\"")==0) {
425					quot = singleterms[i];
426				} else if(quot) {
427					quot += ' ' + singleterms[i];
428				}
429				if(quot && quot.substring(1).indexOf("\"")!=-1) {
430					singleterms[i] = quot.replace(/\"/gi, '');
431					quot = null;
432				}
433				var hasTerm = false;
434				for (j=0;j<singletermsRet.length;j++) {
435					if (singletermsRet[j]==singleterms[i]) {
436						hasTerm = true;
437						break;
438					}
439				}
440				if (!hasTerm) {
441					singletermsRet[singletermsRet.length] = singleterms[i];
442				}
443			}
444		}
445		//terms which includes subterms should be performed at first
446		singletermsRet = singletermsRet.sort(obj.sorter);
447		return singletermsRet;
448	};
449	obj.sorter = function (a,b) {
450		var c = ("" + a);
451		var d = ("" + b);
452		if (c.indexOf(d)>-1){
453			return -1;
454		} else if (d.indexOf(c)>-1){
455			return 1;
456		}
457		return 0;
458	}
459	return obj;
460}
461// Slide direction: from bottom on mobile/tablets
462function setStickySidebarFlyoutsSlideEffect() {
463    if (window.matchMedia("(max-width: 68.125em)").matches) {
464        return "down";
465    }
466    return "right";
467}
468
469// Positioning: at the bottom as a bottom tray on mobile/tablets
470function setPositionBasedOnWidth() {
471    if (window.matchMedia("(max-width: 68.125em)").matches) {
472        $(".stickySidebar .flyout-element").each(function() {
473            $(this).css({
474                position:    "fixed",
475                left:        "0",
476                right:       "0",
477                bottom:      "91px",
478                top:         "auto",
479                width:       "100%",
480                "max-height":"calc(100vh - 91px)",
481                overflowY:   "auto",
482                display:     "block",
483                visibility:  "visible"
484            });
485        });
486        $(".footer").css("margin-bottom", "91px");
487    } else {
488        $(".stickySidebar .flyout-element").css({
489            position:    "",
490            left:        "",
491            right:       "",
492            bottom:      "",
493            top:         "",
494            width:       "",
495            "max-height":"",
496            overflowY:   "",
497            display:     "",
498            visibility:  ""
499        });
500        $("footer").css("margin-bottom", "");
501    }
502}
503
504// Optional: Hide print icon if not needed
505function hiddenPrintIconInStickySidebar() {
506    const main = $("main");
507    if (main.find(".grid").length > 0 && $(".no-hidden-print").length > 0) {
508        $(".stickySidebar-element.no-hidden-print").removeClass("no-hidden-print").addClass("hidden-print");
509    }
510}
511
512// Optional: Header spacing on mobile if sidebar is empty
513function stickySidebarIsEmpty() {
514    if (window.matchMedia("(max-width: 68.125em)").matches && $(".stickySidebar").length === 0) {
515        $(".header__menu").css("margin-bottom", "0");
516    }
517}
518
519// Hover and focus effect for the icon containers
520function setStickySidebarFlyoutsHoverEffect() {
521    $('.stickySidebar-trigger').off('mouseenter mouseleave focus blur').on({
522        mouseenter: function() {
523            var $fly = $(this).closest('.stickySidebar-element').find('.flyout-element');
524            if (!$fly.length || $fly.css('display') === 'none') {
525                $(this).addClass('active');
526            }
527        },
528        mouseleave: function() {
529            var $fly = $(this).closest('.stickySidebar-element').find('.flyout-element');
530            if (!$fly.length || $fly.css('display') === 'none') {
531                $(this).removeClass('active');
532            }
533        },
534        focus: function() {
535            var $fly = $(this).closest('.stickySidebar-element').find('.flyout-element');
536            if (!$fly.length || $fly.css('display') === 'none') {
537                $(this).addClass('active');
538            }
539        },
540        blur: function() {
541            var $fly = $(this).closest('.stickySidebar-element').find('.flyout-element');
542            if (!$fly.length || $fly.css('display') === 'none') {
543                $(this).removeClass('active');
544            }
545        }
546    });
547}
548
549// DOM ready: initialize everything
550$(document).ready(function () {
551    // If there is no sidebar on the page: exit
552    if ($(".stickySidebar").length === 0) {
553        hiddenPrintIconInStickySidebar();
554        stickySidebarIsEmpty();
555        return;
556    }
557
558    // 1) Setting ARIA basics on the button elements with aria-controls
559    $('.stickySidebar-trigger[aria-controls]').each(function(){
560        const $btn = $(this);
561        $btn.attr({
562            "aria-haspopup": "true",
563            "aria-expanded": "false",
564            "tabindex": "0"
565        });
566        // Label from span.visually-hidden or alt text
567        const hiddenText = $btn.find("span.visually-hidden").text().trim();
568        const altImg = $btn.find("img").attr("alt") || "";
569        const label = hiddenText || altImg || "Sidebar-Element";
570        $btn.attr("aria-label", label);
571    });
572
573    // 2) Initially hide all flyouts (also set the hidden attribute)
574    $(".flyout-element").attr("hidden", "hidden").hide();
575
576    // 3) Click handler for expanding/collapsing
577    $('.stickySidebar-trigger').off('click').on('click', function(e){
578        e.preventDefault();
579        e.stopPropagation();
580
581        const $btn = $(this);
582        const id   = $btn.attr("aria-controls");
583        const el = document.getElementById(id);
584        if (!el) {
585            return;
586        }
587
588        const $fly = $(el);
589        const isOpen = $btn.attr("aria-expanded") === "true";
590
591        // First: close all flyouts
592        $('.stickySidebar-trigger').attr("aria-expanded", "false").removeClass("active");
593        $('.flyout-element').each(function(){
594            const $f = $(this);
595            $f.hide("slide", {direction: setStickySidebarFlyoutsSlideEffect()}, 400, function(){
596                $f.attr("hidden", "hidden");
597            });
598        });
599
600        // Then: open the current one if needed
601        if (!isOpen) {
602            $btn.attr("aria-expanded", "true").addClass("active");
603            $fly.removeAttr("hidden").css("z-index", 1200).show("slide", {direction: setStickySidebarFlyoutsSlideEffect()}, 400);
604        }
605    });
606
607    // 4) Keyboard: Treat Enter and Spacebar as a click
608    $('.stickySidebar-trigger').off('keydown').on('keydown', function(e){
609        if (e.key === "Enter" || e.key === " ") {
610            e.preventDefault();
611            $(this).click();
612        }
613    });
614
615    // 5) Close button in the flyout
616    $('.close-button').off('click').on('click', function(e) {
617        e.preventDefault();
618        const $fly = $(this).closest('.flyout-element');
619        const id = $fly.attr("id");
620        const $btn = $(`.stickySidebar-trigger[aria-controls="${id}"]`);
621
622        if ($fly.is(':visible')) {
623            $fly.stop(true, true).hide('slide', {direction: setStickySidebarFlyoutsSlideEffect()}, 400, function() {
624                $fly.attr('hidden', 'hidden');
625                $btn.attr('aria-expanded', 'false').removeClass('active');
626            });
627        }
628    });
629
630    // 6) Clicking outside closes everything
631    $(document).on("click", function(e) {
632        if (!$(e.target).closest(".stickySidebar-trigger, .flyout-element").length) {
633            // only handle open flyouts
634            $(".flyout-element:visible").each(function(){
635                const $fly = $(this);
636                const id = $fly.attr("id");
637                const $btn = $(`.stickySidebar-trigger[aria-controls="${id}"]`);
638
639                $fly.stop(true, true).hide('slide', {direction: setStickySidebarFlyoutsSlideEffect()}, 400, function() {
640                    $fly.attr('hidden', 'hidden');
641                    $btn.attr('aria-expanded', 'false').removeClass('active');
642                });
643            });
644        }
645    });
646
647    // 7) Escape closes everything
648    $(document).on('keydown', function(e) {
649        if (e.key === 'Escape') {
650            $('.flyout-element:visible').each(function() {
651                const $fly = $(this);
652                const id = $fly.attr("id");
653                const $btn = $(`.stickySidebar-trigger[aria-controls="${id}"]`);
654
655                $fly.stop(true, true).hide('slide', {direction: setStickySidebarFlyoutsSlideEffect()}, 400, function() {
656                    $fly.attr('hidden', 'hidden');
657                    $btn.attr('aria-expanded', 'false').removeClass('active');
658                });
659            });
660        }
661    });
662
663    // 8) Responsive Helpers
664    $(window).on("resize", setPositionBasedOnWidth);
665    setPositionBasedOnWidth();
666
667    // 9) Other Utilities
668    hiddenPrintIconInStickySidebar();
669    stickySidebarIsEmpty();
670    setStickySidebarFlyoutsHoverEffect();
671});
672function sendSubscription(url, type, data, context, captchaImg) {
673    var submitButton = $(context).find('input[type="submit"]');
674    submitButton.prop('disabled', true);
675
676    $.ajax({
677        type:     type,
678        url:      url,
679        data:     data,
680        context:  context,
681        async:    true,
682        cache:    false,
683        success:  function (msg) {
684            $(this).html(msg).slideDown("fast");
685        },
686        error:    function () {
687            submitButton.prop('disabled', false);
688        },
689        complete: function (msg) {
690            if (captchaImg != null && document.getElementById(captchaImg) != null) {
691                captchaReload(captchaImg);
692            }
693
694            setTimeout(function () {
695                if (typeof initAltchaInSubscription === 'function') {
696                    initAltchaInSubscription();
697                }
698
699                if (typeof initAltchaInSubscribeComments === 'function') {
700                    initAltchaInSubscribeComments();
701                }
702
703                if (typeof initAltchaInSubscribeBlog === 'function') {
704                    initAltchaInSubscribeBlog();
705                }
706            }, 50);
707
708            submitButton.prop('disabled', false);
709        }
710    });
711}
712var refreshByEditorUrl;
713function refreshByEditor(id, locale, userobject) {
714	var url = document.location.href;
715	if (refreshByEditorUrl) {
716		url = refreshByEditorUrl;
717	}
718	if (userobject != null && userobject.length > 0) {
719		if (url.indexOf("?") > 0) {
720			url += "&";
721		} else {
722			url += "?";
723		}
724		url += "userobject=" + userobject;
725	}
726	document.location.href = url;
727}
728
729$(function() {
730	var $toolbar = $("#toolbar");
731	var isDragging = false;
732	var offsetX, offsetY;
733
734	$toolbar.on("mousedown", function(e) {
735		if (!$(e.target).is("a, a *")) {
736			isDragging = true;
737			offsetX = e.clientX - $toolbar.offset().left;
738			offsetY = e.clientY - $toolbar.offset().top;
739			$toolbar.css("cursor", "grabbing");
740			e.preventDefault();
741		}
742	});
743
744	$(document).on("mousemove", function(e) {
745		if (isDragging) {
746			var newLeft = e.clientX - offsetX;
747			var newTop = e.clientY - offsetY;
748
749			var windowWidth = $(window).width();
750			var windowHeight = $(window).height();
751			var navWidth = $toolbar.outerWidth();
752			var navHeight = $toolbar.outerHeight();
753
754			if (newLeft < 0) newLeft = 0;
755			if (newTop < 0) newTop = 0;
756			if (newLeft + navWidth > windowWidth) newLeft = windowWidth - navWidth;
757			if (newTop + navHeight > windowHeight) newTop = windowHeight - navHeight;
758
759			$toolbar.offset({
760				top: newTop,
761				left: newLeft
762			});
763		}
764	});
765
766	$(document).on("mouseup", function() {
767		if (isDragging) {
768			isDragging = false;
769			$toolbar.css("cursor", "move");
770		}
771	});
772});

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.