1/* js for package: Collections */ 2 3console = console || { 4 log: function(){}, 5 dir: function(){} 6}; 7 8function getQueryVariable(variable){ 9 var query = window.location.search.substring(1); 10 var vars = query.split("&"); 11 for (var i=0;i<vars.length;i++) { 12 var pair = vars[i].split("="); 13 if(pair[0] == variable){return pair[1];} 14 } 15 return false; 16} 17 18 19 20/** 21 * 22 * thesaurus item baum einausklappbar: 23 * https://www.jstree.com/ 24 * 25 */ 26 27var collections = (function () { 28 29 function compare(a,b) { 30 if (a.name < b.name) return -1; 31 if (a.name > b.name) return 1; 32 return 0; 33 } 34 35 //TODO get this url 36// var baseUrl = "http://han.jart.at"; 37 // var contentId = 1440750162061; //XUZIHU:: use correct content-id vor han and xuzi 38 39 40 var thesCatDATEid = 47; 41 var thesCatSammlung; 42 43 var $collectionDiv; //root of this application 44 var $thesDiv; 45 var $thesLoading; 46 var $itemContainer; 47 var $locationFilterContainer; 48 var $thesContainer; 49 var thes; //whole thesaurus 50 var filter = {}; //object holding current filter; that is thesaurus id grouped by thesaurus categories 51 52 var loadingMore = false; 53 var currentPage = 1; 54 55 //date filter 56 var $dtStart, $dtEnd; 57 58 //location filter 59 var $showOnFilter, $showOnNoFilter; 60 var $clearLocationFilterBtn; 61 var $inputLat, $inputLon; 62 63 var flatThesItemList = {}; //flat list of thesItems grouped by thesaurus category 64 65 66 function _div(sClass){ 67 var div = $("<div></div>"); 68 if (sClass){ 69 div.addClass(sClass); 70 } 71 return div; 72 } 73 74 75 function _setBusy(isBusy){ 76 if (isBusy){ 77 $(".item-list").hide(); 78 $(".busy").show(); 79 }else{ 80 $(".item-list").show(); 81 $(".busy").hide(); 82 } 83 } 84 85 function _initDomObjects(){ 86 $collectionDiv = $(".collection"); 87 $locationFilterContainer = $(".location-filter"); 88 $clearLocationFilterBtn = $locationFilterContainer.find(".clear-location-filter"); 89 $showOnFilter = $locationFilterContainer.find(".showOnLocationFilter"); 90 $showOnNoFilter = $locationFilterContainer.find(".showOnNoLocationFilter"); 91 $inputLat = $locationFilterContainer.find("#filterLatitude"); 92 $inputLon = $locationFilterContainer.find("#filterLongitude"); 93 $thesContainer = $(".thesaurus-categories"); 94 $itemContainer = $(".item-list"); 95 $thesDiv = $(".thesaurus"); 96 $thesLoading = $(".thes-loading"); 97 98 $clearLocationFilterBtn.on("click", function(){ 99 _clearLocationFilter(); 100 _sendFilter(); 101 }); 102 } 103 104 function _initInfiniteScroll(){ 105 var scrollDiv = $(document); 106 scrollDiv.bind('scroll', function(){ 107 //$.log("height: " + ($(this).innerHeight() - 1500) + " || scrollTop: " + $(this).scrollTop()); 108 109 /* 110 if(loadingMore){ 111 if($(this).scrollTop() >= ($(this).innerHeight() - 1500)){ 112 $(".loading-more-info").removeClass("hidden"); 113 loadingMore = false; 114 _sendFilter(currentPage + 1); 115 } 116 } 117 */ 118 119 //scroll to top button 120 if ($(this).scrollTop() > 1400) { 121 $('.scrollToTop').fadeIn(); 122 } else { 123 $('.scrollToTop').fadeOut(); 124 } 125 }); 126 } 127 128 function _initPager() { 129 var $pageLinks = $(".page-link"); 130 var totalCount = $pageLinks.length; 131 var neighbourCount = 3; //how many neighbors besides the current active page-button should be shown 132 133 $pageLinks.on("click", function(e){ 134 e.preventDefault(); 135 136 var page = $(this).data("page"); 137// $.log("loading page: " + page); 138 139 _sendFilter(page); 140 141 //set active state for recently clicked page 142 $pageLinks.removeClass("active"); 143 $(this).addClass("active"); 144 145 //update which pagers should be shown 146 147 $pageLinks.each(function(i){ 148 $this = $(this); 149 if(i == 0 || 150 i == totalCount -1 || 151 Math.abs(page - (i+1)) <= neighbourCount ){ 152 //show the link 153 $this.removeClass("hidden"); 154 }else{ 155 $this.addClass("hidden"); 156 } 157 }); 158 159 togglePageSeparators($pageLinks, neighbourCount); 160 161 return false; 162 }); 163 164 togglePageSeparators($pageLinks, neighbourCount); 165 _updateUrl(); 166 } 167 168 /** 169 * shows page-btn separators with some sophisticated logic. 170 * first separator is shown if second page button is not visible 171 * last separator ist shown if next to last page button is not visible 172 */ 173 function togglePageSeparators($pageLinks, neighbourCount){ 174 var totalCount = $pageLinks.length; 175 var $sepFirst = $(".page-separator-first"); 176 var $sepLast = $(".page-separator-last"); 177 178 var maxPagesNoSeparators = neighbourCount * 2 + 1; 179 if($pageLinks.length <= maxPagesNoSeparators){ 180 $sepFirst.addClass("hidden"); 181 $sepLast.addClass("hidden"); 182 }else{ 183 if($($pageLinks[1]).hasClass("hidden")){
184 //second page-link is hidden 185 $sepFirst.removeClass("hidden"); 186 }else{ 187 $sepFirst.addClass("hidden"); 188 } 189 190 if($($pageLinks[totalCount - 2]).hasClass("hidden")){ 191 //next to last page-link is hidden 192 $sepLast.removeClass("hidden"); 193 }else{ 194 $sepLast.addClass("hidden"); 195 } 196 } 197 } 198 199 function _initScrollTop(){ 200 //Click event to scroll to top 201 $('.scrollToTop').click(function(){ 202 $('html, body').animate({scrollTop : 170},600); 203 return false; 204 }); 205 } 206 207 function _fetchData(params, datatype, cb){ 208 var url = "/jart/prj3/volkskundemuseum/main.jart?rel=de&content-id=" + contentId + "&reserve-mode=" + reserveMode; 209 210 //no caching by sending some random value 211 url = url + "&rnd=" + Math.random(); 212 213 return $.ajax({ 214 url : url, 215 data: params, 216 dataType : datatype 217 }).done(function(data) { 218 cb(data); 219 }).fail(function(e) { 220 $.log(e); 221 }); 222 } 223 224 /** 225 * hides thesaurus loading indication and shows the finally built thesaurus 226 */ 227 function _showTesaurus(){ 228 //TODO: some nice animation?? 229 $thesDiv.removeClass("hidden"); 230 $thesLoading.addClass("hidden"); 231 232 //collapse thesaurus on mobile and show a collapse button 233 if(window.matchMedia){ 234 var mq = window.matchMedia('all and (max-width: 991px)'); 235 toggleThesaurusCollapse(mq); 236 mq.addListener(toggleThesaurusCollapse); 237 } 238 } 239 240 /** 241 * on mobile devices thesaurus is hidden in a collapse and the collapse button is shown 242 */ 243 function toggleThesaurusCollapse(mq){ 244 if(mq.matches){ 245 $(".toggle-thesaurus").removeClass("hidden"); 246 $thesDiv.addClass("collapse"); 247 }else{ 248 $(".toggle-thesaurus").addClass("hidden"); 249 $thesDiv.removeClass("collapse"); 250 } 251 } 252 253 /** 254 * loads whole thesaurus tree we use to draw thesaurus 255 * uses localstorage to cache thesaurus cause it changes only on new collections 256 */ 257 function _buildThesaurus(){ 258 var storage = window.localStorage; //sessionStorage vs localStorage 259 var loadFromServer = true; 260 if(storage){ 261 //test if thesaurus was cached already 262 var data = storage.getItem('thesaurus'); 263 if(data){ 264 var thesaurus = JSON.parse(data); 265 if(window.thesaurusVersion && thesaurusVersion != '' && thesaurus.created == thesaurusVersion){ 266 loadFromServer = false; 267 //TODO check for newer version 268 _onThesaurusLoaded(thesaurus); 269 } 270 } 271 } 272 273 if(loadFromServer){ 274 //get thesaurus from server and cache it in local storage 275 _fetchData({ajax:"getThesaurus"}, "json", function(data){ 276 var thesaurus = data.ajax.thesaurus; 277 if(storage){ 278 storage.setItem('thesaurus', JSON.stringify(thesaurus)); 279 } 280 _onThesaurusLoaded(thesaurus); 281 }); 282 } 283 284 285 } 286 287 function _onThesaurusLoaded(_thes){ 288 thes = _thes; 289// var json = data.ajax; 290// thes = json.thesaurus; 291 for(var i=0; i<thes.thes_category.length; i++){ 292 var tc = thes.thes_category[i]; 293 filter[tc.thesaurus_category_id] = []; //init filter groups 294 295 _buildThesCatElement(tc); 296 } 297 _buildDateFilter(); 298 299 _bindEvents(); 300 _buildSelect2Boxes(); 301 302 var $resetAllBtn = $(".clearAllFilter"); 303// $thesContainer.prepend($resetAllBtn); 304 $resetAllBtn.on("click", function(){ 305 $(".select2-box").val('').trigger("change"); 306 $(".thes-item-input").prop("checked", false); 307 $dtStart.val(""); 308 $dtEnd.val(""); 309 _clearLocationFilter(); 310 _recreateFilter(); 311 _sendFilter(); 312 }); 313 314 _buildThesItemFilterBySammlung(thes); 315 _hideAlwaysHiddenThesItems(); // NEU 316 _preselectCollection(); 317 _showTesaurus(); 318 319 //infinitescroll is only active after thesaurus is loaded 320 loadingMore = true; 321 } 322 323 324 325 function _buildDateFilter(){ 326 var tcd = $('.thes-cat[data-thes-id="' + thesCatDATEid + '"]');//thesaurus category date
327 var div = $('<div class="thes-cat date-filter">' + 328 '<h3>Zeitraum</h3>' + 329 '<div class="filter-block"><div class="element"><label for="dt_start">Von</label>' + 330 '<input type="text" maxlength="10" id="dt_start"></input></div>' + 331 '<div class="element"><label for="dt_end">Bis</label>' + 332 '<input type="text" maxlength="10" id="dt_end"></input></div>' + 333 '<span class="dt-format">Format: (DD.MM.YYYY)</span></div>' + 334 '</div'); 335 336 $dtStart = div.find("#dt_start") 337 $dtEnd = div.find("#dt_end"); 338 339 div.find("#dt_start, #dt_end").keyup(function(e) { 340 if (e.which == 13) // Enter key 341 $(this).blur(); //delegate to blur impl 342 }).blur(function() { 343 //TODO validate, if not valid, focus field 344 var valid = true; 345 346 if (!valid){ 347 // console.log("setting focus again"); 348 $(this).focus(); 349 }else{ 350 _sendFilter(); 351 } 352 }); 353 354 var $resetBtn = $("<a class='del-filter'>Filterung aufheben<a/>"); 355 $resetBtn.on("click", function(){ 356 //clear input fields 357 $dtStart.val(""); 358 $dtEnd.val(""); 359 _sendFilter(); 360 }); 361 div.find("h3").after($resetBtn); 362 363 tcd.after(div); 364 } 365 366 function _buildThesCatElement(tc){ 367 flatThesItemList[tc.thesaurus_category_id] = { 368 tc: tc, 369 tiList: [] 370 }; 371 372 var div = _div("thes-cat").attr("data-thes-id", tc.id); 373 div.append($("<h3></h3>").text(tc.category_name)); 374 _buildThesItemList(tc.thesaurus_item, div); 375 376 tc.elem = div; 377 $thesContainer.append(div); 378 } 379 380 /** 381 * builds a list of thesaurus item elements and adds it to the given parent dom element (pElem) 382 */ 383 function _buildThesItemList(tiList, pElem){ 384 if (tiList){ 385 var ul = $("<ul class='object-selector'></ul>").appendTo(pElem); 386 if ($.isArray(tiList)){ 387 388 for (var i=0; i<tiList.length; i++){ 389 _buildThesItem(tiList[i], ul); 390 } 391 }else{ 392 _buildThesItem(tiList, ul); 393 } 394 } 395 } 396 397 function _isRootItem(ti){ 398 return ti.parent_thesaurus_item_id == null; 399 } 400 401 function _getThesItemLabel(ti){ 402 var label = ""; 403 if (!_isRootItem(ti)){ 404 label = ti.name; 405 if(ti.synonym){ 406 label = label + "<br> [" 407 if(ti.synonym.length){ 408 for(var i=0; i<ti.synonym.length; i++){ 409 if(i>0){ 410 label = label + " | <br>"; 411 } 412 label = label + ti.synonym[i].name; 413 } 414 }else{ 415 label = label + ti.synonym.name; 416 } 417 label = label + "]"; 418 } 419 }else{ 420 //use category name as root? 421 //var tc = flatThesItemList[ti.thesaurus_category_id]; auskommentiert Michael 15.4.2024 422// label = tc.tc.category_name; 423 label = "Gesamt"; 424// label = ti.name; 425 } 426 return label; 427 } 428 429 /**
430 * builds a single thesaurus item and adds it to the given parent dom element (pElem) 431 */ 432 function _buildThesItem(ti, pElem){ 433 //flatThesItemList[ti.thesaurus_category_id].tiList.push(ti); auskommentiert Michael 15.4.2024 434 435 var li = $("<li></li>").appendTo(pElem); 436 437 var label; 438 if (_isRootItem(ti)){ 439 label = $('<span>' + _getThesItemLabel(ti) + " [" + ti["linked-objects"] + "]" + '</span>'); 440 }else{ 441 label = $('<label>' + _getThesItemLabel(ti) + " [" + ti["linked-objects"] + "]" + '</label>').attr("for", ti.thesaurus_item_id); 442 //only non-root items get a checkbox 443 var chkbx = $('<input type="checkbox" name="thes-item" value="' + ti.thesaurus_item_id + '">') 444 .attr("id", ti.thesaurus_item_id) 445 .addClass("thes-item-input") 446 .data({ 447 tiId: ti.thesaurus_item_id, 448 tcId: ti.thesaurus_category_id 449 }); 450 li.append(chkbx); 451 } 452 453 li.append(label); 454 455 if (ti.thesaurus_item){ 456 li.append( 457 $("<span> <img src='/jart/prj3/volkskundemuseum/indexes/main/resources/img/arrow_right.png' class='ico' alt='aufklappen' /> </span>").addClass("open-toggle") 458 ); 459 460 li.addClass("closed"); 461 } 462 463 464 _buildThesItemList(ti.thesaurus_item, li); 465 466 ti.elem = li; 467 468 } 469 470 /** 471 * creates select2 boxes for quick accessing thesaurus items in a single category 472 */ 473 function _buildSelect2Boxes(){ 474 $.each(/*flatThesItemList, auskommentiert Michael 17.4. */function( key, value ) { 475 var $select = $("<select></select>").attr("multiple", "multiple").css("width", "100%").addClass("select2-box").attr("data-placeholder", value.tc.category_name + " auswählen"); 476 477 value.tiList.sort(compare); 478 479 for (var i=0; i<value.tiList.length; i++){ 480 var ti = value.tiList[i]; 481 if (!_isRootItem(ti)){ 482 $select.append($("<option value='" + ti.thesaurus_item_id + "'>" + _getThesItemLabel(ti) + "</option>")); 483 } 484 } 485 486 487 //append select box, create select2 out of it and bind select/unselect events to keep the selection in sync with the tree 488 value.tc.elem.find("h3").after($select); 489 $select.select2({ 490 sorter: _select2Sorter 491 }); 492 $select.on("select2:select", _onSelect2Select); 493 $select.on("select2:unselect", _onSelect2Unselect); 494 495 var $resetBtn = $("<a class='del-filter'>Filterung aufheben<a/>"); 496 $resetBtn.on("click", function(){ 497 $select.val('').trigger("change"); 498 //clear select boxes 499 value.tc.elem.find(".thes-item-input").prop("checked", false); 500 _recreateFilter(); 501 _sendFilter(); 502 }); 503 value.tc.elem.find("h3").after($resetBtn); 504 }); 505 506 //aria labels for select2 507 $(".select2-search__field").each(function(){ //, .select2-selection 508 $(this).attr("aria-label", $(this).closest(".thes-cat").find("h3").text() + " Filter"); 509 // $(this).attr("title", $(this).attr("aria-label")); 510 }); 511 } 512 513 function _select2Sorter(data){ 514 data.sort(function(a,b){ 515 return a.text.localeCompare(b.text, 'de'); //localCompare takes umlaute into account! 516 }); 517 return data; 518 } 519 520 /* 521 var customSorter = function(data) { 522 return data.sort(function(a,b){ 523 a = a.text.toLowerCase(); 524 b = b.text.toLowerCase(); 525 if(a > b) { 526 return 1; 527 } else if (a < b) { 528 return -1; 529 } 530 return 0; 531 }); 532 }; 533 */ 534 535 /* 536 recreates the filterobject from the current checkbox selection. this function may be used to created a totally synced filter object based on user selection 537 */ 538 function _recreateFilter(){ 539 $.each(filter, function( key, value ) { 540 value.length=0; 541 }); 542 543 $(".thes-item-input:checked").each(function(){ 544 $ti = $(this);
545 filter[$ti.data("tcId")].push($ti.data("tiId")); 546 }); 547 548 _filterThesItems(); 549 } 550 551 function _onSelect2Select(e){ 552 var id = e.params.data.id; 553 var opt = $thesContainer.find("input[value='" + id + "']"); 554 opt.prop("checked", true).change(); 555 556// console.log($(this).val()); 557 } 558 559 function _onSelect2Unselect(e){ 560 var id = e.params.data.id; 561 var opt = $thesContainer.find("input[value='" + id + "']"); 562 opt.prop("checked", false).change(); 563 } 564 565 /* 566 function _updateCollectionItems(items){ 567 568 $itemContainer.empty(); 569 for(var i=0; i<items.length; i++){ 570 item = items[i]; 571 572 var itemElem = $('<div class="item-teaser"><div class="item-image"></div><div class="inventarnummer">' + item.inventarnummer_online + '</div><h2>' + item.titel + '</h2><div class="link"><a href="/jart/prj3/volkskundemuseum/main.jart?rel=de&reserve-mode=reserve&content-id=' + contentId + '&item_id=' + item.collection_item_id + '">_Mehr</a></div></div>'); 573 if (item.image){ 574 var src = baseUrl + ($.isArray(item.image) ? item.image[0]["image-url"] : item.image["image-url"]);
575 itemElem.find(".item-image").append($("<img></img>").attr("src", src)); 576 } 577 578 $itemContainer.append(itemElem); 579 } 580 } 581 */ 582 583 function _sendFilter(page){ 584 //send filter to server to retrieve new item list 585 586 var pageGiven = typeof page !== "undefined"; //important to now later what to add to DOM from ajax response 587 if(!pageGiven){ 588 currentPage = 1; 589 loadingMore = true; 590 }else{ 591 currentPage = page; 592 } 593 594 var params = { 595 groups:[], 596 'collection-page':currentPage 597 }; 598 $.each(filter, function( key, value ) { 599 if (value.length > 0){ 600 params.groups.push(key); //collect group id 601 params["grp_"+key] = value.join(); //serialize item-ids 602 } 603 }); 604 605 if (params.groups){ 606 params.groups = params.groups.join(); 607 } 608 609 params["get-filtered-items"] = "yes"; 610 611 params["dt_start"] = $dtStart.val(); 612 params["dt_end"] = $dtEnd.val(); 613 614 //set location filter 615 params["lat"] = $inputLat.val(); 616 params["lon"] = $inputLon.val(); 617 618 //console.log(params); 619 620 if(pageGiven){ 621 $(".real-item-list").empty(); 622 $(".loading-more-info").removeClass("hidden"); 623 }else{ 624 //TODO small loading more animation 625 _setBusy(true); 626 } 627 628 _updateUrl(); 629 630 _fetchData(params, "html", function(data){ 631 632 //extract itemlist and set it into dom 633 634 if(pageGiven){ 635 //response cause of pager link. only swap the items 636 637 var newItemList = $(data).find(".real-item-list .item-teaser"); 638 $(".loading-more-info").addClass("hidden"); 639 $(".real-item-list").empty().append(newItemList); 640 641 }else{ 642 //response cause of some filter change. add whole item-list which includes also new pager links 643 var newItemList = $(data).find(".item-list"); 644 $(".item-list").before(newItemList).remove(); 645 646 //init pager links 647 _initPager(); 648 _setBusy(false); 649 } 650 651 /* 652 653 if(currentPage == 1){ 654 //set itemlist with headline 655 var newItemList = $(data).find(".item-list"); 656 $(".item-list").before(newItemList).remove(); 657 658 //init pager links 659 _initPager(); 660 661 }else{ 662 //append new items 663 var newItemList = $(data).find(".real-item-list .item-teaser"); 664 $(".loading-more-info").addClass("hidden"); 665 $(".real-item-list").append(newItemList); 666 if(newItemList.length > 0){ 667 loadingMore = true; 668 } 669 } 670 671 */ 672 673 674 675 // console.log(itemList.html()); 676 677 //_updateCollectionItems(data.collection_item); 678 }); 679 } 680 681 function _bindEvents(){ 682 //console.log("binding events, " + $(".thes-item-input").length); 683 //console.dir(filter); 684 685 $(".thes-item-input").on("change", function(){ 686 $ti = $(this); 687 $select2 = $ti.closest(".thes-cat").find(".select2-box"); 688 689 // console.log("tiId: " + $ti.data("tiId") + "; tcId: " + $ti.data("tcId")); 690 if (this.checked){ 691 //add to filter 692 filter[$ti.data("tcId")].push($ti.data("tiId")); 693 //add value to select2 box 694 var values = $select2.val(); 695 if (!values){ 696 values = []; 697 } 698 values.push($ti.val()); 699 $select2.val(values).trigger("change"); 700 }else{ 701 var tiId = $ti.data("tiId");
702 filter[$ti.data("tcId")] = $.grep(filter[$ti.data("tcId")], function(value) { 703 return value != tiId; 704 }); 705 706 var values = $select2.val(); 707 if (values){ 708 values = $.grep(values, function(value) { 709 return value != tiId; 710 }); 711 } 712 $select2.val(values).trigger("change"); 713 } 714 715 //console.log(filter[$ti.data("tcId")]); 716 _sendFilter(); 717 }); 718 719 $(".open-toggle").on("click", function(){ 720 $me = $(this); 721 $me.parent().toggleClass("closed"); 722 if($me.parent().hasClass("closed")){ 723 $me.html(" <img src='/jart/prj3/volkskundemuseum/indexes/main/resources/img/arrow_right.png' class='ico' alt='aufklappen' /> "); 724 725 //close child elements too 726 var $childToggles = $me.parent().find(".open-toggle"); 727 $childToggles.html(" <img src='/jart/prj3/volkskundemuseum/indexes/main/resources/img/arrow_right.png' class='ico' alt='aufklappen' /> "); 728 $childToggles.parent().addClass("closed"); 729 }else{ 730 $me.html(" <img src='/jart/prj3/volkskundemuseum/indexes/main/resources/img/arrow_down.png' class='ico' alt='zuklappen' />"); 731 } 732 }); 733 } 734 735 736 var alwaysHiddenThesItemIds = ['1599292138284', '1599292138037']; //Kochbücher Petersmann, Forstner 737 function _hideAlwaysHiddenThesItems(){ 738 for(var i=0; i<alwaysHiddenThesItemIds.length; i++){ 739 var el = document.getElementById(alwaysHiddenThesItemIds[i]); 740 if(el){ 741 var li = el.closest('li'); 742 if(li){ 743 li.style.setProperty('display', 'none', 'important'); 744 } 745 } 746 } 747 } 748 749 750 751 752 function _buildThesItemFilterBySammlung(thes){ 753 var sids = thes["thesIds-by-Sammlung"].sids.split(","); 754 755 //$(".thes-item-input").parent().hide(); 756 //collection checkboxes are binded with there special logic about showing only there own thesaurus items 757 for(var i=0; i<sids.length; i++){ 758 //special class for thesaurus items which are a Collection (Sammlung) so that these items are never hidden 759 $("#" + sids[i]).addClass("ti-collection"); 760 $("#" + sids[i]).closest(".thes-cat").find(".select2-box").addClass("ti-collection"); 761 762 $("#" + sids[i]).on("change", function(){ 763 _filterThesItems(); 764 }); 765 } 766 767 // console.dir(thesIdsByCollection); 768 } 769 770 function _filterThesItems(){ 771 var sids = thes["thesIds-by-Sammlung"].sids.split(","); 772 var thesIdsByCollection = {}; 773 for(var i=0; i<sids.length; i++){ 774 thesIdsByCollection[sids[i]] = []; 775 } 776 $.each(thes["thesIds-by-Sammlung"], function(key, val){ 777 if (key != "sids" && key != "ids"){ 778 var sids = (""+val).split(","); 779 var thesId = key.substring(2, key.length); 780 for(var i=0; i<sids.length; i++){ 781 try{ 782 thesIdsByCollection[sids[i]].push(thesId); 783 }catch(e){ 784 $.log("ERROR: " + e); 785 $.log(sids[i]); 786 } 787 } 788 } 789 }); 790 791 //find all selected sammlungen 792 var selectedCol = []; 793 for(var j=0; j<sids.length; j++){ 794 if($("#" + sids[j] + ":checked").length>0){ 795 selectedCol.push(sids[j]); 796 } 797 } 798 799 //initially show all open-toggles 800 $(".open-toggle").show(); 801 802 if(selectedCol.length == 0 || 803 selectedCol.length == sids.length){ 804 //show all thesaurus checkboxes 805 $(".thes-item-input").parent().show(); 806 //enable all thesaurus select2 options 807 $(".select2-box option").removeAttr("disabled"); 808 }else{ 809 $(".thes-item-input:not(.ti-collection)").parent().hide(); 810 $(".select2-box:not(.ti-collection) option").attr("disabled", "disabled"); 811 812 /* 813 $(".select2-box option").each(function(){ 814 var $this = $(this); 815 var d = $this.parent().data('selectOptions') || {}; 816 d[$this.attr("value")] = $this.detach(); 817 $this.parent().data('selectOptions', d); 818 }); 819 */ 820 821 for(var x=0; x<selectedCol.length; x++){ 822 var thesIds = thesIdsByCollection[selectedCol[x]]; 823 for(var y=0; y<thesIds.length; y++){ 824 $("#" + thesIds[y]).parent().show(); 825 826 827 //show select2-box options 828 $('.select2-box option[value="' + thesIds[y] + '"').removeAttr("disabled"); 829 830 //TODO: show all parents too?? 831 } 832 } 833 834 //hide open-toggler if no children are visible 835 $(".open-toggle").each(function(){ 836 $objSel = $(this).parent().find(">.object-selector"); 837 838 var LIs = $objSel.children();
839 var allHidden = true; 840 for(var i=0; i<LIs.length; i++){ 841 if($(LIs[i]).css("display") != "none"){ 842 allHidden = false; 843 break; 844 } 845 } 846 if(allHidden){ 847 $(this).hide(); 848 } 849 }); 850 } 851 852 _hideAlwaysHiddenThesItems(); // NEU – erzwingt erneutes Verstecken nach jedem Filterdurchlauf 853 } 854 855 856 /** 857 * updates the url based on the current result-page 858 * 859 * TODO: later: the url should also contain all information about the current active filter for: 860 * *) sharing the current filter 861 * *) navigating back from the detail page should restore the filter 862 */ 863 function _updateUrl(){ 864 var params = location.search; 865 866 //remove old collection-page param 867 params = params.replace(/([\?&]collection-page=\d*)/, ''); 868 869 if(params === ""){ 870 // 871 params = "?collection-page=" + currentPage; 872 }else{ 873 params = params + "&collection-page=" + currentPage; 874 } 875 876 //TODO: later: add filter params here too 877 878 var newUrl = location.pathname + params; 879// $.log(newUrl); 880 881 history.replaceState({}, '', newUrl); 882 } 883 884 885 886 /** 887 * for pre-selecting into a collection: checkbox of collection is checked and the select2 box filled with the collection 888 * 889 * --> NEW: not only collections can be preselected, but all thesaurus items. this is done by linking from the details page. 890 * 891 */ 892 function _preselectCollection(){ 893 var colId = $collectionDiv.data("collection-id"); //the parameter is called collection-id, but it can be ANY thesaurus_item_id!! 894 if(colId){ 895 //check checkbox 896 var $thesCkbx = $("#" + colId); 897 $thesCkbx.prop("checked", true); 898 899 //add value to select2box 900 $select2 = $thesCkbx.closest(".thes-cat").find(".select2-box"); 901 $select2.val(colId).trigger("change"); 902 903 //open collections 904 //$thesCkbx.parent().parent().parent().removeClass("closed"); 905 /* 906 var closedLi = $thesCkbx.parent(); //.parent().parent().removeClass("closed"); 907 while(closedLi.closest("li.closed").length > 0){ 908 closedLi = closedLi.closest("li.closed"); 909 closedLi.removeClass("closed"); 910 } 911 912 */ 913 914 var breakCounter = 10; 915 var elem = $thesCkbx; //.parent().parent().removeClass("closed"); 916 while(elem.parent().closest("ul.object-selector").length > 0){ 917 elem = elem.parent().closest("ul.object-selector"); 918 elem.siblings(".open-toggle").click(); 919 920// closedLi.removeClass("closed"); 921 if(breakCounter-- < 0){ 922 console.log("breakcounter reached, breaking loop now"); 923 break; 924 } 925 } 926 927 //hide thesaurus items from other collections 928 _filterThesItems(); 929 930 //add it as filter 931 _recreateFilter(); 932 } 933 } 934 935 function _setLocationFilter(lat, lon, ortsangabe){ 936 937 $showOnFilter.removeClass("hidden"); 938 $showOnNoFilter.addClass("hidden"); 939 940 //TODO: add some animation so that the user sees this filter was applied 941 $locationFilterContainer.find(".ortsangabe").text(ortsangabe); 942 $inputLat.val(lat); 943 $inputLon.val(lon); 944 945 _sendFilter(); 946 } 947 948 function _clearLocationFilter(){ 949 950 $showOnFilter.addClass("hidden"); 951 $showOnNoFilter.removeClass("hidden"); 952 953 $locationFilterContainer.find(".ortsangabe").text(""); 954 $inputLat.val(""); 955 $inputLon.val(""); 956 } 957 958 function _init(){ 959 _initDomObjects(); 960 _buildThesaurus(); 961 _initScrollTop(); 962 _initInfiniteScroll(); 963 //_preselectCollection(); 964 _initPager(); 965 } 966 967 return { 968 init: _init, 969 setLocationFilter: _setLocationFilter, 970 _hideAlwaysHiddenThesItems: _hideAlwaysHiddenThesItems // NEU 971 }; 972 973 974})(); 975 976 977/** 978 * map drawing methods 979 * 980 * 981 * cluster references: 982 * https://unpkg.com/[email protected]/dist/supercluster.js 983 * https://github.com/nitaliano/react-native-mapbox-gl/issues/1069 984 * https://stackoverflow.com/questions/51033188/how-to-use-supercluster 985 * 986 * 987 * 988 */ 989 990var collectionMap = (function () { 991 992 //both taken from ginas map box account! 993 var accessToken = 'pk.eyJ1IjoiaGFyZSIsImEiOiJjanNibTJoNWUwYTF4M3lteWVzbzNrcjR4In0.rrqGMzzUvTx1g1owCJtsFg'; 994 var mapStyle = "mapbox://styles/hare/cjsps7smi26wi1fpkly4pwht4"; 995 var map = null; //mapbox map 996 var _mapData; //json data 997 var $itemContent = $("#item-content"); //content of clicked items is rendered here 998 var useClusterMode = false; 999 var groupedLocations; 1000 1001 function _initMap(){ 1002 if(mapData){ 1003 _mapData = _processMapData(mapData.collection_item); 1004 } 1005 1006 if(getQueryVariable("useClusterMode") == "true"){ 1007 useClusterMode = true; 1008 } 1009 1010 //always use clustermode; later on, remove this branch 1011 useClusterMode = true; 1012 1013 $('.collection-tabs a[data-toggle="tab"]').on('show.bs.tab', function (e) { 1014 //tab will be shown 1015 if(_isMapTab(e.target)){ 1016 _unselectMap();
1017 } 1018 1019 }).on('shown.bs.tab', function (e) { 1020 //tabis shown 1021 if(_isMapTab(e.target)){ 1022 if(map == null){ 1023 //map was not draw already 1024 _drawMap('item-map'); 1025 } 1026 } 1027 }) 1028 } 1029 1030 /* 1031 duplicates items with a second location 1032 */ 1033 function _processMapData(ciList){ 1034 1035 //items with latitude2 and longitude2 are duplicated. latitude2 and logitude2 means that there is a second location for this object 1036 var duplicatedItems = ciList.filter(function(ci){ 1037 return ci.latitude2 != '' && ci.longitude2 != ''; 1038 }).map(function (ci){ 1039 //clone the object, otherwhise we could change the original one later on 1040 return $.extend(true, {}, ci); 1041 }); 1042 1043 duplicatedItems.forEach(function(ci){ 1044 //set second location as first one to only use latitude-/longitude-/ortsangabe-1 in further code 1045 ci.latitude1 = ci.latitude2; 1046 ci.longitude1 = ci.longitude2; 1047 ci.ortsangabe1 = ci.ortsangabe2; 1048 ci.isDuplicate = true; //never used at the moment, but useful for finding bugs 1049 }); 1050 1051 //merge duplicated list into original one; 1052 $.merge(ciList, duplicatedItems); 1053 1054 return ciList; 1055 } 1056 1057 function _isMapTab(tab){ 1058 return tab.href.indexOf("collection-map") !== -1; 1059 } 1060 1061 function _drawMap(mapElementId){ 1062 1063 mapboxgl.accessToken = accessToken; 1064 1065 map = new mapboxgl.Map({ 1066 container: mapElementId, 1067 style: mapStyle, 1068 center: [52.93934616896888, 39.39714943204433], 1069 zoom: 2.022485356759363, 1070 minZoom:1.2, 1071 maxZoom:17.7 1072 }); 1073 1074 map.on('zoomend', function(e){ 1075 console.log("zoom-level: " + map.getZoom()); 1076 }).on('moveend', function(e){ 1077 console.log("center: " + map.getCenter()); 1078 }); 1079 1080 //detect if something was clicked on the map 1081 map.on('click', function(e) { 1082 1083 //unclusterd data point clicked? 1084 var features = map.queryRenderedFeatures(e.point, { layers: ['unclustered-point'] }); 1085 1086 if (features.length) { 1087 var clickedPoint = features[0]; 1088 1089 // $.log("clicked point: "); 1090 // $.log(clickedPoint); 1091 1092 //get group of clicked point and show its collection items 1093 var gName = clickedPoint.properties.gName; 1094 var group = groupedLocations[gName]; 1095 _drawCollectionItmesForMarker(gName, group); 1096 1097 /* 1098 map.flyTo({ 1099 center: clickedPoint.geometry.coordinates, 1100 zoom: 15, 1101 speed: .75 1102 }); 1103 */ 1104 }else{ 1105 _unselectMap(); 1106 } 1107 }); 1108 1109 1110 if(_mapData){ 1111 // $.log(_mapData); 1112 1113 1114 //group locations by exact coordinates 1115 groupedLocations = _mapData.reduce(function(grouped, ci){ 1116 var gName = ci.latitude1 +","+ci.longitude1; 1117 ci.gName = gName; 1118 typeof grouped[gName] !== 'undefined' ? (grouped[gName].push(ci)) : (grouped[gName] = [ci]); 1119 return grouped; 1120 },{}); 1121 1122 // $.log("grouped locations"); 1123// $.log(groupedLocations); 1124 1125 drawCluster(); 1126 1127 /* 1128 1129 if(useClusterMode){ 1130 //draw clustered data 1131 1132 clusterDemo(); 1133 }else{ 1134 //draw unclustered data 1135 Object.keys(groupedLocations).forEach(function(key) { 1136 _drawMarker(key, groupedLocations[key]); 1137 }); 1138 } 1139 */ 1140 } 1141 } 1142 1143 1144 1145 1146 function _mapToGeoJson(){ 1147 var geoJson = { 1148 "type": "FeatureCollection", 1149 "crs": { "type": "name", "properties": { "name": "Volkskundemuseum Sammlungsobjekte" } }, 1150 }; 1151 geoJson.features = _mapData.map(_itemToGeoJSONPoint); 1152 return geoJson; 1153 } 1154 1155 function _itemToGeoJSONPoint(ci){ 1156 return { 1157 type: "Feature", 1158 geometry: { 1159 type: "Point", 1160 coordinates: [ci.longitude1.replace(",", "."), ci.latitude1.replace(",", "."), 0] 1161 }, 1162 properties: { 1163 ci: ci, 1164 inventarnummer_online: ci.inventarnummer_online, 1165 collection_item_id: ci.collection_item_id, 1166 gName:ci.gName, //groupname the marker belongs to 1167 itemCount: groupedLocations[ci.gName].length 1168 } 1169 }; 1170 } 1171 1172 1173 1174 1175 1176 1177 1178 1179 /* 1180 when a marker is clicked, this function draws all collection items in the marker group into itemContent 1181 */ 1182 function _drawCollectionItmesForMarker(grpName, ciList){ 1183 var title = ciList.length + (ciList.length === 1 ? " Objekt" : " Objekte"); 1184 var ortsangabe = ciList[0].ortsangabe1 != '' ? ciList[0].ortsangabe1 : '(' + ciList[0].latitude1 + ", " + ciList[0].longitude1 + ')'; //take either ortsangabe1 or coordinates 1185 var lat = ciList[0].latitude1;
1186 var lon = ciList[0].longitude1; 1187 var filterBtn = 1188 '<div class="filter-btn">' + 1189 '<a class="btn btn-secondary locationFilterBtn" href="#" data-lat="' + lat + '" data-lon="' + lon + '" data-ortsangabe="' + ortsangabe + '">' + 1190 '<i class="fal fa-filter"> </i>Filtern' + 1191 '</a>' + 1192 '<p class="help-block">Filtert Objekte für diese Ortsangabe</p>' 1193 '<hr>' + 1194 '</div>'; 1195 var ciListHtml = ciList.map(function(ci){ 1196 1197 var href = "/jart/prj3/volkskundemuseum/main.jart?rel=de&reserve-mode=" + reserveMode + "&content-id=1440750162061&nice_url=" + ci.nice_url; 1198 var link = '<div class="link"><a class="detail-link" href="' + href + '" target="_objektdetail">zum Objekt</a></div>'; 1199 1200 var img = ""; 1201 if(ci.collection_item_image){ 1202 var filepath = ci.collection_item_image[0].filename; 1203 img = 1204 '<div class="item-image">' + 1205 '<div class="inner">' + 1206 '<a href="' + href + '" target="_objektdetail">' + 1207 '<img src="/jart/pub-prc/img.jart?base=/prj3/volkskundemuseum&img=' + filepath + '&mode=version&v=Gallery-Thumbnail" />' + 1208 '</a>' + 1209 '</div>' + 1210 '</div>'; 1211 1212 //preload image 1213 /* 1214 var tmp = new Image(); 1215 tmp.src = '/prj3/volkskundemuseum&img=' + filepath + '&mode=version&v=Gallery-Thumbnail'; 1216 */ 1217 } 1218 1219 var content = 1220 img + 1221 '<div class="inventar-nummer">' + ci.inventarnummer_online + "</div>" + 1222 '<h2>' + ci.titel + '</h2>' + 1223 link; 1224 1225 return '<div class="ci-item">' + content + '</div>'; 1226 1227 }).join(''); 1228 1229 var sClass = "popup_" + grpName.replace(/,/g, "_"); 1230 1231 // $.log(sClass); 1232 1233 var popupHtml = 1234 '<div class="' + sClass + '">' + 1235 '<h3>' + title + '</h3>' + 1236 '<div class="ortsangabe">' + (ortsangabe && ortsangabe != '' ? ortsangabe : '') + '</div>' + 1237 filterBtn + 1238 '<div class="ci-item-list">' +ciListHtml + '</div>' + 1239 '</div>'; 1240 1241 $itemContent.html(popupHtml); 1242 $itemContent.find(".locationFilterBtn").on("click", function(e){ 1243 e.preventDefault(); 1244 1245 var $this = $(this); 1246 _filterByCoordinates($this.data("lat"), $this.data("lon"), $this.data("ortsangabe")); 1247 1248 return false; 1249 }); 1250 } 1251 1252 /* 1253 function _drawMarker(grpName, ciList){ 1254 var lat = ciList[0].latitude1.replace(",", "."); 1255 var lon = ciList[0].longitude1.replace(",", "."); 1256 1257 var mElem = $('<div class="marker">' + ciList.length + '</div>') 1258 .on('click', function() { 1259 $.log("markergroup clicked: elements: " + ciList); 1260 1261 _unselectMap(); 1262 1263 //highlight marker 1264 $(this).addClass("selected"); 1265 _drawCollectionItmesForMarker(grpName, ciList); 1266 }); 1267 1268 var marker = new mapboxgl.Marker({ 1269 element:mElem[0], 1270 color: '#aeaeae' 1271 }).setLngLat({lon: lon, lat: lat}) 1272 .addTo(map); 1273 1274 1275 return; 1276 } 1277 */ 1278 1279 function _unselectMap(){ 1280 $("#item-map .marker").removeClass("selected"); 1281 $itemContent.empty(); //clear selection 1282 } 1283 1284 function _filterByCoordinates(lat, lon, ortsangabe){ 1285 //1. show ergebnislisten tab 1286 $('a[href="#collection-results"]').tab('show'); 1287 1288 //2. set location filter 1289 collections.setLocationFilter(lat, lon, ortsangabe); 1290 } 1291 1292 1293 1294 /* 1295 TODO: generate custom markers for 1296 *) cluster 1297 *) unclustered points 1298 1299 https://docs.mapbox.com/mapbox-gl-js/example/cluster-html/ 1300 1301 SO MACHEN:!!! 1302 Clustering Properties with Mapbox and HTML markers
1303 https://blog.mapbox.com/clustering-properties-with-mapbox-and-html-markers-bb353c8662ba 1304 1305 */ 1306 1307 function drawCluster(){ 1308 this._geoJsonData = _mapToGeoJson(); 1309 1310 map.on('load', function() { 1311 map.addSource("collection_items", { 1312 type: "geojson", 1313 data: _geoJsonData, // "https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson", 1314 cluster: true, 1315 clusterMaxZoom: 12, // Max zoom to cluster points on 1316 clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50) 1317 }); 1318 1319 map.addLayer({ 1320 id: "clusters", 1321 type: "circle", 1322 source: "collection_items", 1323 filter: ["has", "point_count"], 1324 paint: { 1325 // Use step expressions (https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-step) 1326 // with three steps to implement three types of circles: 1327 // * Blue, 20px circles when point count is less than 100 1328 // * Yellow, 30px circles when point count is between 100 and 750 1329 // * Pink, 40px circles when point count is greater than or equal to 750 1330 "circle-color": [ 1331 "step", 1332 ["get", "point_count"], 1333 "#51bbd6", 1334 100, 1335 "#f1f075", 1336 750, 1337 "#f28cb1" 1338 ], 1339 "circle-radius": [ 1340 "step", 1341 ["get", "point_count"], 1342 20, 1343 100, 1344 30, 1345 750, 1346 40 1347 ] 1348 } 1349 }); 1350 1351 map.addLayer({ 1352 id: "cluster-count", 1353 type: "symbol", 1354 source: "collection_items", 1355 filter: ["has", "point_count"], 1356 layout: { 1357 "text-field": "{point_count_abbreviated}", 1358 "text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"], 1359 "text-size": 12 1360 } 1361 }); 1362 1363 map.addLayer({ 1364 id: "unclustered-point-outer", 1365 type: "circle", 1366 source: "collection_items", 1367 filter: ["!", ["has", "point_count"]], 1368 paint: { 1369 "circle-color": "#ffffff", 1370 "circle-radius": 20, 1371 "circle-stroke-width": 1, 1372 "circle-stroke-color": "#000000" 1373 } 1374 }); 1375 map.addLayer({ 1376 id: "unclustered-point", 1377 type: "symbol", 1378 source: "collection_items", 1379 filter: ["!", ["has", "point_count"]], 1380 layout:{ 1381 "text-field": ['get', 'itemCount'], //weird notation to access geojson-features properties (which we have set before); https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-feature-data 1382 "text-size": 20 1383 } 1384 }); 1385 1386 1387 // inspect a cluster on click 1388 map.on('click', 'clusters', function(e) { 1389 var features = map.queryRenderedFeatures(e.point, { 1390 layers: ['clusters'] 1391 }); 1392 var clusterId = features[0].properties.cluster_id; 1393 map.getSource('collection_items').getClusterExpansionZoom(clusterId, function(err, zoom) { 1394 if (err) 1395 return; 1396 1397 map.easeTo({ 1398 center: features[0].geometry.coordinates, 1399 zoom: zoom 1400 }); 1401 }); 1402 }); 1403 1404 map.on('mouseenter', 'clusters', function() { 1405 map.getCanvas().style.cursor = 'pointer'; 1406 }); 1407 map.on('mouseleave', 'clusters', function() { 1408 map.getCanvas().style.cursor = ''; 1409 }); 1410 }); 1411 } 1412 1413 1414 1415 return { 1416 initMap: _initMap, 1417 drawMap:_drawMap 1418 }; 1419 1420})(); 1421 1422 1423 1424 1425$( document ).ready(function() { 1426 1427 $origDld = $('.original-image a'); 1428 1429 function initPanZoom(){ 1430 $section = $('#inverted-contain'); 1431 $section.find('.panzoom').panzoom({ 1432 $zoomIn: $section.find(".zoom-in"), 1433 $zoomOut: $section.find(".zoom-out"), 1434 $zoomRange: $section.find(".zoom-range"), 1435 $reset: $section.find(".reset"), 1436 startTransform: 'scale(1.0)', 1437 increment: 0.1, 1438 minScale: 1 1439 }); 1440 //.panzoom('zoom'); 1441 } 1442 1443 1444 if($(".item-list").length > 0){ 1445 collections.init(); 1446 collectionMap.initMap();
1447 1448 }else{ 1449 /*** DETAILSEITE ***/ 1450 1451 initPanZoom(); 1452 1453 $(".thumbs .thumb").on("click", function(){ 1454 $section.find('.panzoom').panzoom("reset", false); 1455 $section.find('.panzoom').attr("src", this.src); 1456 $section.find('.panzoom').attr("alt", this.alt); 1457 $origDld.attr("href", this.src); 1458 }); 1459 1460 //add querystring to anchor links; if there is no querystrings, nothing to do here 1461 //var queryString = window.location.search; 1462 var queryString = window.location; 1463 if(queryString && queryString != ""){ 1464 $("a.footnote-link").each(function(){ 1465 //this.href = queryString + this.href.substring(this.href.indexOf("#"), this.href.length); 1466 this.href = queryString.origin + queryString.pathname + this.href.substring(this.href.indexOf("#"), this.href.length); 1467 }); 1468 } 1469 1470 1471 //kommentar functions 1472 $('#comment-modal').on('shown.bs.modal', function (event) { 1473 $('#name').focus(); 1474 }); 1475 $('#comment-modal').on('show.bs.modal', function (event) { 1476 //init 1477 $(".modal-form").removeClass("hidden"); 1478 $(".modal-feedback").addClass("hidden"); 1479 $(".saveComment").removeClass("hidden"); 1480 $(".closeModal").removeClass("hidden"); 1481 $(".clear-on-init").val(""); 1482 $(".upload_link").empty(); 1483 1484 var button = $(event.relatedTarget) // Button that triggered the modal 1485 var modal = $(this); 1486 1487 modal.find("input[name='collection_item']").attr("value", $(this).data("uuid")); 1488 modal.find("input[name='replied_to']").attr("value", button.data("replied_to")); 1489 }); 1490 1491 $(".saveComment").on("click", function(e){ 1492 e.preventDefault(); 1493 //trigger vlaidation on riquired filds 1494 $(".jv\\[required\\]").trigger("blur"); 1495 if($(".comment-form .has-error").length > 0){ 1496 //validation errors 1497 return; 1498 } 1499 1500 var $this = $(this); 1501 var data = $(".comment-form").serialize() + "&addComment=yes"; 1502 var url = $(".comment-form").attr("action"); 1503 1504 //data = new FormData($("#comment-form")[0]); 1505 //saving text 1506 1507 $this.button('loading'); 1508 $(".closeModal").addClass("hidden"); 1509 1510 $.ajax({
1511 url: url, 1512 method: "POST", 1513 data: data 1514// contentType: 'multipart/form-data', // The content type used when sending data to the server. 1515// cache: false, // To unable request pages to be cached 1516// processData:false, // To send DOMDocument or non processed data file it is set to false 1517 }).done(function() { 1518 $this.button('reset'); 1519 $(".modal-form").addClass("hidden"); 1520 $(".modal-feedback").removeClass("hidden"); 1521 $(".saveComment").addClass("hidden"); 1522 $(".closeModal").removeClass("hidden"); 1523 }); 1524 }); 1525 1526 1527 } 1528 1529//document.getElementById('1599292138284') ?.closest('li') ?.style.setProperty('display', 'none', 'important'); //Ausblenden Kochbücher Petersmann in Sammlung-Filter 1530//document.getElementById('1599292138037') ?.closest('li') ?.style.setProperty('display', 'none', 'important'); //Ausblenden Forstner in Sammlung-Filter 1531 1532 if(typeof collections !== "undefined" && collections._hideAlwaysHiddenThesItems){ 1533 collections._hideAlwaysHiddenThesItems(); 1534 } 1535 1536}); 1537 1538 1539 1540 1541 1542
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.