1/* eslint-disable */ 2import mwBookmark from "/js/mw-core/mw-bookmark.js"; 3import "/js/mw-core/mw-core-button.js"; 4import "/js/mw-core/mw-core-actionsheet.js"; 5import mwCore from "/js/mw-core/mw-core.js"; 6import mwUtility from "/js/mw-core/mw-utility.js"; 7 8class mwCoreTeaser extends mwCore { 9 // livecycle methods 10 11 beforeFirstRender() { 12 let template; 13 14 // render data 15 16 try { 17 template = this.querySelector(`template[is="component-data"]`); 18 19 if (template) { 20 this._data = JSON.parse(template.content.textContent); 21 22 // add mqmedia rule to data 23 // relevant for bookmark 24 25 if (this.mqmedia) { 26 this._data.mqmedia = this.mqmedia; 27 } 28 29 // remove template from DOM 30 31 template.remove(); 32 } 33 } catch (error) { 34 console.error(error); 35 return; 36 } 37 } 38 39 updated() { 40 // private properties 41 42 this._dom = {}; 43 44 // cache DOM 45 46 this.cacheDOM(); 47 48 // register eventListener 49 50 this.registerEventListener(); 51 } 52 53 static get observedAttributes() { 54 // variants: default, inline, compact 55 56 return [ 57 "linkelement", 58 "button", 59 "buttonattr", 60 "bookmark", 61 "background", 62 "variant", 63 "saleschannelid", 64 "mqmedia", 65 "maxlines", 66 "maxlineslineheight", 67 "fallbackpicture", 68 "as", 69 "priceaddition", 70 "priceformat" 71 ]; 72 } 73 74 // css 75 76 styles() { 77 return [ 78 `<link href="/css/styleguide.css" rel="stylesheet">`, 79 ` 80 * { 81 user-select: none; 82 } 83 84 ${ 85 this.maxlines && this.maxlineslineheight 86 ? ` 87 :host { 88 --max-lines: ${this.maxlines}; 89 --lh: ${this.maxlineslineheight}; 90 } 91 ` 92 : `` 93 } 94 *:focus-visible { 95 outline-offset: -2px !important; 96 } 97 .root { 98 height: 100%; 99 } 100 p { 101 margin: 0; 102 } 103 a { 104 color: var(--mw-core-color-body-text-dark); 105 text-decoration: none; 106 } 107 a.button:focus-visible { 108 outline: none !important; 109 } 110 img { 111 display: block; 112 height: 100%; 113 object-fit: cover; 114 width: 100%; 115 } 116 .root > a.href { 117 height: 100%; 118 width: 100%; 119 } 120 .teaser { 121 display: flex; 122 flex-direction: column; 123 height: 100%; 124 width: 100%; 125 } 126 :host([linkelement]) .teaser { 127 cursor: pointer; 128 } 129 .main { 130 border-radius: 0; 131 display: flex; 132 flex: 1; 133 flex-direction: column; 134 padding: 24px 16px; 135 } 136 :host([background]) .main { 137 background: var(--mw-core-color-background-bright); 138 } 139 :host([variant="compact"]) .main { 140 padding: 12px; 141 text-align: center; 142 } 143 :host([noimage][tag]) .main { 144 padding-top: 50px; 145 } 146 .content { 147 margin: 0 0 10px; 148 } 149 :host([variant="compact"]) .content { 150 margin-bottom: 0; 151 } 152 :host([objecttype="provider"]) .content { 153 display: flex; 154 flex-wrap: wrap; 155 margin: 0; 156 } 157 .bottom { 158 align-items: flex-end; 159 display: flex; 160 justify-content: flex-end; 161 margin-top: auto; 162 } 163 :host([variant="compact"]) .bottom { 164 justify-content: center; 165 } 166 .bottom.has-info { 167 justify-content: space-between; 168 } 169 .tag { 170 background: var(--mw-core-color-action-primary); 171 color: var(--mw-core-color-body-text-dark); 172 font-size: 16px; 173 left: 20px; 174 line-height: 1; 175 padding: 5px 8px; 176 position: absolute; 177 text-transform: unset; 178 text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.24); 179 top: 20px; 180 visibility: visible; 181 z-index: 1; 182 } 183 .tag.no-tag { 184 display: none; 185 } 186 :host([variant="inline"]) .tag { 187 bottom: 20px; 188 left: auto; 189 right: 20px; 190 top: auto; 191 } 192 :host([variant="inline"]) .double-tag .tag.state { 193 top: 54px; 194 } 195 .tag.level1 { 196 background: var(--mw-core-color-label-moderate); 197 } 198 .tag.level2 { 199 background: var(--mw-core-color-state-error); 200 color: #FFFFFF; 201 } 202 .tag.level3 { 203 background: var(--mw-core-color-label-difficult); 204 color: #FFFFFF; 205 } 206 .tag.state { 207 left: auto; 208 right: 20px; 209 top: 20px; 210 } 211 .tag.state.state-cancelled, 212 .tag.state.state-postponed { 213 background: var(--mw-core-color-state-error); 214 color: #FFFFFF; 215 } 216 .tag.state.state-scheduled, 217 .tag.state.state-rescheduled { 218 background: var(--mw-core-color-state-success); 219 } 220 .image { 221 position: relative; 222 width: 100%; 223 z-index: -1; 224 } 225 .image a.href { 226 display: block; 227 } 228 .text, 229 .teasertext { 230 hyphens: auto; 231 word-break: break-word; 232 } 233 :host([objecttype="provider"]) .teasertext,
234 :host([objecttype="infrastructure"]) .teasertext, 235 :host([objecttype="tour"]) .teasertext { 236 display: none; 237 } 238 .teasertext ul { 239 margin: 8px 0; 240 padding: 0 0 0 16px; 241 } 242 .place { 243 margin-top: 16px; 244 } 245 .opening-days { 246 margin: 14px 0; 247 } 248 .opening-days .current { 249 align-items: center; 250 background: none; 251 border: none; 252 border-bottom: 2px solid transparent; 253 cursor: pointer; 254 display: inline-flex; 255 padding: 5px 0; 256 } 257 .opening-days .current:not(.no-further-openingdays):hover { 258 border-bottom: 2px solid; 259 } 260 .opening-days .current .state-good { 261 color: var(--mw-core-color-label-good); 262 } 263 .opening-days .current .state-medium { 264 color: var(--mw-core-color-label-medium); 265 } 266 .opening-days .current .state-bad { 267 color: var(--mw-core-color-label-bad); 268 } 269 .opening-days .current mw-core-icon { 270 display: block; 271 line-height: 1; 272 margin: 0 0 0 4px; 273 } 274 .opening-days.show-further .current mw-core-icon { 275 transform: rotate(180deg); 276 } 277 .opening-days .further { 278 display: none; 279 } 280 .opening-days.show-further .further { 281 display: block; 282 margin: 8px 0 0 0; 283 } 284 .opening-days .day { 285 display: flex; 286 padding: 2px 0; 287 } 288 .opening-days .day .d { 289 display: flex; 290 flex: 2; 291 } 292 .opening-days .day .t { 293 display: flex; 294 flex: 3; 295 } 296 .date { 297 color: var(--mw-core-color-brand1); 298 margin-bottom: 4px; 299 } 300 .price { 301 color: var(--mw-core-color-body-text-dark); 302 margin: 12px 0 0 0; 303 } 304 .center { 305 align-items: flex-end; 306 display: flex; 307 flex: 0 0 100%; 308 margin: 16px 0; 309 } 310 .availability:not(.no-availability) { 311 color: var(--mw-core-color-state-success); 312 margin-top: 8px; 313 } 314 .marketinggroups { 315 display: inline-flex; 316 flex-wrap: wrap; 317 gap: 16px; 318 width: 100%; 319 } 320 .marketinggroups .logo img { 321 display: block; 322 height: 100%; 323 max-height: 50px; 324 max-width: 100px; 325 object-fit: contain; 326 width: 100%; 327 } 328 .holidayThemes { 329 display: inline-flex; 330 flex-wrap: wrap; 331 gap: 16px; 332 width: 100%; 333 } 334 .holidayThemes .logo img { 335 display: block; 336 height: 100%; 337 max-height: 50px; 338 max-width: 100px; 339 object-fit: contain; 340 width: 100%; 341 } 342 .rating { 343 align-items: flex-end; 344 display: flex; 345 flex: 0 0 120px; 346 flex-direction: column; 347 padding: 6px 0 0 0; 348 } 349 :host([variant="compact"]) .price { 350 margin-top: 0; 351 } 352 a.href { 353 color: var(--mw-core-color-body-text-dark); 354 display: flex; 355 text-decoration: none; 356 } 357 :host([variant="compact"]) a.href { 358 justify-content: center; 359 } 360 .title { 361 margin: 0 0 12px; 362 } 363 :host([variant="compact"]) .title { 364 margin-bottom: 4px; 365 } 366 :host([objecttype="infrastructure"]) .title { 367 margin-bottom: 4px; 368 } 369 :host([objecttype="tour"]) .title { 370 margin-bottom: 4px; 371 } 372 :host([objecttype="provider"]) .title { 373 margin-bottom: 4px; 374 } 375 :host([variant="inline"]) .title { 376 color: var(--mw-core-color-body-text-bright); 377 margin-bottom: 0; 378 } 379 :host([objecttype="tour"]) span.state { 380 color: var(--mw-core-color-state-success); 381 } 382 :host([objecttype="tour"]) span.state-closed, 383 :host([objecttype="tour"]) span.state-disturbance, 384 :host([objecttype="tour"]) span.state-underconstruction, 385 :host([objecttype="tour"]) span.state-blocked { 386 color: var(--mw-core-color-state-error); 387 } 388 :host([objecttype="tour"]) span.state-inpreparation, 389 :host([objecttype="tour"]) span.state-partiallyopen { 390 color: var(--mw-core-color-label-moderate); 391 } 392 :host([objecttype="infrastructure"]) .tag.state { 393 background: var(--mw-core-color-state-success); 394 }
395 :host([objecttype="infrastructure"]) .tag.state-closed, 396 :host([objecttype="infrastructure"]) .tag.state-disturbance, 397 :host([objecttype="infrastructure"]) .tag.state-underconstruction { 398 background: var(--mw-core-color-state-error); 399 color: #FFFFFF; 400 } 401 .left { 402 margin: 0 10px 0 0; 403 } 404 :host([objecttype="tour"]) .left { 405 align-items: center; 406 display: flex; 407 } 408 .left .location { 409 margin: 0 0 2px; 410 } 411 .starttime { 412 background: var(--mw-core-color-brand1); 413 color: #FFFFFF; 414 display: table; 415 padding: 3px 6px; 416 } 417 .right { 418 align-items: center; 419 display: flex; 420 } 421 .phone { 422 align-items: center; 423 display: flex; 424 } 425 .phone mw-core-icon { 426 margin: 0 6px 0 0; 427 } 428 .tour-data { 429 align-items: center; 430 display: flex; 431 margin: 0 16px 0 0; 432 } 433 .tour-data:last-child { 434 margin-right: 0; 435 } 436 .tour-data.uphill { 437 display: none; 438 } 439 .tour-data mw-core-icon { 440 color: var(--mw-core-color-brand1); 441 margin-right: 6px; 442 } 443 .provider { 444 flex: 1; 445 } 446 .rating-value-wrapper { 447 margin-bottom: 4px; 448 } 449 .rating-value { 450 background: var(--mw-core-color-brand1); 451 color: #FFFFFF; 452 display: inline-flex; 453 padding: 2px 8px; 454 } 455 .provider-price { 456 background: none; 457 border: none; 458 cursor: pointer; 459 padding: 0; 460 position: relative; 461 } 462 .provider-price .price-value { 463 color: var(--mw-core-color-brand1); 464 display: flex; 465 } 466 .provider-price .price-value .price { 467 color: var(--mw-core-color-brand1); 468 display: flex; 469 margin: 0; 470 } 471 .provider-price .price-value .price-wrapper { 472 align-items: center; 473 display: flex; 474 } 475 .provider-price .price-value .price-wrapper .previous-price { 476 font-size: 18px; 477 margin-right: 8px; 478 text-decoration: line-through; 479 opacity: 0.5; 480 } 481 .provider-price .price-info { 482 display: flex; 483 } 484 .provider-price .free-cancellation { 485 background: var(--mw-core-color-state-success); 486 border-radius: 4px; 487 color: #FFFFFF; 488 display: table; 489 margin: 4px 0 0 0; 490 padding: 4px 8px; 491 }´ 492 .provider-price .preloader { 493 position: absolute; 494 top: 50%; 495 } 496 .bookmark { 497 background: none; 498 border: none; 499 color: var(--mw-core-color-brand1); 500 cursor: pointer; 501 line-height: 1; 502 padding: 0; 503 position: relative; 504 } 505 .bookmark:hover { 506 color: var(--mw-core-color-background-dark); 507 } 508 .bookmark + .button, 509 .bookmark + a.href { 510 margin: 0 0 0 18px; 511 } 512 513 /*** Inline ***/ 514 515 :host([variant="inline"]) { 516 min-height: 110px; 517 } 518 :host([variant="inline"]) .image { 519 height: 100%; 520 } 521 :host([variant="inline"]) .main { 522 background: var(--mw-core-color-overlay-gradient-dark-top); 523 left: 0; 524 min-height: 110px; 525 padding: 18px 16px; 526 position: absolute; 527 right: 0; 528 top: 0; 529 } 530 :host([variant="inline"]) .content { 531 align-items: center; 532 display: flex; 533 justify-content: space-between; 534 margin: 0; 535 } 536 :host([variant="inline"]) a.href { 537 color: var(--mw-core-color-body-text-bright); 538 } 539 :host([variant="inline"]) .bookmark { 540 line-height: 1; 541 margin: 0 0 0 10px; 542 } 543 :host([variant="inline"]) .bookmark { 544 color: var(--mw-core-color-action-primary); 545 } 546 :host([variant="inline"]) .bookmark:hover { 547 color: var(--mw-core-color-action-primary-variant); 548 } 549 550 @media all and (min-width: 420px) { 551 552 .tour-data.uphill { 553 display: flex; 554 } 555 556 } 557 558 @media all and (min-width: 500px) { 559 560 :host([as="singleteaser"]) .teaser { 561 flex-direction: row; 562 } 563 :host([as="singleteaser"]) .image { 564 flex: 1; 565 } 566 :host([as="singleteaser"]) .main { 567 flex: 2; 568 } 569 :host([as="singleteaser"][objecttype="provider"]) .content { 570 flex: 1; 571 } 572 :host([as="singleteaser"][objecttype="provider"]) .teasertext,
573 :host([as="singleteaser"][objecttype="infrastructure"]) .teasertext, 574 :host([as="singleteaser"][objecttype="tour"]) .teasertext { 575 display: block; 576 margin: 24px 0 0 0; 577 } 578 579 } 580 581 @media all and (min-width: 769px) { 582 583 .main { 584 padding: 32px 24px; 585 } 586 .content { 587 margin: 0 0 20px; 588 } 589 .price { 590 margin: 18px 0 0; 591 } 592 .title { 593 margin: 0 0 18px; 594 } 595 .left p.location { 596 margin: 0 0 4px; 597 } 598 599 /*** Inline ***/ 600 601 :host([variant="inline"]) .main { 602 padding: 25px; 603 } 604 605 } 606 607 ` 608 ]; 609 } 610 611 // render template 612 613 render() { 614 // check data 615 616 if (!this._data) { 617 console.error("no valid data"); 618 return ""; 619 } 620 621 if (!this.variant) { 622 this.variant = "default"; 623 } 624 625 let objectType = "web"; 626 627 if (this._data.objectType) { 628 objectType = this._data.objectType; 629 } 630 631 this.objectType = objectType; 632 633 // detect objectType 634 635 switch (objectType) { 636 case "web": 637 case "event": 638 return this.layoutDefault(); 639 640 case "infrastructure": 641 return this.layoutInfrastructure(); 642 643 case "tour": 644 return this.layoutTour(); 645 646 case "service": 647 return this.layoutService(); 648 649 case "provider": 650 case "package": 651 return this.layoutProvider(); 652 653 case "joboffer": 654 return this.layoutJobOffer(); 655 656 default: 657 return this.layoutDefault(); 658 } 659 } 660 661 // getter and setter 662 663 get linkelement() { 664 return this._getAttribute("linkelement"); 665 } 666 667 set linkelement(val) { 668 this._setAttribute("linkelement", val); 669 } 670 671 get button() { 672 return this._getAttribute("button"); 673 } 674 675 set button(val) { 676 this._setAttribute("button", val); 677 } 678 679 get buttonattr() { 680 return this._getAttribute("buttonattr"); 681 } 682 683 set buttonattr(val) { 684 this._setAttribute("buttonattr", val); 685 } 686 687 get bookmark() { 688 return this._getAttribute("bookmark"); 689 } 690 691 set bookmark(val) { 692 this._setAttribute("bookmark", val); 693 } 694 695 set background(val) { 696 this._setAttribute("background", val); 697 } 698 699 get background() { 700 return this._getAttribute("background"); 701 } 702 703 get variant() { 704 return this._getAttribute("variant"); 705 } 706 707 set variant(val) { 708 this._setAttribute("variant", val); 709 } 710 711 get saleschannelid() { 712 return this._getAttribute("salesChannelID"); 713 } 714 715 set saleschannelid(val) { 716 this._setAttribute("salesChannelID", val); 717 } 718 719 get mqmedia() { 720 return this._getAttribute("mqmedia"); 721 } 722 723 set mqmedia(val) { 724 this._setAttribute("mqmedia", val); 725 } 726 727 get maxlines() { 728 return this._getAttribute("maxlines"); 729 } 730 731 set maxlines(val) { 732 this._setAttribute("maxlines", val); 733 } 734 735 get maxlineslineheight() { 736 return this._getAttribute("maxlineslineheight"); 737 } 738 739 set maxlineslineheight(val) { 740 this._setAttribute("maxlineslineheight", val); 741 } 742 743 get fallbackpicture() { 744 return this._getAttribute("fallbackpicture"); 745 } 746 747 set fallbackpicture(val) { 748 this._setAttribute("fallbackpicture", val); 749 } 750 751 get objectType() { 752 return this._getAttribute("objectType"); 753 } 754 755 set objectType(val) { 756 this._setAttribute("objectType", val); 757 } 758 759 get as() { 760 return this._getAttribute("as"); 761 } 762 763 set as(val) { 764 this._setAttribute("as", val); 765 } 766 767 get priceaddition() { 768 return this._getAttribute("priceaddition"); 769 } 770 771 set priceaddition(val) { 772 this._setAttribute("priceaddition", val); 773 } 774 775 get priceformat() { 776 return this._getAttribute("priceformat"); 777 } 778 779 set priceformat(val) { 780 this._setAttribute("priceformat", val); 781 } 782 783 get preloadprices() { 784 return this._getAttribute("preloadprices"); 785 } 786 787 set preloadprices(val) { 788 this._setAttribute("preloadprices", val); 789 } 790 791 set asyncprices(teaser) { 792 // try to insert prices 793 // ! important note: preloadprices should be set before 794 795 if (teaser.price && teaser.price.from >= 0) { 796 if (!this._dom.providerPriceValue) { 797 console.error("providerPriceValue missing"); 798 return undefined; 799 } 800 801 let previousPrice = ``; 802 this._data = teaser; 803 804 if (this._dom.providerPrice) { 805 this._dom.providerPrice.setAttribute("tabindex", "0"); 806 } 807 808 if (teaser.price.isSpecialPrice) { 809 let prefix = this._CONSTANTS.PRICEFROM; 810 let currency = "â¬"; 811 let discount = this._data.price.specialPriceDiscount; 812 813 let formatedPrice = mwUtility.formatNumber(this._data.price.from + discount); 814 815 previousPrice = `${prefix} ${formatedPrice} ${currency}`; 816 } 817 818 if (teaser.price.isSpecialPrice) { 819 this._dom.providerPriceValue.innerHTML += `<span class="previous-price">${this.priceValue()}</span>`; 820 } 821 822 this._dom.providerPriceValue.innerHTML = `${ 823 teaser.price.isSpecialPrice 824 ? `<span class="price-wrapper"><span class="previous-price">${previousPrice}</span>` 825 : `` 826 }<span class="price">${this.priceValue()}<span class="price-info"><mw-core-icon class="cancellation" name="I" size="s"></mw-core-icon></span></span></span>`; 827 828 if (this._data.price.addition) { 829 this._dom.providerPriceLabel.innerHTML = this.priceLabel(); 830 } else { 831 this._dom.providerPriceLabel.innerHTML = ``; 832 } 833 } else { 834 this._dom.providerPriceValue.innerHTML = ``; 835 836 if (this._dom.providerPrice) { 837 this._dom.providerPrice.setAttribute("tabindex", "-1"); 838 } 839 } 840 841 if (this._data.price.specialPriceName) { 842 this._dom.tag.innerHTML = this._data.price.specialPriceName; 843 this._dom.tag.classList.remove("no-tag"); 844 } else { 845 this._dom.tag.classList.add("no-tag"); 846 } 847 848 if (this._dom.availability) { 849 if (this._data.availability && this._data.availability <= 3) { 850 this._dom.availability.innerHTML = `${this._CONSTANTS.COUNTAVAILABILITY.replace( 851 "%%COUNT%%", 852 this._data.availability 853 )}`; 854 this._dom.availability.classList.remove("no-availability"); 855 } else { 856 this._dom.availability.innerHTML = ``; 857 this._dom.availability.classList.add("no-availability"); 858 } 859 } 860
861 if (this._data && this._data.cancellationDetails && this._data.cancellationDetails.free) { 862 if (this._dom.providerPriceLabel) { 863 this._dom.providerPriceLabel.classList.add("free-cancellation"); 864 this._dom.providerPriceLabel.innerHTML = this._CONSTANTS.FREECANCELLATION; 865 } 866 } 867 } 868 869 get id() { 870 if (this._data.id) { 871 return this._data.id; 872 } 873 874 return undefined; 875 } 876 877 // custom methods 878 879 cacheDOM() { 880 // cache DOM elements for faster access 881 882 this._dom = { 883 teaser: this.shadowRoot.querySelector(".teaser"), 884 button: this.shadowRoot.querySelector(".button"), 885 buttonComponent: this.shadowRoot.querySelector(".button mw-core-button"), 886 tag: this.shadowRoot.querySelector(".tag"), 887 availability: this.shadowRoot.querySelector(".availability"), 888 image: this.shadowRoot.querySelector(".image"), 889 date: this.shadowRoot.querySelector(".date"), 890 price: this.shadowRoot.querySelector(".price"), 891 href: this.shadowRoot.querySelector("a.href"), 892 title: this.shadowRoot.querySelector(".title"), 893 text: this.shadowRoot.querySelector(".text"), 894 addition: this.shadowRoot.querySelector(".addition"), 895 location: this.shadowRoot.querySelector(".location"), 896 bookmark: this.shadowRoot.querySelector(".bookmark"), 897 bookmarkIcon: this.shadowRoot.querySelector(".bookmark mw-core-icon"), 898 openingDays: this.shadowRoot.querySelector(".opening-days"), 899 providerPrice: this.shadowRoot.querySelector(".provider-price"), 900 providerPriceValue: this.shadowRoot.querySelector(".price-value"), 901 providerPriceLabel: this.shadowRoot.querySelector(".price-label") 902 }; 903 } 904 905 registerEventListener() { 906 // bookmark 907 908 if (this._dom.bookmark) { 909 this._dom.bookmark.addEventListener("click", (e) => { 910 e.preventDefault(); 911 912 // add to bookmark 913 914 if (mwBookmark.add(this._data)) { 915 // change icon 916 917 this._dom.bookmarkIcon.name = "heartselected"; 918 this._dom.bookmark.setAttribute("aria-pressed", true); 919 } else { 920 // remove from bookmark 921 922 mwBookmark.delete(this._data); 923 924 // change icon 925 926 this._dom.bookmarkIcon.name = "heart"; 927 this._dom.bookmark.setAttribute("aria-pressed", false); 928 } 929 }); 930 } 931 932 // toggle opening days wrapper 933 934 if (this._dom.openingDays) { 935 let current = this._dom.openingDays.querySelector(".current"); 936 937 if (current) { 938 current.addEventListener("click", (e) => { 939 e.preventDefault(); 940 941 const isExpanded = current.getAttribute("aria-expanded") === "true"; 942 const newState = !isExpanded; 943 944 this._dom.openingDays.classList.toggle("show-further", newState); 945 current.setAttribute("aria-expanded", newState); 946 }); 947 } 948 } 949 950 // show price info 951 952 if (this._dom.providerPrice) { 953 this._dom.providerPrice.setAttribute("tabindex", "-1"); 954 955 this._dom.providerPrice.addEventListener("click", (e) => { 956 if (mwUtility.cookie("mw-core-bookingsearch") === "true") { 957 e.preventDefault(); 958 this.showPriceInfo(); 959 } 960 }); 961 } 962 } 963 964 parseConstants() { 965 // parse constants 966 // from component-constants template 967 968 try { 969 let template = this.querySelector(`template[is="component-constants"]`); 970 971 if (template) { 972 this._CONSTANTS = JSON.parse(template.content.textContent); 973 974 // remove template from DOM 975 976 template.remove(); 977 } 978 } catch (error) { 979 console.error(error); 980 return; 981 } 982 } 983 984 layoutDefault() { 985 // layout default (web, events) 986 987 this.parseConstants(); 988 989 // pagename 990 991 let pagename = this._data.pageName === "//.html" && this._data.externalLink ? this._data.externalLink : this._data.pageName ? this._data.pageName : `#`; 992 993 if (this._data.linkAnchorTag !== "") { 994 pagename += `#${this._data.linkAnchorTag}`; 995 } 996 997 // target 998 999 let target = this._data.target ? `target="${this._data.target}"` : ``; 1000 1001 // rel attribute ("noopener noreferrer" if external url) 1002 1003 let rel = this._data.external === true ? `rel="noopener noreferrer"` : ``; 1004 1005 // teaserimage 1006 1007 let picture = ``; 1008 1009 // date 1010 1011 let date = ``; 1012 let dateString = ``; 1013 let startTime = ``; 1014 1015 if (this._data.date) { 1016 if (this._data.date.next && !this._data.recurring) { 1017 let dateNextObj = new Date(this._data.date.next); 1018 1019 if (mwUtility.checkValidDate(dateNextObj)) { 1020 let dateNextStr = mwUtility.formatDateToString(dateNextObj); 1021 date = dateNextStr; 1022 } 1023 } else { 1024 // datefrom 1025 1026 let dateFromObj = new Date(this._data.date.from); 1027 1028 if (mwUtility.checkValidDate(dateFromObj)) { 1029 let dateFromStr = mwUtility.formatDateToString(dateFromObj); 1030 date = dateFromStr; 1031 } 1032 1033 // dateto 1034 1035 let dateToObj = new Date(this._data.date.to); 1036 1037 if (mwUtility.checkValidDate(dateToObj)) { 1038 let dateToStr = mwUtility.formatDateToString(dateToObj); 1039 date !== "" ? (date += " - " + dateToStr) : (date = dateToStr); 1040 } 1041 } 1042 1043 dateString = date; 1044 1045 if (date) { 1046 date = `<p class="date ${ 1047 this.variant === "compact" ? `normal-text-bold` : `large-text-bold` 1048 }">${date}</p>`; 1049 } 1050 1051 // starttime 1052 1053 if (this._data.date.timeFrom && this._data.date.timeFrom !== "00:00") { 1054 startTime = this._data.date.timeFrom; 1055 } 1056 } 1057 1058 if (startTime && startTime !== "00:00") { 1059 startTime = `<p class="starttime small-text-bold effect-border-radius">${startTime}</p>`; 1060 } 1061 1062 // read rule 1063 // if this.mqmedia is null 1064 // try read mqmedia from data 1065 // for example relevant in bookmark 1066 1067 let mqMediaRule; 1068 1069 if (this.mqmedia) { 1070 mqMediaRule = this.mqmedia; 1071 } else if (this._data.mqmedia) { 1072 mqMediaRule = this._data.mqmedia; 1073 } 1074 1075 if (this._data.media && this._data.media.length > 0 && this._data.media[0].filename) { 1076 picture = mwUtility.htmlMediaPicture( 1077 this._data.media[0], 1078 mqMediaRule, 1079 this._data?.media[0]?.alt || this._data?.title, 1080 { lang: this._data.media[0]?.lang} 1081 ); 1082 } else { 1083 if (this.fallbackpicture) { 1084 picture = `<picture><img src="${this.fallbackpicture}" alt="Fallback Image"></picture>`; 1085 } 1086 } 1087 1088 // link picture? 1089 1090 if (!this.linkelement && picture) { 1091 picture = `<a class="href" href="${ 1092 this.objectType === "event" ? pagename + "#" + dateString : pagename 1093 }" ${target} ${rel}>${picture}</a>`; 1094 } 1095 1096 // teasertext 1097 1098 let description = ``; 1099 1100 if (this._data.description) { 1101 if (this.variant === "compact") { 1102 description = `<div class="text small-text">${this._data.description}</div>`; 1103 } else { 1104 description = `<div class="text normal-text">${this._data.description}</div>`; 1105 } 1106 } 1107 1108 // teasertitle 1109 1110 let teasertitle = this._data.title 1111 ? `<p class="title ${ 1112 this.variant === "compact" ? `normal-text-bold` : `large-text-bold` 1113 }">${this._data.title}</p>` 1114 : ``; 1115 1116 // link teasertitle? 1117 1118 if (!this.linkelement && teasertitle) { 1119 teasertitle = `<a class="href" href="${ 1120 this.objectType === "event" ? pagename + "#" + dateString : pagename 1121 }" ${target} ${rel}>${teasertitle}</a>`; 1122 } 1123 1124 // price 1125 1126 let price = ``; 1127 1128 if (this.objectType === "event") { 1129 price = ``; 1130 } else { 1131 if (!this.priceformat) { 1132 this.priceformat = "long"; 1133 } 1134 1135 if (this._data.price) { 1136 let priceShort = this._data.price.split(",")[0] + ",-"; 1137 let priceLong = this._data.price; 1138 1139 if (this.priceformat === "short") { 1140 price = `<p class="price ${ 1141 this.variant === "compact" ? `small-text-bold` : `large-text-bold` 1142 }">${priceShort} ⬠${ 1143 this.priceaddition 1144 ? `<span class="small-text-bold">${this.priceaddition}</span>` 1145 : `` 1146 }</p>`; 1147 } else { 1148 price = `<p class="price ${ 1149 this.variant === "compact" ? `small-text-bold` : `large-text-bold` 1150 }">${priceLong} ⬠${ 1151 this.priceaddition 1152 ? `<span class="small-text-bold">${this.priceaddition}</span>` 1153 : `` 1154 }</p>`; 1155 } 1156 } 1157 } 1158 1159 // location 1160 1161 let location = 1162 this._data.location && this.variant !== "compact" 1163 ? `<p class="location small-text-bold">${this._data.location}</p>` 1164 : ``; 1165 1166 // addition 1167 1168 let addition = 1169 this._data.addition && this.variant !== "compact" 1170 ? `<p class="addition caption-text">${this._data.addition}</p>` 1171 : ``; 1172 1173 // bookmark 1174 1175 let bookmark = 1176 this.bookmark && this.variant !== "compact" 1177 ? `<button aria-label="${document.documentElement.lang === "de" ? "merken" : "save"}" class="bookmark" type="button"><mw-core-icon size="m" name="${this.checkBookmark( 1178 "heart", 1179 "heartselected" 1180 )}" aria-pressed="false"></mw-core-icon></button>` 1181 : ``; 1182
1183 // tag + recurring tag (events) 1184 1185 let tag = this._data.tag || this._data.recurring 1186 ? `<p class="tag caption-text-bold effect-border-radius">${this._data.tag || this._CONSTANTS.RECURRING}</p>` 1187 : ``; 1188 1189 // status (events) 1190 1191 let status = `` 1192 1193 if (this.objectType === "event" && this._data.statusType) { 1194 1195 let label = ``; 1196 let state = ``; 1197 1198 switch (this._data.statusType) { 1199 case "cancelled": 1200 label = this._CONSTANTS.STATECANCELLED; 1201 state = "cancelled" 1202 break; 1203 1204 case "scheduled": 1205 label = this._CONSTANTS.STATESCHEDULED; 1206 state = "scheduled" 1207 break; 1208 1209 case "rescheduled": 1210 label = this._CONSTANTS.STATERESCHEDULED; 1211 state = "rescheduled" 1212 break; 1213 1214 case "postponed": 1215 label = this._CONSTANTS.STATEPOSTPONED; 1216 state = "postponed" 1217 break; 1218 1219 } 1220 1221 status = `<p class="tag state state-${state} caption-text-bold effect-border-radius">${label}</p>` 1222 } 1223 1224 // button 1225 1226 let button = ``; 1227 1228 if (this.button !== true && this.button !== null) { 1229 if (this.variant === "compact") { 1230 button = ` 1231 <p class="button"> 1232 <mw-core-button nofocus tertiary ${this.buttonattr} nolabel icon="3" small iconsize="s"></mw-core-button> 1233 </p>`; 1234 } else { 1235 button = ` 1236 <p class="button"> 1237 <mw-core-button nofocus primary ${this.buttonattr} label="${this.button}" labelclass="primary-link"></mw-core-button> 1238 </p> 1239 `; 1240 } 1241 } 1242 1243 // link button? 1244 1245 if (!this.linkelement && button) { 1246 button = `<a class="href" href="${ 1247 this.objectType === "event" ? pagename + "#" + dateString : pagename 1248 }" ${target} ${rel}>${button}</a>`; 1249 } 1250 1251 let html = ``; 1252 1253 if (this.variant === "inline") { 1254 html = ` 1255 ${ 1256 this.linkelement 1257 ? `<a class="href" href="${ 1258 this.objectType === "event" ? pagename + "#" + dateString : pagename 1259 }" ${target} ${rel}>` 1260 : `` 1261 } 1262 <div class="teaser"> 1263 ${tag} 1264 ${status} 1265 <div class="image"> 1266 ${picture} 1267 <span class="teaser-frame" aria-hidden="true"></span> 1268 </div> 1269 <div class="main"> 1270 <div class="content"> 1271 ${teasertitle} 1272 ${bookmark} 1273 </div> 1274 </div> 1275 </div> 1276 ${this.linkelement ? `</a>` : ``} 1277 `; 1278 } else { 1279 html = ` 1280 ${ 1281 this.linkelement 1282 ? `<a class="href" href="${ 1283 this.objectType === "event" ? pagename + "#" + dateString : pagename 1284 }" ${target} ${rel}>` 1285 : `` 1286 } 1287 <div class="teaser ${tag && status ? `double-tag` : ``}"> 1288 ${tag} 1289 ${status} 1290 <div class="image"> 1291 ${picture} 1292 <span class="teaser-frame" aria-hidden="true"></span> 1293 </div> 1294 <div class="main"> 1295 <div class="content"> 1296 ${date} 1297 ${teasertitle} 1298 ${description} 1299 ${price} 1300 </div> 1301 <div class="bottom ${ 1302 this._data.location || this._data.addition || startTime ? `has-info` : `` 1303 }"> 1304 ${ 1305 location || addition || startTime 1306 ? `<div class="left">${location + addition + startTime}</div>` 1307 : "" 1308 } 1309 ${bookmark || button ? ` <div class="right">${bookmark + button}</div>` : ""} 1310 </div> 1311 </div> 1312 </div> 1313 ${this.linkelement ? `</a>` : ``} 1314 `; 1315 } 1316 1317 return html; 1318 } 1319 1320 layoutInfrastructure() { 1321 // layout infrastructure 1322 1323 // parse constants 1324 1325 this.parseConstants(); 1326 1327 if (!this._CONSTANTS) { 1328 console.error(`CONSTANTS missing in ${this.tagName.toLowerCase()}`); 1329 return; 1330 } 1331 1332 // pagename 1333 1334 let pagename = this._data.pageName ? this._data.pageName : `#`; 1335 1336 // target 1337 1338 let target = this._data.target ? `target="${this._data.target}"` : ``; 1339 1340 // teaserimage 1341 1342 let picture = ``; 1343 1344 // read rule 1345 // if this.mqmedia is null 1346 // try read mqmedia from data 1347 // for example relevant in bookmark 1348 1349 let mqMediaRule; 1350 1351 if (this.mqmedia) { 1352 mqMediaRule = this.mqmedia; 1353 } else if (this._data.mqmedia) { 1354 mqMediaRule = this._data.mqmedia; 1355 } 1356 1357 if (this._data.media && this._data.media.length > 0) { 1358 picture = mwUtility.htmlMediaPicture( 1359 this._data.media[0], 1360 mqMediaRule, 1361 this._data?.media[0]?.alt || this._data?.title 1362 ); 1363 } else { 1364 if (this.fallbackpicture) { 1365 picture = `<picture><img src="${this.fallbackpicture}" alt="Fallback Image"></picture>`; 1366 } 1367 } 1368 1369 // link picture? 1370 1371 if (!this.linkelement && picture) { 1372 picture = `<a class="href" href="${ 1373 this.objectType === "event" ? pagename + "#" + dateString : pagename 1374 }" ${target}>${picture}</a>`; 1375 } 1376 1377 // title 1378 1379 let title = this._data.title 1380 ? `<p class="title ${ 1381 this.variant === "compact" ? `normal-text-bold` : `large-text-bold` 1382 }">${this._data.title}</p>` 1383 : ``; 1384 1385 // link title? 1386 1387 if (!this.linkelement && title) { 1388 title = `<a class="href" href="${ 1389 this.objectType === "event" ? pagename + "#" + dateString : pagename 1390 }" ${target}>${title}</a>`; 1391 } 1392 1393 // teasertext 1394 1395 let description = ``; 1396 1397 if (this._data.description) { 1398 if (this.variant === "compact") { 1399 description = `<div class="teasertext small-text">${this._data.description}</div>`; 1400 } else { 1401 description = `<div class="teasertext normal-text">${this._data.description}</div>`; 1402 } 1403 } 1404 1405 // address 1406 1407 let address = ``; 1408 1409 if (this._data.address) { 1410 let street = this._data.address.street ? `${this._data.address.street}` : ``; 1411 let zipCode = this._data.address.zipCode ? `${this._data.address.zipCode}` : ``; 1412 let town = this._data.address.town ? `${this._data.address.town}` : ``; 1413 1414 address = ` 1415 <div class="text small-text"> 1416 ${street + (street ? `, ` : ``) + zipCode + (zipCode ? ` ` : ``) + town} 1417 </div> 1418 `; 1419 } 1420 1421 // phone 1422 1423 let phone = ``; 1424 1425 if (this._data.address) { 1426 if (this._data.address.phone || this._data.address.mobile) { 1427 let phonelink = this._data.address.phone 1428 ? this._data.address.phone 1429 : this._data.address.mobile; 1430 1431 phone = ` 1432 <a class="phone caption-text" href="tel:${phonelink 1433 .replace(/\s/g, "") 1434 .replace(/[\(\)]/g, "")}"> 1435 <mw-core-icon size="m" name="phone"></mw-core-icon> 1436 ${this._data.address.phone ? this._data.address.phone : this._data.address.mobile} 1437 </a> 1438 `; 1439 } 1440 } 1441 1442 // opening days 1443 1444 let openingDays = ``; 1445 1446 if (this._data.openingTimes && this._data.openingTimes.length > 0) { 1447 let currentOpening = this.checkCurrentOpening(); 1448 1449 // check if next opening date <= 7 days 1450 1451 if (this.checkNextOpeningDaySmallerThen(this._data.openingTimes, 6)) { 1452 openingDays = ` 1453 <div class="opening-days"> 1454 <button class="current" type="button" aria-expanded="false"> 1455 ${ 1456 currentOpening 1457 ? `${currentOpening} <mw-core-icon size="s" name="5"></mw-core-icon>` 1458 : `` 1459 } 1460 </button> 1461 <div class="further">${this.listNextOpeningDays()}</div> 1462 </div> 1463 `; 1464 } else { 1465 openingDays = ` 1466 <div class="opening-days"> 1467 <div class="current no-further-openingdays"> 1468 ${currentOpening ? `${currentOpening}` : ``} 1469 </div> 1470 </div> 1471 `; 1472 } 1473 } 1474 1475 // status 1476 1477 let status = ``; 1478
1479 if (this.objectType === "infrastructure" && this._data.statusType) { 1480 1481 let label = ``; 1482 let state = ``; 1483 1484 switch (this._data.statusType) { 1485 case "open": 1486 label = this._CONSTANTS.OPEN; 1487 state = "open" 1488 break; 1489 1490 case "closed": 1491 label = this._CONSTANTS.CLOSED; 1492 state = "closed" 1493 break; 1494 1495 case "underconstruction": 1496 label = this._CONSTANTS.UNDERCONSTRUCTION; 1497 state = "underconstruction" 1498 break; 1499 1500 case "disturbance": 1501 label = this._CONSTANTS.DISTURBANCE; 1502 state = "disturbance" 1503 break; 1504 1505 } 1506 1507 status = `<p class="tag state state-${state} caption-text-bold effect-border-radius">${label}</p>` 1508 } 1509 1510 // holiday themes 1511 1512 let holidayThemes = ``; 1513 1514 if (this._data.holidayThemes) { 1515 holidayThemes += `<div class="holidayThemes">`; 1516 1517 this._data.holidayThemes.forEach((item) => { 1518 if (item?.media?.[0]?.filename) { 1519 holidayThemes += `<div class="logo" title="${item?.title}"><img src="${item?.media?.[0]?.filename}" alt="${item?.title}" aria-label="${item?.title}" /></div>`; 1520 } 1521 }) 1522 1523 holidayThemes += `</div>`; 1524 } 1525 1526 // bookmark 1527 1528 let bookmark = 1529 this.bookmark && this.variant !== "compact" 1530 ? `<button aria-label="${document.documentElement.lang === "de" ? "merken" : "save"}" class="bookmark" type="button"><mw-core-icon size="m" name="${this.checkBookmark( 1531 "heart", 1532 "heartselected" 1533 )}" aria-pressed="false"></mw-core-icon></button>` 1534 : ``; 1535 1536 // button 1537 1538 let button = ``; 1539 1540 if (this.button !== true && this.button !== null) { 1541 if (this.variant === "compact") { 1542 button = ` 1543 <p class="button"> 1544 <mw-core-button nofocus tertiary nolabel icon="3" small iconsize="s"></mw-core-button> 1545 </p>`; 1546 } else { 1547 button = ` 1548 <p class="button"> 1549 <mw-core-button nofocus primary label="${this.button}" labelclass="primary-link"></mw-core-button> 1550 </p> 1551 `; 1552 } 1553 } 1554 1555 let html = ``; 1556 1557 if (this.variant === "inline") { 1558 html = ` 1559 <div class="teaser"> 1560 <a class="href" href="${ 1561 this.objectType === "event" ? pagename + "#" + dateString : pagename 1562 }" ${target}> 1563 <div class="image"> 1564 ${picture} 1565 <span class="teaser-frame" aria-hidden="true"></span> 1566 </div> 1567 </a> 1568 <div class="main"> 1569 <div class="content"> 1570 <a class="href" href="${ 1571 this.objectType === "event" ? pagename + "#" + dateString : pagename 1572 }" ${target}> 1573 ${title} 1574 </a> 1575 ${bookmark} 1576 </div> 1577 </div> 1578 </div> 1579 `; 1580 } else { 1581 html = ` 1582 <div class="teaser"> 1583 <a class="href" href="${ 1584 this.objectType === "event" ? pagename + "#" + dateString : pagename 1585 }" ${target}> 1586 <div class="image"> 1587 ${picture} 1588 <span class="teaser-frame" aria-hidden="true"></span> 1589 </div> 1590 </a> 1591 <div class="main"> 1592 <div class="content"> 1593 <a class="href" href="${ 1594 this.objectType === "event" ? pagename + "#" + dateString : pagename 1595 }" ${target}> 1596 ${title} 1597 </a> 1598 ${address} 1599 ${description} 1600 ${status ? status : openingDays} 1601 </div> 1602 <div class="bottom ${phone ? `has-info` : ``}"> 1603 <div class="left">${phone}</div> 1604 ${bookmark || button ? ` <div class="right">${bookmark + button}</div>` : ""} 1605 </div> 1606 </div> 1607 </div> 1608 `; 1609 } 1610 1611 return html; 1612 } 1613 1614 layoutService() { 1615 // layout service 1616 1617 // parse constants 1618 1619 this.parseConstants(); 1620 1621 if (!this._CONSTANTS) { 1622 console.error(`CONSTANTS missing in ${this.tagName.toLowerCase()}`); 1623 return; 1624 } 1625 1626 // pagename 1627 1628 let pagename = this._data.pageName ? this._data.pageName : `#`; 1629 1630 // target 1631 1632 let target = this._data.target ? `target="${this._data.target}"` : ``; 1633 1634 // teaserimage 1635 1636 let picture = ``; 1637 1638 // read rule 1639 // if this.mqmedia is null 1640 // try read mqmedia from data 1641 // for example relevant in bookmark 1642 1643 let mqMediaRule; 1644 1645 if (this.mqmedia) { 1646 mqMediaRule = this.mqmedia; 1647 } else if (this._data.mqmedia) { 1648 mqMediaRule = this._data.mqmedia; 1649 } 1650 1651 if (this._data.mediaList && this._data.mediaList.length > 0) { 1652 picture = mwUtility.htmlMediaPicture( 1653 this._data.mediaList[0], 1654 mqMediaRule, 1655 this._data?.mediaList[0]?.alt || this._data?.title, 1656 { lang: this._data.mediaList[0]?.lang} 1657 ); 1658 } else { 1659 if (this.fallbackpicture) { 1660 picture = `<picture><img src="${this.fallbackpicture}" alt="Fallback Image"></picture>`; 1661 } 1662 } 1663 1664 // link picture? 1665 1666 if (!this.linkelement && picture) { 1667 picture = `<a class="href" href="${pagename}" ${target}>${picture}</a>`; 1668 } 1669 1670 // title 1671 1672 let title = this._data.title 1673 ? `<p class="title ${ 1674 this.variant === "compact" ? `normal-text-bold` : `large-text-bold` 1675 }">${this._data.title}</p>` 1676 : ``; 1677 1678 // link title? 1679 1680 if (!this.linkelement && title) { 1681 title = `<a class="href" href="${pagename}" ${target}>${title}</a>`; 1682 } 1683 1684 // price 1685 1686 let price = ``; 1687 1688 if (!this.priceformat) { 1689 this.priceformat = "long"; 1690 } 1691 1692 if (this._data.price && !isNaN(this._data.price.from)) { 1693 let priceValue = this.priceValue(); 1694 1695 price = `<p class="price ${this.variant === "compact" ? `small-text-bold` : `large-text-bold`}">${priceValue}</p>`; 1696 } 1697 1698 // teasertext 1699 1700 let description = ``; 1701 1702 if (this._data.description) { 1703 if (this.variant === "compact") { 1704 description = `<div class="teasertext small-text">${this._data.description}</div>`; 1705 } else { 1706 description = `<div class="teasertext normal-text">${this._data.description}</div>`; 1707 } 1708 } 1709 1710 // bookmark 1711 1712 let bookmark = 1713 this.bookmark && this.variant !== "compact" 1714 ? `<button aria-label="${document.documentElement.lang === "de" ? "merken" : "save"}" class="bookmark" type="button"><mw-core-icon size="m" name="${this.checkBookmark( 1715 "heart", 1716 "heartselected" 1717 )}" aria-pressed="false"></mw-core-icon></button>` 1718 : ``; 1719 1720 // button 1721 1722 let button = ``; 1723 1724 if (this.button !== true && this.button !== null) { 1725 if (this.variant === "compact") { 1726 button = ` 1727 <p class="button"> 1728 <mw-core-button nofocus tertiary nolabel icon="3" small iconsize="s"></mw-core-button> 1729 </p>`; 1730 } else { 1731 button = ` 1732 <p class="button"> 1733 <mw-core-button nofocus primary label="${this.button}" labelclass="primary-link"></mw-core-button> 1734 </p> 1735 `; 1736 } 1737 } 1738 1739 let html = ``; 1740 1741 if (this.variant === "inline") { 1742 html = ` 1743 <div class="teaser"> 1744 <a class="href" href="${pagename}" ${target}> 1745 <div class="image"> 1746 ${picture} 1747 <span class="teaser-frame" aria-hidden="true"></span> 1748 </div> 1749 </a> 1750 <div class="main"> 1751 <div class="content"> 1752 <a class="href" href="${pagename}" ${target}> 1753 ${title} 1754 </a> 1755 ${bookmark} 1756 </div> 1757 </div> 1758 </div> 1759 `; 1760 } else { 1761 html = ` 1762 <div class="teaser"> 1763 <a class="href" href="${pagename}" ${target}> 1764 <div class="image"> 1765 ${picture} 1766 <span class="teaser-frame" aria-hidden="true"></span> 1767 </div> 1768 </a> 1769 <div class="main"> 1770 <div class="content"> 1771 <a class="href" href="${pagename}" ${target}> 1772 ${title} 1773 </a> 1774 ${description} 1775 ${price} 1776 </div> 1777 <div class="bottom"> 1778 ${bookmark || button ? ` <div class="right">${bookmark + button}</div>` : ""} 1779 </div> 1780 </div> 1781 </div> 1782 `; 1783 } 1784 1785 return html; 1786 } 1787 1788 layoutJobOffer() { 1789 // layout default (job offer) 1790 1791 // parse constants 1792 1793 this.parseConstants();
1794 1795 if (!this._CONSTANTS) { 1796 console.error(`CONSTANTS missing in ${this.tagName.toLowerCase()}`); 1797 return; 1798 } 1799 1800 // pagename 1801 1802 let pagename = this._data.pagename ? this._data.pagename : `#`; 1803 1804 // target 1805 1806 let target = this._data.target ? `target="${this._data.target}"` : ``; 1807 1808 // rel attribute ("noopener noreferrer" if external url) 1809 1810 let rel = this._data.external === true ? `rel="noopener noreferrer"` : ``; 1811 1812 // teaserimage 1813 1814 let picture = ``; 1815 1816 // read rule 1817 // if this.mqmedia is null 1818 // try read mqmedia from data 1819 // for example relevant in bookmark 1820 1821 let mqMediaRule; 1822 1823 if (this.mqmedia) { 1824 mqMediaRule = this.mqmedia; 1825 } else if (this._data.mqmedia) { 1826 mqMediaRule = this._data.mqmedia; 1827 } 1828 1829 if (this._data.media && this._data.media.length > 0 && this._data.media[0].filename) { 1830 picture = mwUtility.htmlMediaPicture( 1831 this._data.media[0], 1832 mqMediaRule, 1833 this._data.media[0]?.alt || this._data?.title, 1834 { lang: this._data.media[0]?.lang} 1835 ); 1836 } else { 1837 if (this.fallbackpicture) { 1838 picture = `<picture><img src="${this.fallbackpicture}" alt="Fallback Image"></picture>`; 1839 } 1840 } 1841 1842 // teasertext 1843 1844 let description = ``; 1845 1846 if (this._data.description) { 1847 if (this.variant === "compact") { 1848 description = `<div class="text small-text">${this._data.description}</div>`; 1849 } else { 1850 description = `<div class="text normal-text">${this._data.description}</div>`; 1851 } 1852 } 1853 1854 // teasertitle 1855 1856 let teasertitle = this._data.title 1857 ? `<p class="title ${ 1858 this.variant === "compact" ? `normal-text-bold` : `large-text-bold` 1859 }">${this._data.title}</p>` 1860 : ``; 1861 1862 // place 1863 1864 let place = 1865 this._data.placeTitle && this.variant !== "compact" 1866 ? `<p class="place normal-text-bold">${this._data.placeTitle}</p>` 1867 : ``; 1868 1869 // town 1870 1871 let town = 1872 this._data.townTitle && this.variant !== "compact" 1873 ? `<p class="town normal-text-bold">${this._data.townTitle}</p>` 1874 : ``; 1875 1876 // salary 1877 1878 let salary = 1879 this._data.salary && this.variant !== "compact" 1880 ? ` 1881 <p class="salary large-text-bold">${this._data.salaryText}</p> 1882 ` 1883 : ``; 1884 1885 // occupationType 1886 1887 let occupationType = 1888 this._data.occupationType && this.variant !== "compact" 1889 ? ` 1890 <p class="occupation-type small-text-bold"> 1891 ${this._data.occupationType === "fulltime" ? this._CONSTANTS.LABELFULLTIME : ``} 1892 ${this._data.occupationType === "parttime" ? this._CONSTANTS.LABELPARTTIME : ``} 1893 ${ 1894 this._data.occupationType === "fulltimeorparttime" 1895 ? this._CONSTANTS.LABELFULLTIMEORPARTTIME 1896 : `` 1897 } 1898 </p>` 1899 : ``; 1900 1901 // occupationType 1902 1903 let occupationPeriod = 1904 this._data.occupationPeriod && this.variant !== "compact" 1905 ? ` 1906 <p class="occupation-period small-text-bold"> 1907 ${this._data.occupationPeriod === "seasonal" ? this._CONSTANTS.LABELSEASONAL : ``} 1908 ${this._data.occupationPeriod === "limited" ? this._CONSTANTS.LABELLIMITED : ``} 1909 ${ 1910 this._data.occupationPeriod === "yearround" 1911 ? this._CONSTANTS.LABELYEARROUND 1912 : `` 1913 } 1914 </p>` 1915 : ``; 1916 1917 // bookmark 1918 1919 let bookmark = 1920 this.bookmark && this.variant !== "compact" 1921 ? `<button aria-label="${document.documentElement.lang === "de" ? "merken" : "save"}" class="bookmark" type="button"><mw-core-icon size="m" name="${this.checkBookmark( 1922 "heart", 1923 "heartselected" 1924 )}" aria-pressed="false"></mw-core-icon></button>` 1925 : ``; 1926 1927 // button 1928 1929 let button = ``; 1930 1931 if (this.button !== true && this.button !== null) { 1932 if (this.variant === "compact") { 1933 button = ` 1934 <p class="button"> 1935 <mw-core-button nofocus tertiary ${this.buttonattr} nolabel icon="3" small iconsize="s"></mw-core-button> 1936 </p>`; 1937 } else { 1938 button = ` 1939 <p class="button"> 1940 <mw-core-button nofocus primary ${this.buttonattr} label="${this.button}" labelclass="primary-link"></mw-core-button> 1941 </p> 1942 `; 1943 } 1944 } 1945 1946 let html = ``; 1947 1948 if (this.variant === "inline") { 1949 html = ` 1950 ${ 1951 this.linkelement 1952 ? `<a class="href" href="${ 1953 this.objectType === "event" ? pagename + "#" + dateString : pagename 1954 }" ${target} ${rel}>` 1955 : `` 1956 } 1957 <div class="teaser"> 1958 <div class="image"> 1959 ${picture} 1960 <span class="teaser-frame" aria-hidden="true"></span> 1961 </div> 1962 <div class="main"> 1963 <div class="content"> 1964 ${teasertitle} 1965 ${bookmark} 1966 </div> 1967 </div> 1968 </div> 1969 ${this.linkelement ? `</a>` : ``} 1970 `; 1971 } else { 1972 html = ` 1973 <a href="${pagename}" ${target} ${rel}> 1974 <div class="teaser"> 1975 <div class="image">${picture}</div> 1976 <div class="main"> 1977 <div class="content"> 1978 ${teasertitle} 1979 ${description} 1980 ${place || town ? `${place + town}` : ""} 1981 </div> 1982 <div class="bottom ${this._data.placeTitle || this._data.townTitle ? `has-info` : ``}"> 1983 ${salary || occupationType || occupationPeriod ? `<div class="left">${salary + occupationType + occupationPeriod}</div>` : ""} 1984 ${bookmark || button ? ` <div class="right">${bookmark + button}</div>` : ""} 1985 </div> 1986 </div> 1987 </div> 1988 </a> 1989 `; 1990 } 1991 1992 return html; 1993 } 1994 1995 layoutTour() { 1996 // layout tour 1997 1998 // parse constants 1999 2000 this.parseConstants();
2001 2002 if (!this._CONSTANTS) { 2003 console.error(`CONSTANTS missing in ${this.tagName.toLowerCase()}`); 2004 return; 2005 } 2006 2007 // pagename 2008 2009 let pagename = this._data.pageName ? this._data.pageName : `#`; 2010 2011 // target 2012 2013 let target = this._data.target ? `target="${this._data.target}"` : ``; 2014 2015 // teaserimage 2016 2017 let picture = ``; 2018 2019 // read rule 2020 // if this.mqmedia is null 2021 // try read mqmedia from data 2022 // for example relevant in bookmark 2023 2024 let mqMediaRule; 2025 2026 if (this.mqmedia) { 2027 mqMediaRule = this.mqmedia; 2028 } else if (this._data.mqmedia) { 2029 mqMediaRule = this._data.mqmedia; 2030 } 2031 2032 if (this._data.media && this._data.media.length > 0) { 2033 picture = mwUtility.htmlMediaPicture( 2034 this._data.media[0], 2035 mqMediaRule, 2036 this._data.media[0]?.alt || this._data?.title, 2037 { lang: this._data.media[0]?.lang} 2038 ); 2039 } else { 2040 if (this.fallbackpicture) { 2041 picture = `<picture><img src="${this.fallbackpicture}" alt="Fallback Image"></picture>`; 2042 } 2043 } 2044 2045 // link picture? 2046 2047 if (!this.linkelement && picture) { 2048 picture = `<a class="href" href="${ 2049 this.objectType === "event" ? pagename + "#" + dateString : pagename 2050 }" ${target}>${picture}</a>`; 2051 } 2052 2053 // title 2054 2055 let title = this._data.title 2056 ? `<p class="title ${ 2057 this.variant === "compact" ? `normal-text-bold` : `large-text-bold` 2058 }">${this._data.title}</p>` 2059 : ``; 2060 2061 // link title? 2062 2063 if (!this.linkelement && title) { 2064 title = `<a class="href" href="${ 2065 this.objectType === "event" ? pagename + "#" + dateString : pagename 2066 }" ${target}>${title}</a>`; 2067 } 2068 2069 // opening state 2070 2071 let state = ``; 2072 2073 if (this._data.statusType) { 2074 let label = ``; 2075 2076 switch (this._data.statusType) { 2077 case "open": 2078 label = this._CONSTANTS.OPEN; 2079 state = "open"; 2080 break; 2081 2082 case "closed": 2083 label = this._CONSTANTS.CLOSED; 2084 state = "closed"; 2085 break; 2086 2087 case "blocked": 2088 label = this._CONSTANTS.BLOCKED; 2089 state = "blocked"; 2090 break; 2091 2092 case "partiallyopen": 2093 label = this._CONSTANTS.PARTIALLYOPEN; 2094 state = "partiallyopen"; 2095 break; 2096 2097 case "inpreparation": 2098 label = this._CONSTANTS.INPREPARATION; 2099 state = "inpreparation"; 2100 break; 2101 2102 case "underconstruction": 2103 label = this._CONSTANTS.UNDERCONSTRUCTION; 2104 state = "underconstruction"; 2105 break; 2106 2107 case "disturbance": 2108 label = this._CONSTANTS.DISTURBANCE; 2109 state = "disturbance"; 2110 break; 2111 } 2112 2113 if (label !== "") { 2114 state = `<span class="state state-${state} small-text-bold">${label}</span>`; 2115 } 2116 } 2117 2118 // teasertext 2119 2120 let description = ``; 2121 2122 if (this._data.description) { 2123 if (this.variant === "compact") { 2124 description = `<div class="teasertext small-text">${this._data.description}</div>`; 2125 } else { 2126 description = `<div class="teasertext normal-text">${this._data.description}</div>`; 2127 } 2128 } 2129 2130 // tag 2131 2132 let tag = ``; 2133 2134 if (this._data.difficultyLevel) { 2135 let level = ``; 2136 let levelNum = 0; 2137 2138 switch (this._data.difficultyLevel) { 2139 case "easy": 2140 level = this._CONSTANTS.EASY; 2141 levelNum = 1; 2142 break; 2143 2144 case "medium": 2145 level = this._CONSTANTS.MODERATE; 2146 levelNum = 2; 2147 break; 2148 2149 case "hard": 2150 level = this._CONSTANTS.DIFFICULT; 2151 levelNum = 3; 2152 break; 2153 } 2154 2155 if (level !== "") { 2156 tag = `<p class="tag level${levelNum} caption-text-bold effect-border-radius">${level}</p>`; 2157 } 2158 } 2159 2160 // categories 2161 2162 let categories = this._data.categories 2163 ? `<p class="categories small-text">${this._data.categories.join(", ")}</p>` 2164 : ``; 2165 2166 // duration 2167 2168 let tmpDurationValue = parseInt(this._data.duration); 2169 let tmpDurationString = ``; 2170 2171 if (tmpDurationValue > 0) { 2172 let hours = Math.floor(tmpDurationValue / 60); 2173 let minutes = tmpDurationValue % 60; 2174 tmpDurationString = `${mwUtility.leadingZero(hours, 2)}:${mwUtility.leadingZero( 2175 minutes, 2176 2 2177 )} ${this._CONSTANTS.PREFIXH}`; 2178 } 2179 2180 let duration = tmpDurationString 2181 ? `<p class="duration tour-data small-text"><mw-core-icon size="m" name="t"></mw-core-icon>${tmpDurationString}</p>` 2182 : ``; 2183 2184 // distance 2185 2186 let tmpDistanceValue = parseInt(this._data.distance); 2187 let tmpDistanceString = ``; 2188 2189 if (tmpDistanceValue >= 1000) { 2190 tmpDistanceString = tmpDistanceValue / 1000; 2191 tmpDistanceString = `${tmpDistanceString.toFixed(2).toString().replace(".", ",")} ${ 2192 this._CONSTANTS.PREFIXKM 2193 }`; 2194 } else if (tmpDistanceValue > 0) { 2195 tmpDistanceString = `${tmpDistanceValue.toString().replace(".", ",")} ${ 2196 this._CONSTANTS.PREFIXM 2197 }`; 2198 } 2199 2200 let distance = tmpDistanceString 2201 ? `<p class="distance tour-data small-text"> 2202 <mw-core-icon size="m" name="l"></mw-core-icon> 2203 ${tmpDistanceString} 2204 </p>` 2205 : ``; 2206 2207 // uphill 2208
2209 let tmpUphillValue = parseInt(this._data.uphill); 2210 let tmpUphillString = ``; 2211 2212 if (tmpUphillValue > 0) { 2213 tmpUphillString = `${Math.ceil(tmpUphillValue).toLocaleString()} ${ 2214 this._CONSTANTS.PREFIXM 2215 }`; 2216 } 2217 2218 let uphill = tmpUphillString 2219 ? `<p class="uphill tour-data small-text"><mw-core-icon size="m" name="*"></mw-core-icon>${tmpUphillString}</p>` 2220 : ``; 2221 2222 // bookmark 2223 2224 let bookmark = 2225 this.bookmark && this.variant !== "compact" 2226 ? `<button aria-label="${document.documentElement.lang === "de" ? "merken" : "save"}" class="bookmark" type="button"><mw-core-icon size="m" name="${this.checkBookmark( 2227 "heart", 2228 "heartselected" 2229 )}" aria-pressed="false"></mw-core-icon></button>` 2230 : ``; 2231 2232 // button 2233 2234 let button = ``; 2235 2236 if (this.button !== true && this.button !== null) { 2237 if (this.variant === "compact") { 2238 button = ` 2239 <p class="button"> 2240 <mw-core-button nofocus tertiary nolabel icon="3" small iconsize="s"></mw-core-button> 2241 </p>`; 2242 } else { 2243 button = ` 2244 <p class="button"> 2245 <mw-core-button nofocus primary label="${this.button}" labelclass="primary-link"></mw-core-button> 2246 </p> 2247 `; 2248 } 2249 } 2250 2251 let html = ``; 2252 2253 if (this.variant === "inline") { 2254 html = ` 2255 ${ 2256 this.linkelement 2257 ? `<a class="href" href="${ 2258 this.objectType === "event" ? pagename + "#" + dateString : pagename 2259 }" ${target}>` 2260 : `` 2261 } 2262 <div class="teaser"> 2263 ${tag} 2264 <div class="image"> 2265 ${picture} 2266 <span class="teaser-frame" aria-hidden="true"></span> 2267 </div> 2268 <div class="main"> 2269 <div class="content"> 2270 ${title} 2271 ${bookmark} 2272 </div> 2273 </div> 2274 </div> 2275 ${this.linkelement ? `</a>` : ``} 2276 `; 2277 } else { 2278 html = ` 2279 ${ 2280 this.linkelement 2281 ? `<a class="href" href="${ 2282 this.objectType === "event" ? pagename + "#" + dateString : pagename 2283 }" ${target}>` 2284 : `` 2285 } 2286 <div class="teaser"> 2287 ${tag} 2288 <div class="image"> 2289 ${picture} 2290 <span class="teaser-frame" aria-hidden="true"></span> 2291 </div> 2292 <div class="main"> 2293 <div class="content"> 2294 ${title} 2295 ${categories} 2296 ${state} 2297 ${description} 2298 </div> 2299 <div class="bottom ${duration || distance || uphill ? `has-info` : ``}"> 2300 <div class="left">${duration + distance + uphill}</div> 2301 ${bookmark || button ? ` <div class="right">${bookmark + button}</div>` : ""} 2302 </div> 2303 </div> 2304 </div> 2305 ${this.linkelement ? `</a>` : ``} 2306 `; 2307 } 2308 2309 return html; 2310 } 2311 2312 layoutProvider() { 2313 // layout provider 2314 2315 // parse constants 2316 2317 this.parseConstants(); 2318 2319 // pagename 2320 2321 let pagename = `` 2322 2323 if (this?.objectType === "package") { 2324 if (this._data?.type !== "provider") { 2325 if (micadoWeb?.lang === "de") { 2326 pagename = `/de/hotel-unterkunft/spezial-angebote.html#/spezialangebote/SBG/${this._data.interfaceIdentifier}`; 2327 } else { 2328 pagename = `/en/hotel-accomodation/special-offers.html#/specialoffers/SBG/${this._data.interfaceIdentifier}`; 2329 } 2330 } else { 2331 pagename = this._data.pageName ? this._data.pageName : `#`; 2332 } 2333 } else { 2334 pagename = this._data.pageName ? this._data.pageName : `#`; 2335 2336 if (this.saleschannelid && this.saleschannelid != 4242) { 2337 pagename += `?salesChannelID=${this.saleschannelid}` 2338 } 2339 } 2340 2341 // target 2342 2343 let target = this._data.target ? `target="${this._data.target}"` : ``; 2344 2345 // teaserimage 2346 2347 let picture = ``; 2348 2349 // read rule 2350 // if this.mqmedia is null 2351 // try read mqmedia from data 2352 // for example relevant in bookmark 2353 2354 let mqMediaRule; 2355 2356 if (this.mqmedia) { 2357 mqMediaRule = this.mqmedia; 2358 } else if (this._data.mqmedia) { 2359 mqMediaRule = this._data.mqmedia; 2360 } 2361 2362 if (this._data.media && this._data.media.length > 0) { 2363 picture = mwUtility.htmlMediaPicture( 2364 this._data.media[0], 2365 mqMediaRule, 2366 this._data.media[0]?.alt || this._data?.title, 2367 { lang: this._data.media[0]?.lang} 2368 ); 2369 } else { 2370 if (this.fallbackpicture) { 2371 picture = `<picture><img src="${this.fallbackpicture}" alt="Fallback Image"></picture>`; 2372 } 2373 } 2374 2375 // link picture? 2376 2377 if (!this.linkelement && picture) { 2378 picture = `<a class="href" href="${ 2379 this.objectType === "event" ? pagename + "#" + dateString : pagename 2380 }" ${target}>${picture}</a>`; 2381 } 2382 2383 // title 2384 2385 let title = this._data.title 2386 ? `<p class="title ${ 2387 this.variant === "compact" ? `normal-text-bold` : `large-text-bold` 2388 }">${this._data.title}</p>` 2389 : ``; 2390 2391 // link title? 2392 2393 if (!this.linkelement && title) { 2394 title = `<a class="href" href="${ 2395 this.objectType === "event" ? pagename + "#" + dateString : pagename 2396 }" ${target}>${title}</a>`; 2397 } 2398 2399 // teasertext 2400 2401 let description = ``; 2402 2403 if (this._data.description) { 2404 if (this.variant === "compact") { 2405 description = `<div class="teasertext small-text">${this._data.description}</div>`; 2406 } else { 2407 description = `<div class="teasertext normal-text">${this._data.description}</div>`; 2408 } 2409 } 2410 2411 // marketinggroups 2412 2413 let marketinggroups = ``; 2414 2415 if (this._data.marketinggroups) { 2416 marketinggroups += `<div class="marketinggroups">`; 2417 2418 this._data.marketinggroups.forEach((item) => { 2419 marketinggroups += `<div class="logo" title="${item?.title}"><img src="${item?.media?.[0]?.filename}" alt="${item?.title}" aria-label="${item?.title}" /></div>`; 2420 }); 2421 2422 marketinggroups += `</div>`; 2423 } 2424 2425 // classification & town 2426 2427 let classificationAndTownArr = []; 2428 let classificationAndTown = ``; 2429 2430 if (this._data && Array.isArray(this._data.categories)) { 2431 classificationAndTownArr.push(this._data.categories.join(", ")); 2432 } 2433 2434 if (this._data && this._data.classificationTitle) { 2435 classificationAndTownArr.push(this._data.classificationTitle); 2436 } 2437 2438 if (this._data && this._data.address && this._data.address.town) { 2439 classificationAndTownArr.push(this._data.address.town); 2440 } 2441 2442 if (classificationAndTownArr.length > 0) { 2443 classificationAndTown = `<div class="text small-text">${classificationAndTownArr.join( 2444 ", " 2445 )}</div>`; 2446 } 2447 2448 // bookmark 2449 2450 let bookmark = 2451 this.bookmark && this.variant !== "compact" 2452 ? `<button aria-label="${document.documentElement.lang === "de" ? "merken" : "save"}" class="bookmark" type="button"><mw-core-icon size="m" name="${this.checkBookmark( 2453 "heart", 2454 "heartselected" 2455 )}" aria-pressed="false"></mw-core-icon></button>` 2456 : ``; 2457 2458 // button 2459 2460 let button = ``; 2461 2462 if (this.button !== true && this.button !== null) { 2463 if (this.variant === "compact") { 2464 button = ` 2465 <p class="button"> 2466 <mw-core-button nofocus tertiary nolabel icon="3" small iconsize="s"></mw-core-button> 2467 </p>`; 2468 } else { 2469 button = ` 2470 <p class="button"> 2471 <mw-core-button nofocus primary label="${this.button}" labelclass="primary-link"></mw-core-button> 2472 </p> 2473 `; 2474 } 2475 } 2476 2477 // link button? 2478 2479 if (!this.linkelement && button) { 2480 button = `<a class="href" href="${ 2481 this.objectType === "event" ? pagename + "#" + dateString : pagename 2482 }" ${target}>${button}</a>`; 2483 } 2484 2485 // rating 2486 2487 const calculateAverageByTotalValue = (average, total) => { 2488 let value = (total * average) / 100; 2489 2490 return Math.round(value * 10) / 10; 2491 }; 2492 2493 let rating = ``; 2494 let tag = ``; 2495 2496 if ( 2497 this._data.ratingAverage && 2498 parseInt(this._data.ratingAverage) > 0 && 2499 parseInt(this._data.ratingCount) > 0 2500 ) { 2501 rating = ` 2502 <div class="rating"> 2503 <p class="rating-value-wrapper"> 2504 <span class="rating-value effect-border-radius large-text-bold"> 2505 ${calculateAverageByTotalValue(this._data.ratingAverage, 5)} 2506 </span> /5</p> 2507 <p class="rating-summ small-text"> 2508 ${ 2509 this._data.ratingCount === 1 2510 ? ` 2511 ${this._data.ratingCount} ${this._CONSTANTS.RATING}` 2512 : ` 2513 ${this._data.ratingCount} ${this._CONSTANTS.RATINGS}` 2514 } 2515 </p> 2516 </div> 2517 `; 2518 } 2519 2520 // tag 2521 2522 if (this._data && this._data.price && this._data.price.isBestPrice) { 2523 tag = this._CONSTANTS.BESTPRICE; 2524 } 2525 2526 // price 2527 2528 let price = ``; 2529 2530 if (this.preloadprices) { 2531 if (!this._data.price) { 2532 this._data.price = { 2533 from: -1, 2534 addition: "perperson" 2535 }; 2536 } 2537 } 2538 2539 if (this._data.price && !isNaN(this._data.price.from)) { 2540 let label = this.priceLabel(); 2541 let priceValue = this.priceValue(); 2542 2543 const brandColor = getComputedStyle(document.documentElement).getPropertyValue( 2544 "--mw-core-color-brand1" 2545 ); 2546 2547 const preloader = `
2548 <span class="preloader"> 2549 <?xml version="1.0" encoding="utf-8"?> 2550 <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="24px" height="24px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid"> 2551 <circle cx="50" cy="50" fill="none" stroke="${brandColor}" stroke-width="10" r="35" stroke-dasharray="164.93361431346415 56.97787143782138"> 2552 <animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform> 2553 </circle> 2554 </svg> 2555 </span> 2556 `; 2557 2558 price = ` 2559 <button class="provider-price" type="button" aria-haspopup="dialog" aria-controls="modal-cancellation-details" title="${document.documentElement.lang === "de" ? "Weitere Preisinformationen anzeigen" : "Further price details"}"> 2560 <p class="price-value large-text-bold">${ 2561 this._data.price.from > -1 ? `${priceValue}` : `${preloader}` 2562 }</p> 2563 <p class="price-label small-text"> 2564 ${this._data.price.from > -1 ? `${label}` : ``} 2565 </p> 2566 </button> 2567 `; 2568 } 2569 2570 let html = ``; 2571 2572 if (this.variant === "inline") { 2573 html = ` 2574 ${ 2575 this.linkelement 2576 ? `<a class="href" href="${ 2577 this.objectType === "event" ? pagename + "#" + dateString : pagename 2578 }" ${target}>` 2579 : `` 2580 } 2581 <div class="teaser"> 2582 <div class="image"> 2583 ${picture} 2584 <span class="teaser-frame" aria-hidden="true"></span> 2585 </div> 2586 <div class="main"> 2587 <div class="content"> 2588 ${title} 2589 ${bookmark} 2590 </div> 2591 </div> 2592 </div> 2593 ${this.linkelement ? `</a>` : ``} 2594 `; 2595 } else { 2596 html = ` 2597 ${ 2598 this.linkelement 2599 ? `<a class="href" href="${ 2600 this.objectType === "event" ? pagename + "#" + dateString : pagename 2601 }" ${target}>` 2602 : `` 2603 } 2604 <div class="teaser"> 2605 <p class="tag caption-text-bold effect-border-radius${!tag ? ` no-tag` : ``}">${tag}</p> 2606 <div class="image"> 2607 ${picture} 2608 <span class="teaser-frame" aria-hidden="true"></span> 2609 </div> 2610 <div class="main"> 2611 <div class="content"> 2612 <div class="provider"> 2613 ${title} 2614 ${classificationAndTown} 2615 ${description} 2616 </div> 2617 ${rating} 2618 <div class="center"> 2619 ${marketinggroups} 2620 </div> 2621 </div> 2622 <div class="bottom ${price ? `has-info` : ``}"> 2623 <div class="left"> 2624 ${price} 2625 <p class="availability no-availability normal-text-bold"></p> 2626 </div> 2627 ${bookmark || button ? ` <div class="right">${bookmark + button}</div>` : ""} 2628 </div> 2629 </div> 2630 </div> 2631 ${this.linkelement ? `</a>` : ``} 2632 `; 2633 } 2634 2635 return html; 2636 } 2637 2638 listNextOpeningDays() { 2639 // list next openingdays 2640 2641 let htmlop = ``; 2642 2643 let days = []; 2644 2645 for (let ot of this._data.openingTimes) { 2646 let from = new Date(ot.from); 2647 let to = new Date(ot.to); 2648 let id = from.getDate() + from.getMonth() + from.getFullYear(); 2649 2650 // find pos in array 2651 2652 let result = days 2653 .map(function (e) { 2654 if (e[0]) { 2655 return e[0].id; 2656 } else { 2657 return -1; 2658 } 2659 }) 2660 .indexOf(id); 2661 2662 // append new array or to index 2663 2664 if (result >= 0) { 2665 days[result].push({ 2666 id: id, 2667 from: from, 2668 to: to 2669 }); 2670 } else { 2671 days.push([ 2672 { 2673 id: id, 2674 from: from, 2675 to: to 2676 } 2677 ]); 2678 } 2679 } 2680 2681 for (let day of days) { 2682 let htmlDay = ``; 2683 2684 if (day) { 2685 // writes single day line 2686 2687 htmlDay += `<div class="day small-text">`; 2688 2689 if (day.length === 1) { 2690 let state = `${document.documentElement.lang === "en" ? mwUtility.formatDateToEnglishTime(day[0].from) : mwUtility.formatDateToTime( 2691 day[0].from 2692 )} - ${document.documentElement.lang === "en" ? mwUtility.formatDateToEnglishTime(day[0].to) : mwUtility.formatDateToTime(day[0].to)}`; 2693 2694 // check opened 24 hours 2695 2696 if (Math.abs(day[0].to - day[0].from) / 36e5 >= 24) { 2697 state = this._CONSTANTS.OPENINGSTATE6; 2698 } 2699 2700 // single opening time per day 2701 2702 htmlDay += `<span class="d">${this._CONSTANTS.DAYS[day[0].from.getDay()]}</span> 2703 <span class="t">${state}</span>`; 2704 } else if (day.length > 1) { 2705 // multiple opening times per day 2706 2707 let htmlTimes = ``;
2708 let counter = 0; 2709 2710 for (let times of day) { 2711 if (counter > 0) { 2712 htmlTimes += `, `; 2713 } 2714 2715 htmlTimes += `${document.documentElement.lang === "en" ? mwUtility.formatDateToEnglishTime(times.from) : mwUtility.formatDateToTime( 2716 times.from 2717 )} - ${document.documentElement.lang === "en" ? mwUtility.formatDateToEnglishTime(times.to) : mwUtility.formatDateToTime(times.to)}`; 2718 2719 counter++; 2720 } 2721 2722 htmlDay += `<span class="d">${this._CONSTANTS.DAYS[day[0].from.getDay()]}</span> 2723 <span class="t"> 2724 ${htmlTimes} 2725 </span> 2726 `; 2727 } 2728 2729 htmlDay += `</div>`; 2730 } 2731 2732 htmlop += htmlDay; 2733 } 2734 2735 return htmlop; 2736 } 2737 2738 checkCurrentOpening() { 2739 // find current date 2740 2741 let currentOrNextOpeningDate = this.findCurrentOpening(); 2742 2743 // detect current opening state 2744 2745 if (currentOrNextOpeningDate) { 2746 let openingTimeFrom = new Date(currentOrNextOpeningDate.from); 2747 let openingTimeTo = new Date(currentOrNextOpeningDate.to); 2748 2749 if (!openingTimeFrom.getTime() || !openingTimeTo.getTime()) { 2750 return ""; 2751 } 2752 2753 switch (this.detectOpeningState(openingTimeFrom, openingTimeTo)) { 2754 case 0: 2755 return ""; 2756 2757 case 1: 2758 // closing in max 1 hour 2759 2760 return ` 2761 <p class="current-title small-text" data-state-1> 2762 <span class="state-medium small-text-bold"> 2763 ${this._CONSTANTS.OPENINGSTATE1} 2764 </span> - ${document.documentElement.lang === "en" ? mwUtility.formatDateToEnglishTime(openingTimeTo) : mwUtility.formatDateToTime(openingTimeTo)} ${this._CONSTANTS.HOURS} 2765 </p> 2766 `; 2767 2768 case 2: 2769 // opening at (same day) 2770 2771 return ` 2772 <p class="current-title small-text" data-state-2> 2773 <span class="state-medium small-text-bold"> 2774 ${this._CONSTANTS.OPENINGSTATE2} 2775 </span> ${document.documentElement.lang === "en" ? mwUtility.formatDateToEnglishTime(openingTimeFrom) : mwUtility.formatDateToTime(openingTimeFrom)} ${this._CONSTANTS.HOURS} 2776 </p> 2777 `; 2778 2779 case 3: 2780 // opened 2781 2782 return ` 2783 <p class="current-title small-text" data-state-3> 2784 <span class="state-good small-text-bold"> 2785 ${this._CONSTANTS.OPENINGSTATE3} 2786 </span>${document.documentElement.lang === "en" ? mwUtility.formatDateToEnglishTime(openingTimeTo) : mwUtility.formatDateToTime(openingTimeTo)} ${this._CONSTANTS.HOURS} 2787 </p> 2788 `; 2789 2790 case 4: 2791 // closed - opens at 2792 2793 return ` 2794 <p class="current-title small-text"> 2795 <span class="state-bad small-text-bold" data-state-4> 2796 ${this._CONSTANTS.OPENINGSTATE4} 2797 </span> ${mwUtility.formatDateToString(openingTimeFrom)} ${document.documentElement.lang === "en" ? mwUtility.formatDateToEnglishTime(openingTimeFrom) : mwUtility.formatDateToTime( 2798 openingTimeFrom 2799 )} ${this._CONSTANTS.HOURS} 2800 </p> 2801 `; 2802 2803 case 5: 2804 // opens tomorrow 2805 2806 return ` 2807 <p class="current-title small-text" data-state-5> 2808 <span class="state-bad small-text-bold"> 2809 ${this._CONSTANTS.OPENINGSTATE5} 2810 </span> ${document.documentElement.lang === "en" ? mwUtility.formatDateToEnglishTime(openingTimeFrom) : mwUtility.formatDateToTime(openingTimeFrom)} ${this._CONSTANTS.HOURS} 2811 </p> 2812 `; 2813 2814 case 6: 2815 // opened 24 hours 2816 2817 return ` 2818 <p class="current-title small-text" data-state-6> 2819 <span class="state-good small-text-bold"> 2820 ${this._CONSTANTS.OPENINGSTATE6} 2821 </span> 2822 </p> 2823 `; 2824 } 2825 } 2826 2827 return ``; 2828 } 2829 2830 findCurrentOpening() { 2831 // find current openingtime 2832 2833 let currentDate = new Date(); 2834 let strike = ``; 2835 2836 for (let item of this._data.openingTimes) { 2837 let tmpStart = new Date(item.from); 2838 let tmpEnd = new Date(item.to); 2839 2840 if (currentDate > tmpStart && currentDate < tmpEnd) { 2841 strike = item; 2842 break; 2843 } 2844 } 2845 2846 // check if first openingTime is in future 2847 2848 if (strike === "") { 2849 for (let item of this._data.openingTimes) { 2850 let currentTime = new Date(); 2851 let dateStart = new Date(item.from); 2852 2853 if (currentTime < dateStart) { 2854 strike = item; 2855 break; 2856 } 2857 } 2858 } 2859 2860 return strike; 2861 } 2862 2863 detectOpeningState(openingTimeFrom, openingTimeTo) { 2864 let currentTime = new Date(); 2865 2866 if (!openingTimeFrom.getTime() || !openingTimeTo.getTime()) { 2867 return 0; 2868 } 2869 2870 // check closing in max 1 hour 2871 2872 if (currentTime <= openingTimeTo && Math.abs(openingTimeTo - currentTime) / 36e5 < 1) { 2873 return 1; 2874 } 2875 2876 // check opening at (same day) 2877 2878 if ( 2879 openingTimeFrom > currentTime && 2880 Math.abs(openingTimeFrom - currentTime) / 36e5 < 24 && 2881 currentTime.getDate() === openingTimeFrom.getDate() 2882 ) { 2883 return 2; 2884 } 2885 2886 // check opened 24 hours 2887 2888 if ( 2889 currentTime.getDate() === openingTimeFrom.getDate() && 2890 currentTime.getMonth() === openingTimeFrom.getMonth() && 2891 currentTime.getFullYear() === openingTimeFrom.getFullYear() && 2892 Math.abs(openingTimeFrom - openingTimeTo) / 36e5 === 24 2893 ) { 2894 return 6; 2895 } 2896 2897 // check opened 2898 2899 if ( 2900 currentTime.getTime() >= openingTimeFrom.getTime() && 2901 currentTime.getTime() <= openingTimeTo.getTime() 2902 ) { 2903 return 3; 2904 } 2905 2906 // check opens tomorrow 2907 2908 let tomorrow = new Date(); 2909 tomorrow.setDate(tomorrow.getDate() + 1); 2910 tomorrow.setHours(0, 0, 0, 0); 2911 2912 if (Math.abs(tomorrow - openingTimeFrom) / 36e5 < 24) { 2913 return 5; 2914 } 2915 2916 // return closed - opens at 2917 2918 return 4; 2919 } 2920 2921 checkNextOpeningDaySmallerThen(openingTimes, days) { 2922 let today = new Date(); 2923 2924 if (openingTimes.length > 0) { 2925 let firstFromDate = new Date(openingTimes[0].from); 2926 2927 let diffTime = Math.abs(firstFromDate - today); 2928 let diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); 2929 2930 if (diffDays > days) { 2931 return false; 2932 } 2933 } 2934 2935 return true; 2936 } 2937 2938 checkBookmark(iconInactive, iconActive) { 2939 // check if bookmark active/inactive 2940 2941 if (mwBookmark.entryIsInStorage(this._data)) { 2942 // is bookmarked 2943 2944 return iconActive; 2945 } else { 2946 // is not bookmarked 2947 2948 return iconInactive; 2949 } 2950 } 2951 2952 priceLabel() { 2953 let label = ""; 2954 2955 if (this._data.price.addition) { 2956 if (this.objectType === "provider") { 2957 // provider 2958 2959 if (this._data.price.addition && this._data.price.productType) { 2960 if ( 2961 this._data.price.addition === "perunit" && 2962 this._data.price.productType === "apartment" 2963 ) { 2964 if (this._data.price.nights && this._data.price.nights > 1) { 2965 label = `${this._CONSTANTS.PER} ${this._CONSTANTS.UNIT}/${this._data.price.nights} ${this._CONSTANTS.NIGHTS}`; 2966 } else { 2967 label = this._CONSTANTS.PRICEPERUNIT; 2968 } 2969 } else if ( 2970 this._data.price.addition === "perunit" && 2971 this._data.price.productType === "hotelroom" 2972 ) { 2973 if (this._data.price.nights && this._data.price.nights > 1) { 2974 label = `${this._CONSTANTS.PER} ${this._CONSTANTS.ROOM}/${this._data.price.nights} ${this._CONSTANTS.NIGHTS}`; 2975 } else { 2976 label = this._CONSTANTS.PRICEPERROOM; 2977 } 2978 } else if (this._data.price.addition === "total") { 2979 if (this._data.price.nights && this._data.price.nights > 1) { 2980 label = `${this._CONSTANTS.PRICETOTAL}/${this._data.price.nights} ${this._CONSTANTS.NIGHTS}`; 2981 } else { 2982 label = this._CONSTANTS.PRICETOTAL; 2983 } 2984 } else { 2985 label = this._CONSTANTS.PRICEPERPERSON; 2986 } 2987 } 2988 } else { 2989 // package 2990 2991 switch (this._data.price.addition) { 2992 case "perunit": 2993 if (this._data.price.nights) { 2994 if (this._data.price.nights === "1") { 2995 label = `${this._CONSTANTS.PRICEFOR} ${this._data.price.nights} ${this._CONSTANTS.PRICEFORNIGHTUNIT}`; 2996 } else { 2997 label = `${this._CONSTANTS.PRICEFOR} ${this._data.price.nights} ${this._CONSTANTS.PRICEFORNIGHTSUNIT}`; 2998 } 2999 } else { 3000 label = `${this._CONSTANTS.PRICEPERUNIT}`; 3001 } 3002 3003 break; 3004 3005 case "perperson": 3006 if (this._data.price.nights) { 3007 if (this._data.price.nights === "1") { 3008 label = `${this._CONSTANTS.PRICEFOR} ${this._data.price.nights} ${this._CONSTANTS.PRICEFORNIGHTPERSON}`; 3009 } else { 3010 label = `${this._CONSTANTS.PRICEFOR} ${this._data.price.nights} ${this._CONSTANTS.PRICEFORNIGHTSPERSON}`; 3011 } 3012 } else { 3013 label = `${this._CONSTANTS.PRICEPERPERSON}`; 3014 } 3015 3016 break; 3017 } 3018 } 3019 } 3020 3021 return label; 3022 } 3023 3024 priceValue() { 3025 let prefix = this._CONSTANTS.PRICEFROM; 3026 let currency = "â¬"; 3027 let price = this._data.price.from; 3028 3029 let formatedPrice = mwUtility.formatNumber(price); 3030 3031 return `${prefix} ${formatedPrice} ${currency}`; 3032 } 3033 3034 showPriceInfo() { 3035 let addition = []; 3036 let adults = ``; 3037 let children = ``; 3038 let nights = ``; 3039 3040 if (typeof this._data.price.adults === `number` && this._data.price.adults === 1) { 3041 adults = `${this._data.price.adults} ${this._CONSTANTS.ADULT}`; 3042 } else if (typeof this._data.price.adults === `number` && this._data.price.adults > 1) { 3043 adults = `${this._data.price.adults} ${this._CONSTANTS.ADULTS}`; 3044 } 3045 3046 if ( 3047 Array.isArray(this._data.price.childrenAges) && 3048 this._data.price.childrenAges.length === 1 3049 ) { 3050 children = `${this._data.price.childrenAges.length} ${this._CONSTANTS.CHILD}`; 3051 } else if ( 3052 Array.isArray(this._data.price.childrenAges) && 3053 this._data.price.childrenAges.length > 1 3054 ) { 3055 children = `${this._data.price.childrenAges.length} ${this._CONSTANTS.CHILDREN}`; 3056 } 3057 3058 if (this._data.price.dateFrom && this._data.price.dateTo) { 3059 const dateFrom = new Date(this._data.price.dateFrom);
3060 const dateTo = new Date(this._data.price.dateTo); 3061 3062 if (mwUtility.checkValidDate(dateFrom) && mwUtility.checkValidDate(dateTo)) { 3063 const dateDiff = (dateTo.getTime() - dateFrom.getTime()) / (1000 * 3600 * 24); 3064 nights = 3065 dateDiff > 1 3066 ? dateDiff + " " + this._CONSTANTS.NIGHTS 3067 : dateDiff + " " + this._CONSTANTS.NIGHT; 3068 } 3069 } 3070 3071 if (this._data.price.mealType) { 3072 addition.push(this._CONSTANTS.MEALTYPE[this._data.price.mealType.toUpperCase()]); 3073 } 3074 3075 if (adults) { 3076 addition.push(adults); 3077 } 3078 3079 if (children) { 3080 addition.push(children); 3081 } 3082 3083 if (nights) { 3084 addition.push(nights); 3085 } 3086 3087 const finalCleaning = 3088 this._data.price && this._data.price.finalCleaning 3089 ? ` 3090 <p class="sheet-price-info normal-text"> 3091 ${this._CONSTANTS.INCLUSIVE} ${mwUtility.formatNumber(this._data.price.finalCleaning)} ⬠${ 3092 this._CONSTANTS.FINALCLEANING 3093 } 3094 </p> 3095 ` 3096 : ``; 3097 3098 const content = ` 3099 <mw-core-actionsheet ok="OK"> 3100 ${finalCleaning} 3101 ${this.parseLocalTax()} 3102 <div class="cancellation">${this.parseCancellation()}</div> 3103 <style> 3104 .cancellation { 3105 margin: 16px 0 16px 0; 3106 } 3107 p.sheet-price-info { 3108 margin: 0; 3109 } 3110 </style> 3111 <template is="component-style"> 3112 <style> 3113 .actionsheet { 3114 padding: 4px 4px 0; 3115 } 3116 .inner { 3117 padding: 0 16px 90px; 3118 } 3119 3120 @media all and (min-width: 500px) { 3121 3122 .actionsheet { 3123 padding: 16px 16px 0; 3124 } 3125 .content { 3126 height: auto; 3127 max-width: 500px; 3128 } 3129 .inner { 3130 height: auto; 3131 padding: 0 32px 90px; 3132 } 3133 3134 } 3135 </style> 3136 </template> 3137 </mw-core-actionsheet> 3138 `; 3139 3140 // append actionsheet 3141 3142 document.body.insertAdjacentHTML(`beforeend`, content); 3143 } 3144 3145 parseLocalTax() { 3146 let html = ``; 3147 3148 if (this._data.price && this._data.price.visitorTax && this._data.price.visitorTax?.inclusive) { 3149 3150 html += `<p class="sheet-price-info local-tax normal-text"> 3151 ${ 3152 this._data.price.visitorTax?.inclusive === false 3153 ? this._CONSTANTS.EXCLUSIVE 3154 : this._CONSTANTS.INCLUSIVE 3155 } ${this._CONSTANTS.TOURISMTAX} ${this._CONSTANTS.PRICEOF} ${mwUtility.formatNumber( 3156 this._data.price.visitorTax?.price 3157 )} ⬠${ 3158 this._data.price.visitorTax?.addition === "perpersonnight" 3159 ? this._CONSTANTS.PRICEPERPERSON 3160 : "" 3161 } 3162 </p>`; 3163 } 3164 3165 // --- Aufgrund von Kundenwunsch, am 25.01.2024 - Ortstaxe fix hinterlegt --- // 3166 3167 /*html += `<p class="sheet-price-info local-tax normal-text"> 3168 ${this._CONSTANTS.EXCLUSIVE} ${this._CONSTANTS.LOCALTAX} ${mwUtility.formatNumber(2)} ⬠${this._CONSTANTS.PRICEPERPERSON} 3169 </p>`;*/ 3170 3171 /* if (this._data.price && this._data.price.visitorTax && !this._data.price.visitorTax?.inclusive) { 3172 3173 html += `<p class="sheet-price-info local-tax normal-text"> 3174 <br> 3175 ${document.documentElement.lang === "de" ? "Ortstaxe und Mobilitätsabgabe sind nicht im Preis enthalten und werden zusätzlich verrechnet: 3,20 ⬠pro Person und Nacht." : "Local tax and mobility fee are not included in the price and will be charged additionally: â¬3.20 per person per night."} 3176 </p>` 3177 3178 } */ 3179 3180 if (this._data?.price?.visitorTax?.description) { 3181 3182 html += `<p class="sheet-price-info local-tax normal-text"> 3183 ${this._data?.price?.visitorTax?.description} 3184 </p>`; 3185 3186 } 3187 3188 return html; 3189 } 3190 3191 parseCancellation() { 3192 if ( 3193 this._data && 3194 this._data.cancellationDetails && 3195 Array.isArray(this._data.cancellationDetails.items) 3196 ) { 3197 const items = this._data.cancellationDetails.items.map((item) => { 3198 let date = ``; 3199 if (item.dateFrom) { 3200 date = mwUtility.formatDateToString(new Date(item.dateFrom)); 3201 } 3202 return `<p class="sheet-price-info normal-text"> 3203 ${this._CONSTANTS.CANCELLATIONTO} ${date} 3204 <span class="normal-text-bold">${item.percentage}% - ${mwUtility.formatNumber( 3205 item.price 3206 )} â¬</span></p>`; 3207 }); 3208
3209 if (this._data.cancellationDetails.free && this._data.cancellationDetails.freeUntil) { 3210 const freeUntilDate = mwUtility.formatDateToString( 3211 new Date(this._data.cancellationDetails.freeUntil) 3212 ); 3213 const freeUntilText = ` 3214 <p class="sheet-price-info normal-text-bold"> 3215 ${this._CONSTANTS.CANCELLATIONFREEUNTIL} ${freeUntilDate} 3216 </p> 3217 `; 3218 items.unshift(freeUntilText); 3219 } 3220 return items.join(""); 3221 } else { 3222 return ``; 3223 } 3224 } 3225} 3226 3227customElements.define("mw-core-teaser", mwCoreTeaser);
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.