PageSourceSearch

https://www.also.ch/ec/js/pegasos-core/1.2/pegasos_core.js?v=buildNumber

js also.ch collected 2026-10-03 19:50:37 UTC 41,441 bytes, 1,248 lines download raw bytes

1/**
2 * build a client configuration object if not yet available.
3 * The real values will be taken from first spirit.
4 */
5function queryOrBuildPegasosObject() {
6    if (typeof window.pegasos === 'undefined') {
7        window.pegasos = new Object();
8    }
9
10    return window.pegasos;
11}
12
13const webservicePrefix = pegasos.webservicePrefix + "/api/internal/cache-manager";
14
15//die pegasos-variable wird bereits in der Seitenvorlage gesetzt und steht somit IMMER zur Verfügung
16pegasos = queryOrBuildPegasosObject();
17
18pegasos.main_min_height = 550;			//Minimale Höhe, die nicht unterschritten werden soll
19pegasos.utils = utils;
20
21(function () {
22    var MSGS = new Translation();
23
24    var listener = {
25        notLoggedIn: function (id, data, response) {
26            logoutDueToInactivity();
27        }
28    };
29    HS.addListener("*", listener);
30
31    // always set the <code>pegasos.$mainObj</code> for basket binding
32    setMainObjectToPegasosForBasketBinding();
33}());
34
35/**
36 * Sets <code>pegasos.$mainObj</code> by evaluating the existing elements by their id's.
37 * <p>
38 * The value of <code>pegasos.$mainObj</code> is used in <code>basket-binding</code>!
39 * <p>
40 * The following order of id's is processed and used if found:
41 * <ul>
42 * <li><code>center</code>
43 * <li><code>content</code>
44 * <li><code>main</code>
45 * </ul>
46 */
47function setMainObjectToPegasosForBasketBinding() {
48    var $mainObj = $("#center");
49    if ($mainObj.length <= 0) {
50        $mainObj = $("#content");
51        if ($mainObj.length <= 0) {
52            $mainObj = $("#main");
53        }
54    }
55    pegasos.$mainObj = $mainObj;
56}
57
58// Global helper function used by hermes listener above and ASN.
59function logoutDueToInactivity() {
60    window.location.href = pegasos.actionPrefix + '/Logout.do?inactivity=true';
61}
62
63
64/*
65	Rückgabe des Webtrekk-Context
66	Zunächst Prüfen, ob ein individueller Context existiert.
67	Wenn nicht wird der Allgemeine der Seite genommen
68*/
69$.fn.getContext = function () {
70    var context = $(this).arg("context");
71
72    if (context == "") {
73        context = pegasos.context;
74    }
75
76    return context;
77};
78
79/*
80	Rückgabe des Webtrekk-AddedFromPage
81	Zunächst Prüfen, ob AddedFromPage existiert.
82	Wenn nicht wird der Context genommen
83*/
84$.fn.getAddedFromPage = function () {
85    var addedFromPage = $(this).arg("addedFromPage");
86
87    if (addedFromPage == "") {
88        if (typeof(pegasos.addedFromPage) === "undefined") {
89            addedFromPage = pegasos.context;
90        } else {
91            addedFromPage = pegasos.addedFromPage;
92        }
93    }
94
95    return addedFromPage;
96};
97
98
99//Nachladen einer Datei
100
101function getPage(filePath) {
102    var fileContent = $.ajax({
103        type: "GET",
104        async: false,
105        url: filePath,
106        cache: false
107    });
108
109
110    if (fileContent.status == 200) {
111        return fileContent.responseText;
112    }
113
114    return ("File not found: '" + filePath + "'");
115
116}
117
118/**
119 Texte verwalten
120 Verwendung:
121 Texte setzen z.B.
122 TEXT.asn = {
123				cancel: "Abbrechen"
124				,...
125			}
126 Text holen z.B.
127 TEXT.get("asn.cancel");    => "Abbrechen"
128 TEXT.get("gibts.nicht");  => "TEXT.gibts.nicht"
129
130 */
131if (window.TEXT === undefined) {
132    window.TEXT = {
133        get: function (key) {
134            var keys = key.split('.');
135            var obj = this;
136            for (var kx = 0; kx < keys.length; ++kx) {
137                obj = obj[keys[kx]];
138                if (obj === undefined) {
139                    obj = "TEXT." + key;
140                    LOG.warn("Not defined: " + obj);
141                    break;
142                }
143            }
144            return obj;
145        }
146    };
147}
148
149/**
150 From: http://ejohn.org/blog/simple-javascript-inheritance/
151 Minor mod's by
152 @author  UT, Actebis
153 */
154(function () {
155    var initializing = false, fnTest = /xyz/.test(function () {
156        xyz;
157    }) ? /\b_super\b/ : /.*/;
158    // The base Class implementation (does nothing)
159    this.Class = function () {
160    };
161
162    // Create a new Class that inherits from this class
163    Class.extend = function (prop) {
164        var _super = this.prototype;
165
166        // Instantiate a base class (but only create the instance,
167        // don't run the init constructor)
168        initializing = true;
169        var prototype = new this();
170        initializing = false;
171
172        // Copy the properties over onto the new prototype
173        for (var name in prop) {
174            // Check if we're overwriting an existing function
175            prototype[name] = typeof prop[name] == "function" &&
176            typeof _super[name] == "function" && fnTest.test(prop[name]) ?
177                (function (name, fn) {
178                    return function () {
179                        var tmp = this._super;
180
181                        try {
182                            // Add a new ._super() method that is the same method
183                            // but on the super-class
184                            this._super = _super[name];
185
186                            // The method only need to be bound temporarily, so we
187                            // remove it when we're done executing
188                            var ret = fn.apply(this, arguments);
189                        }
190                        finally {
191                            this._super = tmp;
192                        }
193
194                        return ret;
195                    };
196                })(name, prop[name]) :
197                prop[name];
198        }
199
200        // The dummy class constructor
201        function Class() {
202            var self = this;
203            // All construction is actually done in the init method
204            if (!initializing && this.init)
205                this.init.apply(this, arguments);
206        }
207
208        // Populate our constructed prototype object
209        Class.prototype = prototype;
210
211        // Enforce the constructor to be what we expect
212        Class.constructor = Class;
213        // And make this class extendable
214        Class.extend = arguments.callee;
215        return Class;
216    };
217})();
218
219/* Setzt für eine Gruppe von Objekten eine Einheitliche Höhe, ausgehend von dem Objekt mit der Größten Höhe */
220function equalHeight(group) {
221    var tallest = 0;
222
223    if (group != undefined && group.length > 1) {
224        for (var i = 0; i < group.length; i++) {
225            var thisHeight = $(group[i]).height();
226            if (thisHeight > tallest) {
227                tallest = thisHeight;
228            }
229        }
230    }
231
232    if (tallest > 0) {
233        group.height(tallest);
234    }
235}
236
237
238/**
239 Base64 Codec
240 http://www.webtoolkit.info/javascript-base64.html
241 UT, Actebis modified
242 */
243
244window.Base64Codec = {
245
246    _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
247
248    // public method for encoding
249    encode: function (input) {
250        var out = "";
251        var c1, c2, c3, e1, e2, e3, e4;
252        var i = 0;
253
254        input = this._utf8_encode(input);
255
256        while (i < input.length) {
257
258            c1 = input.charCodeAt(i++);
259            c2 = input.charCodeAt(i++);
260            c3 = input.charCodeAt(i++);
261
262            e1 = c1 >> 2;
263            e2 = ((c1 & 3) << 4) | (c2 >> 4);
264            e3 = ((c2 & 15) << 2) | (c3 >> 6);
265            e4 = c3 & 63;
266
267            if (isNaN(c2)) {
268                e3 = e4 = 64;
269            } else if (isNaN(c3)) {
270                e4 = 64;
271            }
272
273            var k = this._keyStr;
274            out = out + k.charAt(e1) + k.charAt(e2) + k.charAt(e3) + k.charAt(e4);
275        }
276
277        return out;
278    },
279
280    // public method for decoding
281    decode: function (inp) {
282        var out = "";
283        var k1, k2, k3;
284        var e1, e2, e3, e4;
285        var i = 0;
286        var k = this._keyStr;
287
288        inp = inp.replace(/[^A-Za-z0-9\+\/\=]/g, "");
289
290        while (i < inp.length) {
291            e1 = k.indexOf(inp.charAt(i++));
292            e2 = k.indexOf(inp.charAt(i++));
293            e3 = k.indexOf(inp.charAt(i++));
294            e4 = k.indexOf(inp.charAt(i++));
295
296            k1 = (e1 << 2) | (e2 >> 4);
297            k2 = ((e2 & 15) << 4) | (e3 >> 2);
298            k3 = ((e3 & 3) << 6) | e4;
299
300            out += String.fromCharCode(k1);
301
302            if (e3 != 64) out += String.fromCharCode(k2);
303            if (e4 != 64) out += String.fromCharCode(k3);
304        }
305
306        out = this._utf8_decode(out);
307        return out;
308    },
309
310    // private method for UTF-8 encoding
311    _utf8_encode: function (string) {
312        string = string.replace(/\r\n/g, "\n");
313        var utf = "";
314
315        for (var n = 0; n < string.length; n++) {
316
317            var c = string.charCodeAt(n);
318
319            if (c < 128) {
320                utf += String.fromCharCode(c);
321            }
322            else if ((c > 127) && (c < 2048)) {
323                utf += String.fromCharCode((c >> 6) | 192);
324                utf += String.fromCharCode((c & 63) | 128);
325            }
326            else {
327                utf += String.fromCharCode((c >> 12) | 224);
328                utf += String.fromCharCode(((c >> 6) & 63) | 128);
329                utf += String.fromCharCode((c & 63) | 128);
330            }
331        }
332        return utf;
333    },
334
335    // private method for UTF-8 decoding
336    _utf8_decode: function (utf) {
337        var s = "";
338        var i = 0;
339        var c = c1 = c2 = 0;
340
341        while (i < utf.length) {
342
343            c = utf.charCodeAt(i);
344
345            if (c < 128) {
346                s += String.fromCharCode(c);
347                i++;
348            }
349            else if ((c > 191) && (c < 224)) {
350                c2 = utf.charCodeAt(i + 1);
351                s += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
352                i += 2;
353            }
354            else {
355                c2 = utf.charCodeAt(i + 1);
356                c3 = utf.charCodeAt(i + 2);
357                s += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
358                i += 3;
359            }
360        }
361        return s;
362    }
363}; // /Base64Codec
364
365function openSupportInformation() {
366
367    var MSGS = new Translation();
368
369    var buttonClose = MSGS.get('label.core.close');
370    var buttonCopyToClipboard = MSGS.get('label.core.support.information.to.clipboard');
371
372    var buttonArray = [
373        {
374            text: buttonClose, click: function () {
375                $(this).dialog("close");
376            }
377        },
378        {text: buttonCopyToClipboard, "class": 'js-supportInfoToClipboard'}
379    ];
380
381    Dialog.createAndShow($(".supportInformation"), "form", {
382        title: MSGS.get('label.systemError.supportInfo'),
383        minHeight: 320,
384        height: 480,
385        minWidth: 800,
386        width: 1024,
387        modal: false,
388        resizable: true,
389        draggable: true,
390        classes: {
391            "ui-dialog": "debuginfo"
392        },
393        buttons: buttonArray
394    });
395
396    PegasosBlock.unblockPage();
397}
398
399//Handelt es sich um eine Shop-Seite
400function isShopPage() {
401    if ($("#shop_logo").length > 0) {
402        return true;
403    }
404
405    return false;
406}
407
408/**
409 * Selects a range of characters. If 'start' and 'end' parameters are equal, or 'end' is left out, positions the caret before
410 * 'start'.
411 *
412 * @param start
413 *            index of the first selected character, inclusive
414 * @param end
415 *            index of the last selected character, exclusive. optional.
416 */
417$.fn.selectRange = function (start, end) {
418    return this.each(function () {
419        if (!end) end = start;
420        if (this.setSelectionRange) {
421            this.focus();
422            this.setSelectionRange(start, end);
423        } else if (this.createTextRange) {
424            var range = this.createTextRange();
425            range.collapse(true);
426            range.moveEnd('character', end);
427            range.moveStart('character', start);
428            range.select();
429        }
430    });
431};
432
433/** Helper to get the topmost parent window */
434function getRootWindow() {
435    var win = window;
436    var root = win;
437    if (isALightboxOpen()) { // If lightbox is open, we can go directly to it's parent
438        root = win.parent;
439    }
440    return root;
441}
442
443/**
444 *  @param dateInput, either a string like 2014-04-18T00:00:00+02:00, a JS date object
445 *         or a unix timestamp returned by a java webservice
446 *  @param type date, time, datetime
447 */
448function formatDateByType(dateInput, type) {
449
450    var formatedDate = "";
451
452    if (dateInput) {
453        var date;
454        if (dateInput instanceof Date) {
455            date = dateInput;
456        } else {
457            date = new Date(dateInput)
458        }
459
460        var format = pegasos.datepickerDateFormat;
461        switch (type) {
462            case "date":
463                formatedDate = formatDateByPattern(format, date);
464                break;
465            case "datetime":
466                formatedDate = formatDateByPattern(format, date);
467                hours = ('' + date.getHours()).padStart(2);
468                minutes = ('' + date.getMinutes()).padStart(2);
469                formatedDate = formatedDate + " " + hours + ":" + minutes;
470                break;
471            case "time":
472                hours = ('' + date.getHours()).padStart(2);
473                minutes = ('' + date.getMinutes()).padStart(2);
474                formatedDate = formatedDate + " " + hours + ":" + minutes;
475                break;
476            default:
477                console.log('This case is not implemented.')
478                break;
479        }
480    }
481    return formatedDate;
482}
483
484function PegasosCore() {
485
486    var self = this;
487
488    self.init = function () {
489        $("#showMessageKeysOn").click(function () {
490            var link = document.location.href;
491            document.location = self._buildLink(link, 'on', 'off', 'showMessageKeys');
492            return false;
493        });
494        $("#showMessageKeysOff").click(function () {
495            var link = document.location.href;
496            document.location = self._buildLink(link, 'off', 'on', 'showMessageKeys');
497            return false;
498        });
499        $("#showECDEVMessagesOn").click(function () {
500            var link = document.location.href;
501            document.location = self._buildLink(link, 'on', 'off', 'showECDEVMessages');
502            return false;
503        });
504        $("#showECDEVMessagesOff").click(function () {
505            var link = document.location.href;
506            document.location = self._buildLink(link, 'off', 'on', 'showECDEVMessages');
507            return false;
508        });
509
510        $(document).on("click",".js_actionTracking",function(event){
511            if(typeof(pegasos.tracking) != "undefined" && typeof(webtrekkV3) != "undefined") {
512                var trackingLinkId = undefined;
513                if (event.currentTarget){
514                    trackingLinkId = $(event.currentTarget).data("trackingLinkId");
515                }
516                if ((trackingLinkId === undefined || trackingLinkId.length === 0) && event.target){
517                    trackingLinkId = $(event.target).data("trackingLinkId");
518                }
519                if (trackingLinkId !== undefined && trackingLinkId.length > 0) {
520                    pegasosUtils.wtSendinfo_safe({linkId: trackingLinkId});
521                }
522            }
523        });
524
525        window.addEventListener("UsercentricsDataEvent", function (e) {
526            if (e.detail != null && (e.detail.event === "consent_status")) {
527                // Usercentrics V2
528                self.checkDeviceId();
529            } else if (e.data != null && (e.data.event === "consents_initialized" || e.data.event === "consents_changed_finished" || e.data.event === "all_consents_given_status")) {
530                // Usercentrics V1
531                self.checkDeviceId();
532            }
533        });
534    };
535
536    self._buildLink = function (link, newMode, oldMode, paramName) {
537
538        var queryStringPos = link.indexOf('?');
539        if (queryStringPos > -1) {
540
541            var queryString = link.substring(queryStringPos + 1, link.length);
542            link = link.substring(0, queryStringPos);
543
544            var namedAnchorIdx = link.indexOf("#");
545            if (namedAnchorIdx !== -1){
546                link = link.substring(0, namedAnchorIdx);
547            }
548
549            var temp = "";
550            var params = queryString.split('&');
551            for (var i = 0; i < params.length; i++) {
552                var param = params[i];
553                if (param.indexOf(paramName) === 0) {
554                    // ignore this parameter
555                    continue;
556                }
557                if (i > 0) {
558                    temp += "&";
559                }
560
561                temp += param;
562            }
563            queryString = temp;
564
565            if (queryString.length > 0) {
566                link += '?' + queryString + '&';
567            } else {
568                link += '?';
569            }
570        } else {
571            var namedAnchorIdx = link.indexOf("#");
572            if (namedAnchorIdx !== -1){
573                link = link.substring(0, namedAnchorIdx);
574            }
575
576            link += '?';
577        }
578
579        link += paramName + '=' + newMode;
580        return link;
581    };
582
583    self.checkDeviceId = function() {
584
585        if (!this.isLoggedIn()) {
586            return;
587        }
588
589        const ucDataLayerMissing = !(typeof(ucDataLayer) !== 'undefined' && Array.isArray(ucDataLayer) && ucDataLayer.length > 0);
590        if (ucDataLayerMissing) {
591            console.debug("Usercentrics not yet initialized");
592            return;
593        }
594
595        const cookieConsentUsercentrics = ucDataLayer[ucDataLayer.length - 1]["ALSO Trust"];
596
597        const key = "cookieConsent.deviceId." + pegasos.userId;
598        let cookieConsentSessionStorage = undefined;
599        const temp = sessionStorage.getItem(key);
600        if (typeof (temp) !== "undefined" && temp !== null && temp !== "undefined") {
601            try {
602                cookieConsentSessionStorage = JSON.parse(temp);
603            } catch (e) {
604                console.log(e);
605            }
606        }
607
608        if (cookieConsentSessionStorage == null || cookieConsentSessionStorage !== cookieConsentUsercentrics) {
609            if (cookieConsentUsercentrics) {
610                $.ajax({
611                    url: pegasos.webservicePrefix + "/security/device-id",
612                    method: "POST",
613                    contentType: "application/json",
614                    data: "{}"
615                }).done(function (data, textStatus, jqXHR) {
616                    console.debug("Device ID set");
617                }).fail(function(jqXHR, textStatus, errorThrown){
618                    console.error("Error: " + textStatus);
619                });
620            } else {
621                $.ajax({
622                    url: pegasos.webservicePrefix + "/security/device-id",
623                    method: "DELETE",
624                    data: "{}"
625                }).done(function (data, textStatus, jqXHR) {
626                    console.debug("Device ID deleted");
627                }).fail(function(jqXHR, textStatus, errorThrown){
628                    console.error("Error: " + textStatus);
629                });
630            }
631
632            sessionStorage.setItem(key, JSON.stringify(cookieConsentUsercentrics));
633        }
634    }
635
636    self.isLoggedIn = function () {
637        return window.pegasos
638            // userId present?
639            && window.pegasos.userId
640            // userId is numeric?
641            && /^\d+$/.test(window.pegasos.userId.trim());
642    }
643
644    self.init();
645}
646
647var pegasosCore = null;
648var $passwordExpire;
649
650$(document).ready(function () {
651    pegasosCore = new PegasosCore();
652    $passwordExpire = $('#daysPasswordExpireIn');
653
654    $passwordExpire
655        .off("click")
656        .on("click.passwordUpdate", "#gotoPasswordUpdate", gotoPasswordUpdate)
657        .on("click.dismissHint", "#dismissExpiryHint", dismissExpiryHint)
658    ;
659
660    var dismissDate = localStorage.getItem('pwdUpdateDismissed');
661
662    if(!equalDates(dismissDate, getToday())) {
663        $passwordExpire.show();
664    } else {
665        $passwordExpire.hide();
666    }
667
668    pegasosCore.checkDeviceId();
669});
670
671function gotoPasswordUpdate(){
672    $.ajax({
673        url: webservicePrefix + "/pwdnotify/one",
674        method: "GET"
675    }).done(function (data, textStatus, jqXHR) {
676        var env = "weblogin.also.com/auth";
677        var client = "pegasos-shop-" + window.pegasos.salesorgNo;
678
679        if(window.location.href.indexOf("pegdev.also.com") > -1 || window.location.href.indexOf("localhost") > -1){
680            env = "weblogin.also.com/auth-t3";
681            client = "pegasos-shop-q-" + window.pegasos.salesorgNo;
682        }
683        var locale = window.pegasos.locale;
684        locale = locale.substring(0, 2);
685
686        var redirecturl = window.location.href;
687        if(redirecturl.indexOf("?") !== -1){
688            redirecturl = redirecturl.substring(0, redirecturl.indexOf("?"));
689        }
690
691        var redirectUrl = "https://" + env + "/realms/also-customers/protocol/openid-connect/auth?client_id=" + client + "&kc_locale=" + locale + "&response_type=code&kc_action=UPDATE_PASSWORD&redirect_uri=" + redirecturl;
692
693        window.location.href = redirectUrl;
694    }).fail(defaultErrorFunction);
695}
696
697function dismissExpiryHint() {
698    localStorage.setItem('pwdUpdateDismissed', getToday());
699    $passwordExpire.hide();
700}
701
702function defaultErrorFunction(e) {
703    console.log("Error has occurred. Error message: " + e);
704}
705
706function getToday() {
707    var d = new Date();
708    return d.getFullYear() + "/" + (d.getMonth()+1) + "/" + d.getDate();
709}
710
711function equalDates(date1, date2) {
712    return date1 == date2;
713}
714
715//Using tracekit to parse stacktraces and send errors to server
716TraceKit.remoteFetching = false;//don't try to load JS on your own
717TraceKit.collectWindowErrors = false;//we're registering our own onError handler for window
718
719TraceKit.report.subscribe(function myLogger(errorReport, arg1, error){
720
721    if (typeof pegasosConfiguration === "undefined" || pegasosConfiguration == null || !pegasosConfiguration.enabled("pegasos.sentry.enabled.javascript")){
722        return;
723    }
724
725    let stacktrace = {"frames": []};
726
727    let allALSOCode = true;
728    let allTraceKitCode = true;
729
730    if (errorReport.stack) {
731        for (const element of errorReport.stack) {
732            var newFrame = {
733                "filename": element.url,
734                "lineno": element.line,
735                "colno": element.column,
736                "function": element.func
737            };
738            stacktrace.frames.push(newFrame);
739
740            if (newFrame.filename) {
741                if (newFrame.filename.toLowerCase().indexOf('also') === -1 && newFrame.filename.toLowerCase().indexOf('localhost') === -1) {
742                    allALSOCode = false;
743                }
744                if (newFrame.filename.toLowerCase().indexOf('tracekit') === -1) {
745                    allTraceKitCode = false;
746                }
747            }
748        }
749    }
750
751    //Don't report errors when they happen outside of also hosted code
752    //or if they happen only inside of TraceKit
753    if (!allALSOCode || allTraceKitCode){
754        return;
755    }
756
757    const sentryData = {
758            "logger":"javascript",
759            "platform":"javascript",
760            "request":{
761                "headers":{
762                    "User-Agent": navigator.userAgent,
763                    "Referer": document.referrer
764                },
765                "url": window.location.href
766            },
767            "exception":{
768                "type": error.type,
769                "value": error.message
770            },
771            "stacktrace": stacktrace,
772            "culprit": error.filename,
773            "message": error.message,
774            "tags":{
775                "UserId": window.pegasos ? window.pegasos.userId : "n/a",
776                "CustomerNo": window.pegasos ? window.pegasos.customerNo : "n/a",
777                "SalesorgNo": window.pegasos ? window.pegasos.salesorgNo : "n/a",
778                "Hostname": window.location.hostname
779            },
780            "extra":{
781                //This would be the place to add some extra data if required
782                //"someArbitraryKey": "someArbitraryValue"
783            },
784            "user":{
785                "id": window.pegasos ? window.pegasos.userId : "n/a"
786            }
787        };
788
789    $.ajax({
790        type: "POST",
791        url: pegasos.webservicePrefix + "/api/sentry",
792        dataType: "json",
793        contentType: "application/json",
794        data: JSON.stringify(sentryData)
795    });
796});
797
798
799
800window.addEventListener("error", function (event){
801
802    if (event.error && (typeof pegasosUtils != "undefined" && pegasosUtils != null)){
803        pegasosUtils.logToSentry(event.error, event.message, event.filename, event.type);
804    }
805
806   return false;
807});
808
809/* not dependent on documentReady like pegasosCore */
810var pegasosUtils = {
811
812    isDateHtml5Supported: function () {
813        var input = document.createElement('input');
814        var value = 'a';
815        input.setAttribute('type', 'date');
816        input.setAttribute('value', value);
817        return (input.value !== value);
818    },
819
820    getTimeString: function () {
821        var date = new Date();
822        var datestring = ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2) + ":" + ("0" + date.getSeconds()).slice(-2) + "." + ("00" + date.getMilliseconds()).slice(-3);
823        return datestring;
824    },
825
826    debug: function (message) {
827        if (pegasos && pegasos.showDebugInformation) {
828            console.debug(this.getTimeString() + " - " + message);
829        }
830    },
831
832    info: function (message) {
833        console.info(this.getTimeString() + " - " + message);
834    },
835
836    warn: function (message) {
837        console.warn(this.getTimeString() + " - " + message);
838    },
839
840    error: function (message) {
841        console.warn(this.getTimeString() + " - " + message);
842    },
843
844    logToSentry: function(error, message, filename, type){
845        if (typeof TraceKit !== "undefined" && TraceKit != null){
846            var myError = {
847                message: message,
848                stack: error.stack,
849                filename: filename,
850                type: type
851            };
852
853            TraceKit.report(myError);
854        }
855    },
856    /**
857     * Checks if a default Pegasos webservice response is OK.
858     * @param data The default Pegasos webservice response object.
859     */
860    isResponseOk: function (data) {
861        if (data.response) {
862            return data.response.sys && data.response.sys.returnCode && data.response.sys.returnCode === "OK";
863        }
864        return data.sys && data.sys.returnCode && data.sys.returnCode === "OK";
865    },
866
867    isInViewport: function (element) {
868        var $element = $(element);
869        if ($element.length === 0) {
870            this.warn("Element '" + element + "' not found.");
871            return false;
872        }
873        var $window = $(window);
874        var elementTop = $element.offset().top;
875        var elementBottom = elementTop + $element.outerHeight();
876        var viewportTop = $window.scrollTop();
877        var viewportBottom = viewportTop + $window.height();
878        return elementBottom > viewportTop && elementTop < viewportBottom;
879    },
880
881    keysAsArrayfromMap: function (map) {
882        var keys = [];
883        if (!!map && map instanceof Map) {
884            if (!!map.keys) {
885                keys = Array.from(map.keys());
886            } else {
887                for (var key in map) {
888                    keys.push(key);
889                }
890            }
891        }
892        return keys;
893    },
894
895    arrayFromSet: function (set) {
896        var arr = [];
897        if (!!set && set instanceof Set) {
898            if (!!Array.from) {
899                arr = Array.from(set);
900            } else {
901                set.forEach(function (v1, v2, s) {
902                    arr.push(v2);
903                });
904            }
905        }
906        return arr;
907    },
908
909    /**
910     * Checks whether the rightpanel facade is present and the rightpanel is available and visible.
911     * This is the guard consumers should use before calling any window.RightpanelFacade method.
912     * Safe to call on any page: returns false if the rightpanel module is not loaded
913     * (unlike RightpanelFacade.isAvailable(), which assumes the module is present).
914     */
915    isRightpanelUsable: function () {
916        return !!window.RightpanelFacade && window.RightpanelFacade.isAvailable();
917    },
918
919    wtSendinfo_safe: function(wt_object){
920        if (typeof(webtrekkV3) !== "undefined" && !!pegasos.tracking && !!pegasos.tracking.wt) {
921            //if this hasn't been initialized properly it does not provide the required function.
922            //try to fix this by creating a new instance
923            if ((typeof pegasos.tracking.wt.sendinfo !== 'function') && (typeof pageConfig !== 'undefined')) {
924                pegasos.tracking.wt = new webtrekkV3(pageConfig);
925            }
926
927            if (typeof pegasos.tracking.wt.sendinfo === 'function') {
928                pegasos.tracking.wt.sendinfo(wt_object);
929            }
930        }
931    },
932
933    /**
934     * returns the user currency iso code<br>
935     * respects also the customer currency if user currency should be ignored.
936     * as fallback "DEFAULT" is returned
937     * this is just the iso code (or "DEFAULT"), not the translation. The translation can be retrieved with getCurrencyTranslation() which uses this method internally.
938     *
939     * @param ignoreUserCurrency Ignore user currency and use customer currency or default currency instead.
940     * Needed when working with SAP prices as SAP does not know the user currency.
941     * @returns {*}
942     */
943    getUserCurrency(ignoreUserCurrency = false){
944        if (!ignoreUserCurrency){
945            //value is stored in pegasos variable which is set on page load, so we can directly return it without calling the server
946            return pegasos.userCurrency;
947        }
948
949        //if userCurrency should be ignored, we want to have the currency used for SAP-prices. SAP does not know anything about userCurrency
950        if (typeof (pegasos.currencyForSapPrices) !== "undefined" && pegasos.currencyForSapPrices != null){
951            return pegasos.currencyForSapPrices;
952        }
953
954        var userCurrency = "DEFAULT";
955
956        $.ajax({
957            type: "GET",
958            url: pegasos.webservicePrefix + "/currency/userCurrency?ignoreUserCurrency=" + ignoreUserCurrency,
959            async: false,
960            success: function (userCurrencyResponse) {
961                userCurrency = userCurrencyResponse;
962            },
963            error: function () {
964                console.warn("userCurrency could not be retrieved from server, using 'DEFAULT' as fallback");
965            }
966        });
967
968        pegasos.currencyForSapPrices = userCurrency;
969
970        return pegasos.currencyForSapPrices;
971    },
972
973    /**
974     * get userCurrency as iso code. Either take it from pegasos variable or retrieve it from server if not available.<br>
975     * If the currency is "DEFAULT" return the translation for "DEFAULT" which should be the correct iso code as well.
976     * @param ignoreUserCurrency
977     * @returns {*}
978     */
979    getUserCurrencyIsoCode(ignoreUserCurrency = false){
980        var userCurrency = this.getUserCurrency(ignoreUserCurrency);
981        if (userCurrency === "DEFAULT") {
982            //if currency is DEFAULT ask translation which should return the correct iso code
983            userCurrency = MSGS.get("label.core.currency." + userCurrency);
984            if (userCurrency === "Ft") {
985                //Workaround: we cannot work with Ft as it is no ISO-Code. so we need to switch to HUF.
986                //TODO: change value for "label.core.currency.DEFAULT" for 5850 to HUF
987                userCurrency = "HUF";
988            }
989        }
990        return userCurrency;
991    },
992
993    /**
994     * formats given price value according to the users currency
995     * If the currency translation is not valid (e.g. due to a missing or invalid translation) no currency will be shown but the number will still be formatted
996     *
997     * @param value
998     * @param ignoreUserCurrency Ignore user currency and use default currency instead. Needed when working with SAP prices as SAP does not know the user currency. Defaults to false.
999     * @param hideSymbol If true, format the value without showing currency code or symbol.
1000     * @returns {string}
1001     */
1002    formatPrice(value, ignoreUserCurrency = false, hideSymbol = false) {
1003        if (value === null || value === undefined || value === '') {
1004            return '';
1005        }
1006
1007        var numericValue = Number(value);
1008        if (Number.isNaN(numericValue)) {
1009            return '';
1010        }
1011
1012        var currencyIsoCode = this.getUserCurrencyIsoCode(ignoreUserCurrency);
1013
1014        var numberFormatOptions = this.getNumberFormatOptionsForCurrency(currencyIsoCode);
1015        var locale = pegasos.locale.replace("_", "-");
1016
1017        if (hideSymbol && numberFormatOptions.style === 'currency') {
1018            // Keep locale-specific rounding/fraction digits, but render as plain decimal without currency.
1019            var resolvedCurrencyOptions = new Intl.NumberFormat(locale, numberFormatOptions).resolvedOptions();
1020
1021            numberFormatOptions = {
1022                style: 'decimal',
1023                minimumFractionDigits: resolvedCurrencyOptions.minimumFractionDigits,
1024                maximumFractionDigits: resolvedCurrencyOptions.maximumFractionDigits
1025            };
1026        }
1027
1028        return new Intl.NumberFormat(locale,
1029            numberFormatOptions).format(value)
1030    },
1031
1032    /**
1033     * returns number format options for the given currency translation.<br>
1034     * If the translation is not a valid currency iso code, it falls back to standard number formatting options.
1035     *
1036     * @param currencyIsoCode
1037     * @returns
1038     */
1039    getNumberFormatOptionsForCurrency: function(currencyIsoCode){
1040
1041        if (typeof (pegasos.currencyFormatOptions) === "undefined" || pegasos.currencyFormatOptions == null){
1042            //store format options in pegasos variable to avoid calling this method multiple times for the same currency translation
1043            // which would cause multiple regex checks and console warnings in case of invalid translations
1044            pegasos.currencyFormatOptions = {};
1045        } else  if (pegasos.currencyFormatOptions[currencyIsoCode] !== undefined){
1046            return pegasos.currencyFormatOptions[currencyIsoCode];
1047        }
1048
1049        var formatOptions;
1050
1051        if(currencyIsoCode === "HUF"){
1052            formatOptions =  {
1053                style: 'currency',
1054                currency: currencyIsoCode,//use isoCode instead of translation
1055                currencyDisplay: 'symbol',
1056                maximumFractionDigits : 0
1057            };
1058        }
1059        else {
1060
1061            const isCurrencyCodeValid = new RegExp(/^[A-Z]{3}$/);
1062            var currencyCodeTranslated = MSGS.get("label.core.currency." + currencyIsoCode);
1063
1064            if (!isCurrencyCodeValid.test(currencyCodeTranslated)) {
1065                //No valid currency code
1066                //Fallback to standard number formatting
1067
1068                console.warn("Currency '" + currencyCodeTranslated + "' is not a valid currency iso code. " +
1069                    "Falling back to standard number formatting without currency.");
1070
1071                formatOptions = {
1072                    style: 'decimal',
1073                    maximumFractionDigits: 2,
1074                    minimumFractionDigits: 2
1075                }
1076            } else {
1077
1078                //standard currency formatting
1079                formatOptions = {
1080                    style: 'currency',
1081                    currency: currencyCodeTranslated,
1082                    currencyDisplay: 'code'
1083                };
1084            }
1085        }
1086
1087        pegasos.currencyFormatOptions[currencyIsoCode] = formatOptions;
1088
1089        return formatOptions;
1090    },
1091    
1092    /**
1093     * formats a percentage value like 12.5 to a localized string like 12,50 %
1094     * or, if hideSymbol is true, like 12,50
1095     *
1096     * @param percentagePoints value in percent points, e.g. 12.5 for 12.5%
1097     * @param hideSymbol if true only the localized numeric value is returned without percent sign
1098     * @param minimumFractionDigits
1099     * @param maximumFractionDigits
1100     * @returns {string}
1101     */
1102    formatPercentage(percentagePoints, hideSymbol=false, minimumFractionDigits = 0, maximumFractionDigits = 2) {
1103        if (percentagePoints === null || percentagePoints === undefined || percentagePoints === '') {
1104            return '';
1105        }
1106
1107        var numericValue = Number(percentagePoints);
1108        if (Number.isNaN(numericValue)) {
1109            return '';
1110        }
1111
1112        var locale = pegasos.locale.replace("_", "-");
1113
1114        var numberFormatOptions = {
1115            minimumFractionDigits: minimumFractionDigits,
1116            maximumFractionDigits: maximumFractionDigits
1117        };
1118
1119        if (hideSymbol) {
1120            return new Intl.NumberFormat(locale, numberFormatOptions).format(numericValue);
1121        }
1122
1123        return new Intl.NumberFormat(locale, {
1124            ...numberFormatOptions,
1125            style: 'percent'
1126        }).format(numericValue / 100);
1127    },
1128
1129    /**
1130     * normalizes a localized number string to a number value. E.g. it converts "12,50" to 12.5 for German locale.
1131     * Needed to send normalized value to webservice
1132     * @param value
1133     * @returns {number}
1134     */
1135    normalizeLocaleNumber(value){
1136
1137        if (value === null || value === undefined || value.trim() === '') {
1138            return null;
1139        }
1140
1141        const parts = new Intl.NumberFormat(pegasos.locale.replace("_", "-")).formatToParts(12345.6);
1142
1143        const group = parts.find(part => part.type === 'group')?.value ?? ',';
1144        const decimal = parts.find(part => part.type === 'decimal')?.value ?? '.';
1145
1146        const normalized = value
1147            .replaceAll(group, '')
1148            .replace(decimal, '.');
1149
1150        return Number(normalized);
1151    },
1152
1153    /**
1154     * returns the currency for display as it is defined by locale (either as symbol or code)
1155     * @param ignoreUserCurrency
1156     * @returns {string|*}
1157     */
1158    getCurrencyDisplay(ignoreUserCurrency = false) {
1159        var currencyIsoCode = this.getUserCurrencyIsoCode(ignoreUserCurrency);
1160        var numberFormatOptions = this.getNumberFormatOptionsForCurrency(currencyIsoCode);
1161
1162        const formatter = new Intl.NumberFormat(pegasos.locale.replace("_", "-"),
1163            numberFormatOptions)
1164
1165        const parts = formatter.formatToParts(0);
1166        const currencyPart = parts.find(part => part.type === 'currency');
1167        return currencyPart ? currencyPart.value : currencyIsoCode;
1168    },
1169    formatDate: function (datemilis, includeTime = false) {
1170        if (!datemilis || datemilis <= 0 || isNaN(datemilis)) {
1171            return "";
1172        }
1173        var dateobj = new Date(datemilis);
1174        const formatter = Intl.DateTimeFormat(pegasos.locale.replace("_", "-"),{
1175            dateStyle: 'short',
1176            timeStyle: includeTime ? 'short' : undefined
1177        });
1178        return formatter.format(dateobj);
1179    },
1180    /**
1181     * Loads the notepad list from the server asynchronously and converts it to the legacy struts-result object if requested.
1182     *
1183     * callable like this:
1184     * pegasosUtils.fetchNotepadList(true).then(function (savedBaskets) {
1185     *     self.savedBaskets = savedBaskets;
1186     * });
1187     *
1188     * @param convertToLegacyStrutsResult
1189     * @returns {*}
1190     */
1191    fetchNotepadList: function (convertToLegacyStrutsResult = false) {
1192
1193        return $.ajax({
1194            type: "GET",
1195            url: pegasos.webservicePrefix + "/notepad/notepadList",
1196            dataType: "json"
1197        }).then(function (data) {
1198
1199            if (!convertToLegacyStrutsResult){
1200                return data;
1201            }
1202
1203            //convert to old struts-result object so that the existing js-logic can be reused without changes
1204            var convertNotepad = function (notepad) {
1205                return {
1206                    "notepadName": notepad.notepadName,
1207                    "createdDate": notepad.createdDate,
1208                    "createdDateFormatted": pegasosUtils.formatDate(notepad.createdDate),
1209                    "createdBy": notepad.createdBy,
1210                    "lastChangedDate": notepad.lastUpdatedDate,
1211                    "lastChangedDateFormatted": pegasosUtils.formatDate(notepad.lastUpdatedDate),
1212                    "lastChangedBy": notepad.lastUpdatedBy,
1213                    "notepadId": String(notepad.cartId),
1214                };
1215            };
1216
1217            const publicNotepads = data.filter(function (notepad) {
1218                return notepad.notepadType === "PUN";
1219            }).map(convertNotepad);
1220            const privateNotepads = data.filter(function (notepad) {
1221                return notepad.notepadType === "PRN";
1222            }).map(convertNotepad);
1223
1224            const defaultNotepad = data.find(function (notepad) {
1225                return notepad.markAsDefault === true;
1226            });
1227
1228            const savedBaskets = {
1229                "publicNotepadList":publicNotepads,
1230                "privateNotepadList":privateNotepads
1231            }
1232            if (defaultNotepad) {
1233                savedBaskets.notepadIdMarkedAsDefault = String(defaultNotepad.cartId);
1234            }
1235            return savedBaskets;
1236        }, function () {
1237            if (!convertToLegacyStrutsResult){
1238                return [];
1239            }
1240            return {
1241                "publicNotepadList":[],
1242                "privateNotepadList":[],
1243                //marker so callers can distinguish a failed load from an empty-but-successful result
1244                "loadFailed":true
1245            }
1246        });
1247    }
1248};

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.