PageSourceSearch

https://cug.tradedirect.ch/td/application/themes/easy/js/application.js?v=3.4.79

js tradedirect.ch collected 2026-10-06 22:02:29 UTC 184,814 bytes, 3,884 lines download raw bytes

1if(!window.APPLICATION) { // Prevent re-inclusion ..
2/**
3 * solid application settings
4 */
5var Application = function() {
6    var contextPath;
7    var logoutSettings = {
8        solidLogoutUrl:'',
9        solidRedirectUrl:'',
10        bcvLogoutUrl:''
11    };
12
13    return {
14        init: function(ctxPath) {
15            contextPath = ctxPath;
16        },
17        contextPath: function() {
18            return contextPath;
19        },
20        logoutSettings:function(){
21            return logoutSettings;
22        }
23    }
24}();
25Solid = (function ($) {
26    return {
27        contextPath: Application.contextPath(),
28        decorateCSRF: function(object) {
29                    object[$("meta[name='_csrf_param']").attr("content")] = $("meta[name='_csrf']").attr("content");
30                    return object;
31                },
32        decorateCSRFHeader: function(object) {
33                    object[$("meta[name='_csrf_header']").attr("content")]= $("meta[name='_csrf']").attr("content");
34                    return object;
35        },
36        initElasticSearchChart: function (finCharts, containerId) {
37            $("#" + containerId + "-searchParams").solidFastSearch({
38                query:{
39                    fields: "M_NAME,M_SYMB,M_ISIN,M_MARKET:value:description,SC_GROUPED:value:description,M_CUR:value:description,MIC,EUSIPA,DOMICILE,M_BC",
40                    flavor: "EQU,OPT,BON,IND",
41                    size: 2,
42                    mainMarket:false,
43                    useWildcards: false
44                },
45                action: function(context) {
46                    if (context.highlighted) {
47                        var listingId = context.highlighted.data('listing');
48                        if (listingId) {
49                            finCharts.addOverlay(listingId);
50                        }
51                    }
52                },
53                useFieldWidth: false
54            }).closest('td').next().contents().hide();
55        },
56        manageLogin: function (vToHost) {
57            $('.nav-link.btn.btn-header.login').on('click', function(){
58
59            $.ajax({
60               url: vToHost + '/sso/username',
61                  dataType: 'text',
62                  success: function (userID) {
63                    if (userID) {
64                       $("#sessionAlive").fadeIn();
65                       $("#sessionAlive p:first").append(userID);
66                       $("#premiun").hide();
67                    }
68                            // Nothing on error
69                  }
70              });
71            });
72        },
73        initClockDisplay: function (iterationClass) {
74            var panels = $(".marketInfo div.tab-content div.tab-pane ." + iterationClass);
75            panels.each(function() {
76                var data = $(this).data();
77                var clock = $(this).find('.bcClock');
78                clock.clock({
79                    data: {
80                        bc: data.symbol,
81                        name: data.name,
82                        bcOpen: (data.breakfrom && data.breakto) ? [data.open, data.breakto] : data.open,
83                        bcClose: (data.breakfrom && data.breakto) ? [data.breakfrom, data.close] : data.close,
84                        offsetUTC: data.utc,
85                        offsetDST: data.dst,
86                        isOpen: data.isopen
87                    },
88                    bcTime: true
89                });
90            });
91        },
92        initElasticSearch: function (relativeUrl, inputId) {
93            var inputField = $("#" + inputId);
94            var inputFieldGroup = inputField.closest('.input-group');
95            inputField.solidFastSearch({
96                query: {
97                    flavor: "EQU,IND,BON,ETF,FON,TFO,CUR,COM,INT,OPT,DER,FUT,TER,CTR,DIV",
98                    fields: "M_NAME,M_SYMB,M_ISIN,LVAL:value:datetime,NC2_PR_NORM:value,M_MARKET:value:description,SC_GROUPED:value:description,M_CUR:value:description,MOST_LIQUID,MIC,EUSIPA,DOMICILE,M_BC",
99                    mainMarket: false,
100                    useWildcards: true,
101                    size: 15
102                },
103                alignElement: inputFieldGroup.length ? inputFieldGroup : null
104            });
105        },
106        initPortfolioElasticSearch: function (relativeUrl, inputId) {
107            var inputField = $("#" + inputId);
108            var inputFieldGroup = inputField.closest('.input-group');
109            inputField.solidFastSearch({
110                query: {
111                    flavor: "EQU,IND,BON,ETF,FON,TFO,CUR,COM,INT,OPT,DER,FUT,TER,CTR,DIV",
112                    fields: "M_NAME,M_SYMB,M_ISIN,M_MARKET:value:description,SC_GROUPED:value:description,M_CUR:value:description,MOST_LIQUID,MIC,EUSIPA,DOMICILE,M_BC",
113                    mainMarket: false,
114                    useWildcards: true,
115                    size: 15
116                },
117                action: function(context) {
118                    if (context.highlighted) {
119                        var listingId = context.highlighted.data('listing');
120                        if (listingId) {
121                            var a = $("#portfolioId");
122                            var url = Application.contextPath() + "/portfolio/add/instrumentToThisPortfolio/" + a.val() + "/" + listingId +"?context=show";
123                            var title = a.data('title');
124                            var loadingText = a.data('loading-text') || '';
125                            var ajaxOptionsName = a.data('ajax-options') || '';
126                            var dialogOptions = dialogOptions = {};
127                            var ajaxOptions = window[ajaxOptionsName];
128                            if (!ajaxOptions) {
129                                ajaxOptions = {
130                                    error: function(jqXHR, textStatus, errorThrown) {
131                                        this.find('.modal-body').text(errorThrown);
132                                    }
133                                };
134                            }
135                           window.location = Application.contextPath() + "/portfolio/add/instrumentToThisPortfolio/" + $("#portfolioId").val() + "/" + listingId +"?context=show";
136                       }
137                    }
138                },
139                template:'quicksearch/result',
140                errorTemplate:'quicksearch/error',
141                alignElement: inputFieldGroup.length ? inputFieldGroup : null
142            });
143        },
144        initDynMenuTransactionnals: function() {
145
146            /* Define the element that will react on click */
147            var $dynItem = $('a.dyn-item.nav-link');
148
149            /* Proceed only when all the mandatory elements are defined */
150            if($dynItem && $dynItem.length > 0){
151                /* React when clicking on the dyn Item*/
152                $dynItem.on('click', function(e){
153                    e.preventDefault();
154                    e.stopImmediatePropagation();
155
156                    var $this = $(this),
157                        menu = $this.data("menu");
158
159                    var $navsecond = $('#dynMenu');
160
161                    // remove all elements
162                    $('#dynMenu li.dyn-item.nav-item').remove();
163
164                    // append html from div layer!
165                    $navsecond.append($('#menu' + menu).html());
166                })
167            }
168        },
169        checkURLDocument: function(event, url) {
170            event.preventDefault();
171            var documentCheck = $().trading().checkURLDocument(url);
172            $.when(documentCheck).done(function(data){
173                window.open(url, '_blank').focus();
174            });
175        },
176        getDocumentsFromBCV: function(isin) {
177            var documentsDerivatives = $().trading().documentsFromBCV(isin);
178            $.when(documentsDerivatives).done(function(data){
179                if(data !== undefined && data.length !== undefined && data.length > 0) {
180                    var lang = document.documentElement.lang;
181                    if(lang.indexOf("_") >= 0){
182                        lang = lang.split('_', 1)[0];
183                    }
184                    var mainLanguage = null;
185                    var langEn = false;
186                    var langFr = false;
187                    var langDe = false;
188                    data.forEach(function (op, index) {
189                        if (op.documentType == 'PRIIP' && op.source == 'SIXDOCHUB') { // if is not PRIIP is a termsheet, that we musn't take account
190                            var langDocument;
191                            if (op.language == 1) {
192                                langEn = true;
193                                langDocument = 'en';
194                                $('.' + langDocument + '_docs_sub').attr("onclick", "Solid.checkURLDocument(event,'" + $().trading().documentsFromBCVGet() + op.disseminationRecipient + "')");
195                                $('.' + langDocument + '_docs_sub').attr("href", "#");
196                            }
197                            if (op.language == 2) {
198                                langFr = true;
199                                langDocument = 'fr';
200                                $('.' + langDocument + '_docs_sub').attr("onclick", "Solid.checkURLDocument(event,'" + $().trading().documentsFromBCVGet() + op.disseminationRecipient + "')");
201                                $('.' + langDocument + '_docs_sub').attr("href", "#");
202                            }
203                            if (op.language == 3) {
204                                langDe = true;
205                                langDocument = 'de';
206                                $('.' + langDocument + '_docs_sub').attr("onclick", "Solid.checkURLDocument(event,'" + $().trading().documentsFromBCVGet() + op.disseminationRecipient + "')");
207                                $('.' + langDocument + '_docs_sub').attr("href", "#");
208                            }
209                            if (langDocument == lang) {
210                                mainLanguage = lang;
211                                $('#' + langDocument + '_docs').attr("href", "#");
212                                $('#' + langDocument + '_docs').show();
213                                $('#spinnerDocument').hide();
214                                $('.' + langDocument + '_docs_sub').attr("onclick", "Solid.checkURLDocument(event,'" + $().trading().documentsFromBCVGet() + op.disseminationRecipient + "')");
215                                $('.' + langDocument + '_docs_sub').attr("href", "#");
216                            }
217                        }
218                    });
219                    if (!langEn || !langFr || !langDe) {
220                        data.forEach(function (op, index) {
221                            if (op.documentType == 'KIDS' && op.source == 'STRUCTURES_BCV') {
222                                var langDocument;
223                                url = op.linkUrl;
224                                if (op.language == 1 && !langEn) {
225                                    langEn = true;
226                                    langDocument = 'en';
227                                    $('.' + langDocument + '_docs_sub').attr("onclick", "Solid.checkURLDocument(event,'" + url + "')");
228                                    $('.' + langDocument + '_docs_sub').attr("href", "#");
229                                }
230                                if (op.language == 2 && !langFr) {
231                                    langFr = true;
232                                    langDocument = 'fr';
233                                    $('.' + langDocument + '_docs_sub').attr("onclick", "Solid.checkURLDocument(event,'" + url + "')");
234                                    $('.' + langDocument + '_docs_sub').attr("href", "#");
235                                }
236                                if (op.language == 3 && !langDe) {
237                                    langDe = true;
238                                    langDocument = 'de';
239                                    $('.' + langDocument + '_docs_sub').attr("onclick", "Solid.checkURLDocument(event,'" + url + "')");
240                                    $('.' + langDocument + '_docs_sub').attr("href", "#");
241                                }
242                                if (langDocument == lang) {
243                                    mainLanguage = lang;
244                                    $('#' + langDocument + '_docs').attr("href", "#");
245                                    $('#' + langDocument + '_docs').show();
246                                    $('#spinnerDocument').hide();
247                                    $('.' + langDocument + '_docs_sub').attr("onclick", "Solid.checkURLDocument(event,'" + url + "')");
248                                    $('.' + langDocument + '_docs_sub').attr("href", "#");
249                                }
250                            }
251                        });
252                    }
253                    if (mainLanguage == null) {
254                        var fallbackDoc = null;
255                        for (var i = 0; i < data.length; i++) {
256                            var op = data[i];
257                            if (op !== undefined && op.language !== undefined && op.language != null) {
258                                if (op.language == 1 || op.language == 2 || op.language == 3) {
259                                    fallbackDoc = op;
260                                    break;
261                                }
262                            }
263                        }
264                        if (fallbackDoc != null) {
265                            var langAux = fallbackDoc.language;
266                            var langFirst = '';
267                            if (langAux == 1) {
268                                langFirst = 'en';
269                            }
270                            if (langAux == 2) {
271                                langFirst = 'fr';
272                            }
273                            if (langAux == 3) {
274                                langFirst = 'de';
275                            }
276                            $('#spinnerDocument').hide();
277                            $('#' + langFirst + '_docs').attr("onclick", "Solid.checkURLDocument(event,'" + $().trading().documentsFromBCVGet() + fallbackDoc.disseminationRecipient + "')");
278                            $('#' + langFirst + '_docs').attr("href", "#");
279                            $('#' + langFirst + '_docs').show();
280                            $('.' + langFirst + '_docs_sub').attr("href", "#");
281                            $('.' + langFirst + '_docs_sub').attr("onclick", "Solid.checkURLDocument(event,'" + $().trading().documentsFromBCVGet() + fallbackDoc.disseminationRecipient + "')");
282                        }
283                    }
284                    // hide anchor if some of languages doesn't exist
285                    if(!langDe) {
286                        $('.de_docs_sub').hide();
287                    }
288                    if(!langEn) {
289                        $('.en_docs_sub').hide();
290                    }
291                    if(!langFr) {
292                        $('.fr_docs_sub').hide();
293                    }
294                    if(!langEn && !langFr && !langDe){ // if the source is STRUCTURES_BCV structuredproducts(non BCV) that has no PRIIP
295                        $('#textDocument').show();
296                        $('#kiidTextWarning').show();
297                        $('#spinnerDocument').hide();
298                        data = [];
299                    }
300                }
301                else{
302                    $('#textDocument').show();
303                    $('#kiidTextWarning').show();
304                    $('#spinnerDocument').hide();
305                }
306
307
308            }).fail(function (xhr) {
309                console.log("No documents from bcv. Code error from service: " + xhr.status);
310                $('#textDocument').show();
311                $('#kiidTextWarning').show();
312                $('#spinnerDocument').hide();
313            });
314        },
315        initUserInformation: function(time) {
316
317            /* Define the element that will react on click */
318            var $userName = $('#userName');
319
320            /* Proceed only when all the mandatory elements are defined */
321           // if ($userName && $userName.length > 0 ) {
322                var me = {};
323                /* React when clicking on the dyn Item*/
324                var ajaxMe = $().trading().me();
325                $.when(ajaxMe).then(function(dataMe) {
326                    me = dataMe;
327                    console.log("User information: ", me);
328                    if (me == false) {
329                        // if the user information is not loading, we must remove sessionstorage and refresh the page
330                        // and it will work.
331                        sessionStorage.removeItem('userSession');
332                        sessionStorage.removeItem('attributes');
333                        sessionStorage.removeItem('noAttributes');
334                        sessionStorage.removeItem('attributesJSON');
335                        time = time + time;
336                        if(window.location.href != null && !window.location.href.includes('localhost')) {
337                            setTimeout(function () {
338                                Solid.initUserInformation(time);
339                            }, time);
340                        }
341                    }
342                    else {
343                    if (me.person !== undefined && me.person.short
343Name !== undefined) {
344                        $userName.html(me.person.shortName);
345
346                        /* Checks if we must add the user name and account into containers (user preferences) */
347                        var $userAccountElem = $('span#trading-user-account');
348                        var $userNameElem = $('span#trading-user-name');
349
350                        if ($userAccountElem && $userNameElem) {
351                            $userAccountElem.text(me.userName);
352                            $userNameElem.text(me.person.shortName);
353                        }
354                    }
355
356                    if (me.qualifiers !== undefined && $.isArray(me.qualifiers)) {
357                        const $corpacNav = $('.nav-item.corpac');
358                        const $notificationsNav = $('.coparc-notificaions');
359                        const comumnity = me.qualifiers.includes('CORPACCommunity');
360                        const featureBase = me.qualifiers.includes('Feature/CORPAC');
361                        const featureDisabled = me.qualifiers.includes('Feature/CORPAC/disabled');
362                        if (featureBase && comumnity) {
363                            $corpacNav.removeClass('d-none');
364                        }
365                        if (featureBase && comumnity && !featureDisabled) {
366                            $notificationsNav.removeClass('d-none');
367                        }
368                    }
369                    //STINGRAY
370                    <!-- Stingray removed JS method by BCVSETUPS-1143 -->
371
372                    }
373
374                }).fail(function () {
375                    console.log("No User information!");
376                    me = {};
377                });
378            //}
379            <!-- Stingray removed JS method by BCVSETUPS-1143 -->
380
381        },
382        initMostConsulted: function(url){
383            /* State variables, will be used to define what action will be taken */
384            url += "&lang=" + document.documentElement.lang;
385            var webfgConfig = {
386                mouseOnMostConsulted:false,
387                mouseOnTdIcon:false,
388                page:1
389            };
390
391            /* Define the element that will react on click */
392            var $tdIcon = $('a.nav-link span.tdIcon');
393            var $mostConsultedPanel = $("div.webfg.most-consulted");
394            var $navigationBar = $('nav.nav-secondLevel');
395            var $body = $('body');
396
397            /* Proceed only when all the mandatory elements are defined */
398            if($tdIcon && $tdIcon.length > 0 && $navigationBar && $navigationBar.length > 0 && $body && $body.length > 0){
399                /* Keep track of the mouse position towards the td icon. */
400                $tdIcon.mouseover(function(){
401                    webfgConfig.mouseOnTdIcon = true;
402                });
403
404                $tdIcon.mouseout(function(){
405                    webfgConfig.mouseOnTdIcon = false;
406                });
407
408                /* React when clicking on the td icon */
409                $tdIcon.on('click', function(){
410
411                    /* If the panel exists remove it to ensure that we always have the latest state of the widget */
412                    if($mostConsultedPanel.length !== undefined && $mostConsultedPanel.children().length > 0) {
413                        $mostConsultedPanel.hide();
414                        $mostConsultedPanel.empty();
415                        $('div.dim').remove();
416                    }
417                    else {
418                        $('div.dim').remove();
419                        webfg.dim();
420
421                        /* Create the base div */
422                        $mostConsultedPanel = $('<div></div>');
423                        $mostConsultedPanel.addClass('webfg most-consulted');
424                        $mostConsultedPanel.css('position', 'absolute');
425
426                        /* Compute the position of the popup */
427                        var top = $navigationBar.offset().top + $navigationBar.height();
428
429                        $mostConsultedPanel.css('top', top + 'px');
430                        $mostConsultedPanel.css('left', $("#dynMenu").position().left - 15 + 'px');
431
432                        $mostConsultedPanel.load(url, function(){
433                            /* Append the event handlers on the whole body */
434                            $mostConsultedPanel.mouseover(function(){
435                                webfgConfig.mouseOnMostConsulted = true;
436                            });
437
438                            $mostConsultedPanel.mouseout(function(){
439                                webfgConfig.mouseOnMostConsulted = false;
440                            });
441
442                            /* The table links */
443                            var $moreResultsElem = $mostConsultedPanel.find('a.more-results');
444                            var $lessResultsElem = $mostConsultedPanel.find('a.less-results');
445
446                            /* Append an event handler to the 'more results' link */
447                            $moreResultsElem.on('click', function(e){
448                                /* Prevents the link from being called */
449                                e.preventDefault();
450
451                                if(webfgConfig.page < 5){
452
453                                    /* Build the default URL */
454                                    webfgConfig.page = webfgConfig.page + 1;
455
456                                    var anchor = $(this).attr('href') + '?decorator=empty&tableOnly=true';
457
458                                    /* Reload the new table */
459                                    $mostConsultedPanel.find('table').load(
460                                        anchor + '&pageSize=' + webfgConfig.page,
461                                        Solid.handleMostConsultedLinks(webfgConfig.page, $moreResultsElem, $lessResultsElem)
462                                    );
463                                }
464                            });
465
466                            /* Append an event handler to the 'more results' link */
467                            $lessResultsElem.on('click', function(e){
468                                /* Prevents the link from being called */
469                                e.preventDefault();
470
471                                if(webfgConfig.page > 1){
472
473                                    /* Build the default URL */
474                                    webfgConfig.page = webfgConfig.page -1;
475
476                                    var anchor = $(this).attr('href') + '?decorator=empty&tableOnly=true';
477
478                                    /* Reload the new table */
479                                    $mostConsultedPanel.find('table').load(
480                                        anchor + '&pageSize=' + webfgConfig.page,
481                                        Solid.handleMostConsultedLinks(webfgConfig.page, $moreResultsElem, $lessResultsElem)
482                                    );
483                                }
484                            });
485
486                            $body.append($mostConsultedPanel);
487                            $body.on('click', function(){
488                                if(!webfgConfig.mouseOnMostConsulted && !webfgConfig.mouseOnTdIcon){
489                                    $mostConsultedPanel.hide();
490                                    $mostConsultedPanel.empty();
491                                }
492                            });
493                        });
494                    }
495                });
496            }
497        },
498        handleMostConsultedLinks:function(pageSize, $moreResultsElem, $lessResultsElem){
499            /* I'm tired, this explains that. Add a to-do if a better implementation is needed */
500            if(pageSize > 1){
501                $lessResultsElem.show();
502            }
503            else{
504                $lessResultsElem.hide();
505            }
506
507            if(pageSize < 5){
508                $moreResultsElem.show();
509            }
510            else{
511                $moreResultsElem.hide();
512            }
513        },
514         initElasticSearchUnderlyingValorExtendedSearch: function (relativeUrl, inputField) {
515                    var inputField = $("#" + inputField);
516                    var inputFieldGroup = inputField.closest('.input-group');
517                    inputField.solidFastSearch({
518                        query: {
519                                 fields: "M_NAME,M_SYMB,M_ISIN,M_MARKET:value:description,SC_GROUPED:value:description,M_CUR:value:description,MIC,EUSIPA,DOMICILE,M_BC",
520                                 flavor: "EQU,IND,COM,CUR,BON,DIV,INT,LIQ",
521                                 size: 2,
522                                 useWildcards: true
523                        },
524                        alignElement: inputFieldGroup.length ? inputFieldGroup : null
525                    });
526                },
527          createMiniChart:function(fltPrevDayClose){
528
529                                    var color = '#009933';
530                                    var langChart = document.documentElement.lang.trim().replace(/_/g, '-');
531                                     /**
532                                      * Create a constructor for sparklines that takes some sensible defaults and merges in the individual
533                                      * chart options. This function is also available from the jQuery plugin as $(element).highcharts('SparkLine').
534                                      */
535                                      if(typeof Highcharts !== "undefined"){
536                                      Highcharts.setOptions({
537                                          accessibility: {
538                                              enabled: false
539                                          },
540                                          lang: {
541                                              locale: langChart
542                                          }
543                                      });
544                                      Highcharts.SparkLine = function (a, b, c) {
545                                      var hasRenderToArg = typeof a === 'string' || a.nodeName,
546                                      options = arguments[hasRenderToArg ? 1 : 0],
547                                       defaultOptions = {
548                                       chart: {
549                                       renderTo: (options.chart && options.chart.renderTo) || this,
550                                       backgroundColor: null,
551                                       borderWidth: 0,
552                                       type: 'line',
553                                       margin: [2, 0, 2, 0],
554                                       width: 100,
555                                       height: 40,
556                                       style: {
557                                          overflow: 'visible'
558                                       },
559                                       lineWidth: 2,
560                                       lineColor: 'red',
561                                       skipClone: true
562                                       },
563                                       title: {
564                                       text: ''
565                                       },
566                                       credits: {
567                                       enabled: false
568                                       },
569                                       navigation: {
570                                           buttonOptions: {
571                                           enabled: false,
572                                           symbolStroke: '#DDDDDD',
573                                           theme: {
574                                           fill: '#e3e3e3'
575                                           }
576                                           }
577                                       },
578                                       xAxis: {
579                                           labels: {
580                                           enabled: false
581                                           },
582                                       title: {
583                                       text: null
584                                       },
585                                       startOnTick: false,
586                                       endOnTick: false,
587                                       lineColor: 'transparent',
588                                       tickPositions: []
589                                        },
590                                        yAxis: {
591                                       endOnTick: false,
592                                       startOnTick: false,
593                                       labels: {
594                                        enabled: false
595                                       },
596                                       title: {
597                                       text: null
598                                        },
599                                       gridLineColor: 'transparent',
600                                       plotLines: [{
601                                        value: fltPrevDayClose,
602                                        width: 1,
603                                        color: '#aaa'
604                                      }],
605                                       tickPositions: []
606                                       },
607                                        legend: {
608                                          enabled: false
609                                         },
610                                        tooltip: {
611                                         enabled: true,
612                                         backgroundColor: null,
613                                          borderWidth: 0,
614                                          shadow: false,
615                                          useHTML: true,
616                                         hideDelay: 0,
617                                         shared: true,
618                                         padding: 0,
619                                         positioner: function (w, h, point) {
620                                           return { x: point.plotX - w / 2, y: point.plotY - h };
621                                         }
622                                         },
623                                         plotOptions: {
624                                           series: {
625                                          animation: false,
626                                           lineWidth: 1,
627                                            shadow: false,
628                                           color: color,
629                                            states: {
630                                           hover: {
631                                               lineWidth: 1
632                                            }
633                                           },
634                                           marker: {
635                                             radius: 1,
636                                             states: {
637                                                hover: {
638                                                radius: 2
639                                                }
640                                                }
641                                            },
642                                            fillOpacity: 0.25
643                                           },
644                                           column: {
645                                              negativeColor: '#910000',
646                                              borderColor: 'silver'
647                                              }
648                                            }
649                                           };
650
651                                           options = Highcharts.merge(defaultOptions, options);
652
653                                           return hasRenderToArg ?
654                                           new Highcharts.Chart(a, options, c) :
655                                           new Highcharts.Chart(options, b);
656                                           };
657
658                                           var start = +new Date(),
659                                            $tds = $('div[data-sparkline]'),
660                                            fullLen = $tds.length,
661                                            n = 0;
662
663                                         // Creating 153 sparkline charts is quite fast in modern browsers, but IE8 and mobile
664                                        // can take some seconds, so we split the input into chunks and apply them in timeouts
665                                         // in order avoid locking up the browser process and allow interaction.
666                                         function doChunk() {
667                                            var time = +new Date(),
668                                                i,
669                                                len = $tds.length,
670                                            $td,
671                                                stringdata,
672                                                fltPrevDayClose,
673                                                colorvalue,
674                                                 arr,
675                                                 data,
676                                                 chart;
677
678                                              for (i = 0; i < len; i += 1) {
679                                                  $td = $($tds[i]);
680                                                 stringdata = $td.data('sparkline');
681                                                 fltPrevDayClose = $td.data('prevdayclose');
682                                                 colorvalue = $td.data('colorvalue');
683                                                  data = stringdata;
684                                                  arr = data.map(function(elem) {
685                                                      return [elem[0],parseFloat(elem[1])];
686                                                   });
687                                                   //arr = stringdata;
688                                                chart = {};
689                                                if (arr[1]) {
690                                                   //  chart.type = arr[1];
691                                                 }
692                                                 $td.highcharts('SparkLine', {
693                                                     series: [{
694                                                        data:  arr,
695                                                         pointStart: 1
696                                                    }],
697                                                    tooltip: {
698                                                      formatter: function() {
699                                                        return this.points.reduce(function (s, point) {
700                                                           return '<div style="width:200px;"><strong>'+point.key + ' <p style="color:'+point.color+';"> ' +
701                                                               point.y+'</p></strong>' ;
702                                                           }, '<b>' + this.x + '</b></div>');
703                                                      }
704                                                    },
705                                                     plotOptions: {
706                                                           series: {
707                                                          animation: false,
708                                                             lineWidth: 1,
709                                                             shadow: false,
710                                                              zones: [{value: fltPrevDayClose, color: '#dc3545'}],
711                                                             color: '#28a745'
712                                                             }
713                                                             },
714                                                              yAxis: {
715
716                                                                  plotLines: [{
717                                                                       value: fltPrevDayClose,
718                                                                       width: 1,
719                                                                       color: '#aaa'
720                                                                       }],
721                                                                    },
722                                                                    chart: chart
723                                                                });
724
725                                                                n += 1;
726                                                                // If the process takes too much time, run a timeout to allow interaction with the browser
727                                                  if (new Date() - time > 500) {
728                                                      $tds.splice(0, i + 1);
729                                                      setTimeout(doChunk, 0);
730                                                       break;
731                                                     }
732
733                             // Print a feedback on the performance
734                             if (n === fullLen) {
735                               $('#result').html('Generated ' + fullLen + ' sparklines in ' + (ne
735w Date() - start) + ' ms');
736                               }
737                            }
738                        }
739                          doChunk();
740
741
742            }
743            else {
744                setTimeout(Solid.createMiniChart, 50);
745            }
746        },
747        initMiniChartsIntraday:function(){
748                        var fltPrevDayClose = 0;
749                        $.each(timeSeries, function(index, value){
750                        $.each(value, function(index2, value2){
751                            var listingId = value2.listingId;
752                            var prices = value2.prices;
753                            var dataArray = [];
754                            if(listingId && prices && prices.length > 0){
755                                var divId = "mini-chart-" + listingId.replace(new RegExp(',', 'g'), '-');
756                                var $miniChart = $('div#' + divId);
757                                var attributeData = $miniChart.attr('data-sparkline');
758                                if (typeof attributeData === 'undefined' && attributeData !== true) {
759                                if($miniChart.length > 0){
760                                 var value = $miniChart.data('value');
761                                 var strPrevDayClose = $miniChart.data("prevdayclose");
762                                 fltPrevDayClose = parseFloat($miniChart.data('prevdayclose'));
763                                 $.get(Application.contextPath() + "/api/series/intraday",{
764                                     lid: listingId, // man
765                                     max: 2500,
766                                     mode: 'snap', // man
767                                     period: '1d', // man
768                                     vt: 'yes',
769                                     intra: true // include intraday prices series!
770                                 }, function(data) {
771                                      var fltPrevDayClose = parseFloat(strPrevDayClose);
772                                      if(data != ""){
773                                          //add the reference line with the previous day value
774                                          for (var i = 0; i < data.data.length; i++) {
775                                              // date, positive value, negative value, previous day close
776                                              var tickVal = data.data[i][1];
777                                              var date = new Date(data.data[i][0]);
778                                              var hours = date.getHours();
779                                              var minutes = date.getMinutes();
780                                              var seconds = date.getSeconds();
781                                              var day = date.getDate();
782                                              var month = date.getMonth()+1;
783                                              var year = date.getFullYear();
784
785                                              if(hours < 10){hours = '0'+hours;}
786                                              if(minutes < 10){minutes = '0'+minutes;}
787                                              if(seconds < 10){seconds = '0'+seconds;}
788                                              if(month<10){month = '0'+month;}
789                                              if(day<10){day = '0'+day;}
790                                              if(tickVal >= fltPrevDayClose) {
791                                               dataArray.push([day+"/"+month+"/"+year+"  "+hours+":"+minutes, tickVal, 'line {color: #009933}', fltPrevDayClose]);
792                                              } else {
793                                               dataArray.push([day+"/"+month+"/"+year+"  "+hours+":"+minutes, tickVal, 'line {color: #FF5B5B}', fltPrevDayClose]);
794                                              }
795                                          }
796
797                                          var pricesPrint = "";
798                                          $.each(dataArray, function(ind,val) {
799                                              // dataArray.push([val.d, val.c, pval]);
800                                              if(pricesPrint != ""){
801                                                  pricesPrint = pricesPrint + ', ';
802                                              }
803                                              pricesPrint = pricesPrint + "[\""+val[0]+"\",\"" +val[1]+"\"]";
804                                          });
805                                          $('#'+divId).attr('data-sparkline', "["+pricesPrint+"]");
806                                          Solid.createMiniChart(fltPrevDayClose);
807
808                                      } else { // There is no data for the graph and we display an alternative message
809                                          //$('div.sparklight').append('<div class="no-chart-data">' + msg + '</div>');
810                                          $('div.sparklight div.no-chart-data').css('display', 'inline');
811                                      }
812                                    });
813                                }
814                            }
815                            else{
816                                var divId = "mini-chart-" + value2.listingId.replace(new RegExp(',', 'g'), '-');
817                                var $miniChart = $('div#' + divId);
818                                var strPrevDayClose = $miniChart.data("prevdayclose");
819                                fltPrevDayClose = parseFloat($miniChart.data('prevdayclose'));
820                                Solid.createMiniChart(fltPrevDayClose);
821                            }
822                            }
823                        });
824                        });
825        },
826        initMiniCharts:function(){
827                var lastValue = 0;
828                var color = '';
829                // first, put attributes in div for chart
830               // data-sparkline="71, 78, 39, 66 "
831                        $.each(timeSeries, function(index, value){
832                        $.each(value, function(index2, value2){
833                            var listingId = value2.listingId;
834                            var prices = value2.prices;
835
836                            if(listingId && prices && prices.length > 0){
837                                var divId = "mini-chart-" + listingId.replace(new RegExp(',', 'g'), '-');
838                                var $miniChart = $('div#' + divId);
839                                if($miniChart.length > 0){
840
841                                    var value = $miniChart.data('value');
842                                    var pval = $miniChart.data('pval');
843
844                                    if(value > 0 ){
845                                       color = '#009933';
846                                    }
847                                    else {
848                                       color = '#FF5B5B';
849                                    }
850
851                                    var dataArray = [];
852                                    var pricesPrint = "";
853                                    $.each(prices, function(ind,val) {
854                                       // dataArray.push([val.d, val.c, pval]);
855                                       if(pricesPrint != ""){
856                                        pricesPrint = pricesPrint + ', ';
857                                       }
858                                       pricesPrint = pricesPrint + val.c;
859                                    });
860
861                                    $('#'+divId).attr('data-sparkline', pricesPrint);
862                                    lastValue = prices[prices.length-1].c;
863                                    $('#'+divId).attr('data-lastvalue', lastValue);
864                                    $('#'+divId).attr('data-colorvalue', color);
865
866                                     /**
867                                      * Create a constructor for sparklines that takes some sensible defaults and merges in the individual
868                                      * chart options. This function is also available from the jQuery plugin as $(element).highcharts('SparkLine').
869                                      */
870                                      Highcharts.SparkLine = function (a, b, c) {
871                                      var hasRenderToArg = typeof a === 'string' || a.nodeName,
872                                      options = arguments[hasRenderToArg ? 1 : 0],
873                                       defaultOptions = {
874                                       chart: {
875                                       renderTo: (options.chart && options.chart.renderTo) || this,
876                                       backgroundColor: null,
877                                       borderWidth: 0,
878                                       type: 'line',
879                                       margin: [2, 0, 2, 0],
880                                       width: 100,
881                                       height: 40,
882                                       style: {
883                                          overflow: 'visible'
884                                       },
885                                       lineWidth: 2,
886                                       lineColor: 'red',
887                                       skipClone: true
888                                       },
889                                       title: {
890                                       text: ''
891                                       },
892                                       credits: {
893                                       enabled: false
894                                       },
895                                       navigation: {
896                                           buttonOptions: {
897                                           enabled: false,
898                                           symbolStroke: '#DDDDDD',
899                                           theme: {
900                                           fill: '#e3e3e3'
901                                           }
902                                           }
903                                       },
904                                       xAxis: {
905                                           labels: {
906                                           enabled: false
907                                           },
908                                       title: {
909                                       text: null
910                                       },
911                                       startOnTick: false,
912                                       endOnTick: false,
913                                       lineColor: 'transparent',
914                                       tickPositions: []
915                                        },
916                                        yAxis: {
917                                       endOnTick: false,
918                                       startOnTick: false,
919                                       labels: {
920                                        enabled: false
921                                       },
922                                       title: {
923                                       text: null
924                                        },
925                                       gridLineColor: 'transparent',
926                                       plotLines: [{
927                                        value: lastValue,
928                                        width: 1,
929                                        color: '#aaa'
930                                      }],
931                                       tickPositions: []
932                                       },
933                                        legend: {
934                                          enabled: false
935                                         },
936                                        tooltip: {
937                                         enabled: true,
938                                         backgroundColor: null,
939                                          borderWidth: 0,
940                                          shadow: false,
941                                          useHTML: true,
942                                         hideDelay: 0,
943                                         shared: true,
944                                         padding: 0,
945                                         positioner: function (w, h, point) {
946                                           return { x: point.plotX - w / 2, y: point.plotY - h };
947                                         }
948                                         },
949                                         plotOptions: {
950                                           series: {
951                                          animation: false,
952                                           lineWidth: 1,
953                                            shadow: false,
954                                           color: color,
955                                            states: {
956                                           hover: {
957                                               lineWidth: 1
958                                            }
959                                           },
960                                           marker: {
961                                             radius: 1,
962                                             states: {
963                                                hover: {
964                                                radius: 2
965                                                }
966                                                }
967                                            },
968                                            fillOpacity: 0.25
969                                           },
970                                           column: {
971                                              negativeColor: '#910000',
972                                              borderColor: 'silver'
973                                              }
974                                            }
975                                           };
976
977                                           options = Highcharts.merge(defaultOptions, options);
978
979                                           return hasRenderToArg ?
980                                           new Highcharts.Chart(a, options, c) :
981                                           new Highcharts.Chart(options, b);
982                                           };
983
984                                           var start = +new Date(),
985                                            $tds = $('div[data-sparkline]'),
986                                            fullLen = $tds.length,
987                                            n = 0;
988
989                                         // Creating 153 sparkline charts is quite fast in modern browsers, but IE8 and mobile
990                                        // can take some seconds, so we split the input into chunks and apply them in timeouts
991                                         // in order avoid locking up the browser process and allow interaction.
992                                         function doChunk() {
993                                            var time = +new Date(),
994                                                i,
995                                                len = $tds.length,
996                                            $td,
997                                                stringdata,
998                                                lastvalue,
999                                                colorvalue,
1000                                                 arr,
1001                                                 data,
1002                                                 chart;
1003
1004                                              for (i = 0; i < len; i += 1) {
1005                                                  $td = $($tds[i]);
1006                                                 stringdata = $td.data('sparkline');
1007                                                 lastvalue = $td.data('lastvalue');
1008                                                 colorvalue = $td.data('colorvalue');
1009                                                 arr = stringdata.split('; ');
1010                                                  data = $.map(arr[0].split(', '), parseFloat);
1011                                                chart = {};
1012                                                if (arr[1]) {
1013                                                     chart.type = arr[1];
1014                                                 }
1015                                                 $td.highcharts('SparkLine', {
1016                                                     series: [{
1017                                                        data: data,
1018                                                         pointStart: 1
1019                                                    }],
1020                                                     tooltip: {
1021                                                         headerFormat: '',
1022                                                         pointFormat: '<b>{point.y}</b>'
1023                                                     },
1024                                                     plotOptions: {
1025                                                           series: {
1026                                                          animation: false,
1027                                                             lineWidth: 1,
1028                                                             shadow: false,
1029                                                             color: colorvalue
1030                                                             }
1031                                                             },
1032                                                              yAxis: {
1033
1034                                                                  plotLines: [{
1035                                                                       value: lastvalue,
1036                                                                       width: 1,
1037                                                                       color: '#aaa'
1038                                                                       }],
1039                                                                    },
1040                                                                    chart: chart
1041                                                                });
1042
1043                                                                n += 1;
1044                                                                // If the process takes too much time, run a timeout to allow interaction with the browser
1045                                                  if (new Date() - time > 500) {
1046                                                      $tds.splice(0, i + 1);
1047                                                      setTimeout(doChunk, 0);
1048                                                       break;
1049                                                     }
1050
1051                             // Print a feedback on the performance
1052                             if (n === fullLen) {
1053                               $('#result').html('Generated ' + fullLen + ' sparklines in ' + (new Date() - start) + ' ms');
1054                               }
1055                            }
1056                        }
1057                          doChunk();
1058                        }
1059                        }
1060                        });
1061                        });
1062        },
1063        initDetailIndex:function(){
1064            /* Initialisation of the mini-charts */
1065            Solid.initMiniChartsIntraday();
1066
1067            /* Initialisation of the bar chart scripts */
1068            Solid.convertBarcharts();
1069
1070            /* Initialisation of the tooltip */
1071            $('[data-bs-toggle="tooltip"]').tooltip({html:true});
1072
1073            Solid.patchLightboxAjaxLinks($("a.lightBoxAjaxLink"));
1074        },
1075        initTheScreenerPortfolioChart:function(name, reference){
1076            var lang = document.documentElement.lang;
1077            if(!lang){
1078                lang = "en";
1079            }
1080            /* Check if all the variables are here */
1081            if(Highcharts && name && reference){
1082                /* Initialize the time series */
1083                var timeSeries = {};
1084
1085                /* The list of dropdown items */
1086                var $dropdownItems = $('.webfg-select-box a.dropdown-item');
1087
1088                /* The list of performance tables */
1089                var $performanceTables = $('table.thescreener-portfolio-performance');
1090
1091                /* The dropdown button*/
1092                var $dropdownBtn = $('button.dropdown-toggle span');
1093
1094                /* Add the cumulated performances if we have data */
1095                if(cumperfTimeSeriesPf && cumperfTimeSeriesRef){
1096                    timeSeries.cum = { pf:cumperfTimeSeriesPf, ref:cumperfTimeSeriesRef, type:'line' };
1097                }
1098
1099                /* Add the yearly performance if we have data */
1100                if(yearlyperfTimeSeriesPf && yearlyperfTimeSeriesRef){
1101                    timeSeries.yearly = { pf:yearlyperfTimeSeriesPf, ref:yearlyperfTimeSeriesRef, type:'column' };
1102                }
1103
1104                /* Add the monthly performance if we have data */
1105                if(yearlyperfTimeSeriesPf && yearlyperfTimeSeriesRef){
1106                    timeSeries.monthly = { pf:monthlyperfTimeSeriesPf, ref:monthlyperfTimeSeriesRef, type:'column' };
1107                }
1108                var langChart = document.documentElement.lang.trim().replace(/_/g, '-');
1109                if(lang === "de" || lang === "de_CH" || lang === "de_DE") {
1110                    Highcharts.setOptions({
1111                        lang: {
1112                            months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
1113                            weekdays: ['Sonntag', 'Montag', 'Die
1113nstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
1114                            shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],
1115                            decimalPoint: '.',
1116                            thousandsSep: "'",
1117                            rangeSelectorFrom: 'Von',
1118                            rangeSelectorTo: 'bis',
1119                            printChart: "Diagramm drucken",
1120                            downloadCSV:"CSV herunterladen",
1121                            downloadJPEG:"JPEG Bild herunterladen",
1122                            downloadPDF:"PDF Dokument herunterladen",
1123                            downloadPNG:"PNG Bild herunterladen",
1124                            downloadSVG:"SVG Vektor Bild herunterladen",
1125                            downloadXLS:"XLS herunterladen",
1126                            locale: langChart
1127
1128                        }
1129                    });
1130                }else if(lang === "fr" || lang === "fr_CH" || lang === "fr_FR"){
1131                    Highcharts.setOptions({
1132                        lang: {
1133                            months: ['Janvier','Février','Mars','Avril','Mai','Juin','Juillet','Août','Septembre','Octobre','Novembre','Décembre'],
1134                            weekdays: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
1135                            shortMonths: ['Janv','Fév','Mars','Avr','Mai','Juin','Juil','Août','Sep','Oct','Nov','Déc'],
1136                            decimalPoint: ',',
1137                            thousandsSep: ' ',
1138                            rangeSelectorFrom: 'De',
1139                            rangeSelectorTo: 'A',
1140                            printChart: "Imprimer le graphique",
1141                            downloadCSV:"Télécharger CSV",
1142                            downloadJPEG:"Télécharger l'image JPEG",
1143                            downloadPDF:"Télécharger le document PDF",
1144                            downloadPNG:"Télécharger l'image PNG",
1145                            downloadSVG:"Télécharger l'image vectorielle SVG",
1146                            downloadXLS:"Télécharger XLS",
1147                            locale: langChart
1148                        }
1149                    });
1150                }else if(lang === "it" || lang === "it_CH" || lang === "it_IT"){
1151                    Highcharts.setOptions({
1152                        lang: {
1153                            months: ['gennaio','febbraio','marzo','aprile','maggio','giugno','luglio','agosto','settembre','ottobre','novembre','dicembre'],
1154                            weekdays: ['domenica', 'lunedì', 'martedì', 'mercoledì', 'giovedì', 'venerdì', 'sabato'],
1155                            shortMonths: ['Gen','Feb','Mar','Apr','Mag','Giu','Lug','Ago','Set','Ott','Nov','Dic'],
1156                            decimalPoint: '.',
1157                            thousandsSep: "'",
1158                            rangeSelectorFrom: 'Da',
1159                            rangeSelectorTo: 'a',
1160                            printChart: "Stampa grafico",
1161                            downloadCSV:"Scarica CSV",
1162                            downloadJPEG:"Scarica l'immagine JPEG",
1163                            downloadPDF:"Scarica il documento PDF",
1164                            downloadPNG:"Scarica l'immagine PNG",
1165                            downloadSVG:"Scarica l'immagine vettoriale SVG",
1166                            downloadXLS:"Scarica XLS",
1167                            locale: langChart
1168                        }
1169                    });
1170                }else if(lang === "en"){
1171                    Highcharts.setOptions({
1172                        lang: {
1173                            decimalPoint: '.',
1174                            thousandsSep: ",",
1175                            locale: langChart
1176                        }
1177                    });
1178                }
1179
1180                // Create the chart
1181                var stockChart = Highcharts.stockChart('thescreener-portfolio-chart', {
1182                    legend: {
1183                        enabled: true,
1184                        align: 'center',
1185                        borderColor: '#dee2e6',
1186                        borderWidth: 1,
1187                        layout: 'horizontal',
1188                        verticalAlign: 'top',
1189                        y: 50
1190                    },
1191                    chart:{ height:500, type:'line' },
1192                    rangeSelector: { selected: 3 },
1193                    title: { text: '' },
1194                    series: [{
1195                        name: name,
1196                        data: timeSeries.cum.pf,
1197                        tooltip: {
1198                            valueDecimals: 2,
1199                            pointFormat: '<span style="color:{series.color}">\u25CF</span> {series.name}: <b>{point.y:,.2f} %</b><br/>',
1200                        }
1201                    },{
1202                        name: reference,
1203                        data: timeSeries.cum.ref,
1204                        tooltip: {
1205                            valueDecimals: 2,
1206                            pointFormat: '<span style="color:{series.color}">\u25CF</span> {series.name}: <b>{point.y:,.2f} %</b><br/>',
1207                        }
1208                    }]
1209                });
1210
1211                if($dropdownItems && $performanceTables){
1212                    /* Event handler for the chart select box */
1213                    $dropdownItems.each(function(){
1214                        $(this).on('click', function(){
1215                            /* Set the selected element */
1216                            var element = $(this).data('element');
1217
1218                            /* Set the text of the dropdown button correctly */
1219                            if($dropdownBtn){
1220                                $dropdownBtn.text($(this).text());
1221                            }
1222
1223                            /* Proceed only if the selected time series exists */
1224                            if(element && timeSeries[element]){
1225                                stockChart.series[0].update({ type: timeSeries[element].type});
1226                                stockChart.series[1].update({ type: timeSeries[element].type});
1227                                stockChart.series[0].setData(timeSeries[element].pf, false);
1228                                stockChart.series[1].setData(timeSeries[element].ref, true);
1229
1230                                /* Compute the id of the table that should be displayed if it exist */
1231                                var id = 'thescreener-portfolio-' + element + '-performance';
1232
1233                                $performanceTables.each(function(){
1234                                    if($(this).attr('id') === id){
1235                                        $(this).show();
1236                                    }
1237                                    else {
1238                                        $(this).hide();
1239                                    }
1240                                });
1241                            }
1242                        });
1243                    });
1244                }
1245            }
1246        },
1247        initGlobalMarkets:function(){
1248            /* Initialisation of the bar chart scripts */
1249            Solid.convertBarcharts();
1250
1251            /* Initialisation of the mini charts */
1252            Solid.initMiniChartsIntraday();
1253
1254            /* Initialisation of the tooltip */
1255            $('[data-bs-toggle="tooltip"]').tooltip({html:true});
1256        },
1257        initFundinfoDocumentationPanel:function(){
1258
1259            var ajaxMe = $().trading().me();
1260            $.when(ajaxMe).then(function(dataMe){
1261             me = dataMe;
1262             $('#USER').val(me.userName);
1263             console.log("User information: ", me.userName);
1264            });
1265
1266            /* Initialisation of the mini-charts */
1267            Solid.initMiniChartsIntraday();
1268
1269            /* Initialisation of the tooltip */
1270            $('[data-bs-toggle="tooltip"]').tooltip({html:true});
1271
1272            /* Handle the documentation request */
1273            var $documentationForm = $('div#documentation-details-tabs-row form');
1274            if($documentationForm && $documentationForm.length > 0){
1275                $documentationForm.on('submit', function(e){
1276                    /* Don't explicitly send the form */
1277                    e.preventDefault();
1278
1279                    /* Duration of the fadeIn and fadeOut function */
1280                    var duration = 1500;
1281
1282                    /* Send the form via ajax */
1283                    $.ajax({
1284                        type: "POST",
1285                        url: $documentationForm.attr('action'),
1286                        data: $documentationForm.serialize(),
1287                        success: function(){
1288                            /* Code redundancy with the error callback, implement a function when you have enough time */
1289                            var $successElem = $('div#documentation-detail
1289s-tabs-row div.alert-success');
1290                            if($successElem && $successElem.length > 0){
1291                                $successElem.fadeIn(duration, function(){
1292                                    setTimeout(function(){
1293                                        $successElem.fadeOut(duration);
1294                                    }, 3000);
1295                                });
1296                            }
1297                        },
1298                        error:function(XMLHttpRequest, textStatus){
1299                            var $errorElem = $('div#documentation-details-tabs-row div.alert-danger');
1300                            if($errorElem && $errorElem.length > 0){
1301                                $errorElem.fadeIn(duration, function(){
1302                                    setTimeout(function(){
1303                                        $errorElem.fadeOut(duration);
1304                                    }, 3000);
1305                                });
1306                            }
1307                        }
1308                    });
1309                });
1310            }
1311        },
1312        initStreaming:function(ctx, pullID){
1313            if(ThemeManager && Streaming && ctx && pullID){
1314                ThemeManager.defaults({ themeUrl: ''});
1315
1316                var defaultColors = {
1317                    equal: { background: '#FFFF00' },
1318                    up: { background: '#00FF00' },
1319                    down: { background: '#FF0000' }
1320                };
1321
1322                function setColors(settings) {
1323                    settings = $.extend(true, defaultColors, settings);
1324                    Highlighter.setEffect('default', Highlighter.Effects.createHighlightEffect(settings.equal.background, settings.equal.text, 1500));
1325                    Highlighter.setEffect('highlightUp', Highlighter.Effects.createHighlightEffect(settings.up.background, settings.up.text, 1500));
1326                    Highlighter.setEffect('highlightDown', Highlighter.Effects.createHighlightEffect(settings.down.background, settings.down.text, 1500));
1327                }
1328
1329                if (window.ThemeManager) {
1330                    setColors(ThemeManager.register('highlighter', setColors));
1331                }
1332                else {
1333                    setColors({});
1334                }
1335                Streaming.init({
1336                    type: 'pull',
1337                    pullSettings: {
1338                        pullInterval: 10000,
1339                        pullURL: ctx + '/pull',
1340                        destroyURL: ctx + '/listing/stopPull',
1341                        settingsURL: ctx + '/listing/updatePull',
1342                        pullID: pullID
1343                    }
1344                });
1345
1346                // Add default renderer for all (value) fields ..
1347                Streaming.setDefaultRenderer({
1348                    isApplicable: function (field, entry) {
1349                        return entry === 'value';
1350                    },
1351                    adaptConfig: function (fieldConfig) {
1352                        // We need VAS / VAT data ..
1353                        fieldConfig.type = true;
1354                    },
1355                    prepareFieldEntry: function (/*fieldEntry*/) {
1356                        return false;
1357                    },
1358                    handleUpdate: function (fieldEntry, data/*, pluginConfig*/) {
1359                        if (data.vas === 339) {
1360                            // -> Deleted price ..
1361                            fieldEntry.cell.addClass('deleted').attr('title', 'price deleted');
1362                        }
1363                        else if (data.vas === 114) {
1364                            // -> Trade Temporaly stopped price ..
1365                            fieldEntry.cell.text('');
1366                            return true;
1367                        }
1368                        else {
1369                            fieldEntry.cell.removeClass('deleted').removeAttr('title');
1370                        }
1371                        return false; // Return false so normal rendering takes place ..
1372                    }
1373                });
1374                Streaming.debug = true;
1375                Streaming.convertAndSubscribe();
1376            }
1377            else{
1378                console.error("Could not initialize the streaming, some elements must be missing")
1379            }
1380        },
1381        submitDerivatives:function(baseUrl, requestValue, derivativesParameters, parameterName){
1382            /* Set the correct value before sending the request */
1383            if(requestValue) {
1384                derivativesParameters[parameterName] = requestValue;
1385
1386                /* Build the query string */
1387                var queryString = '?';
1388                var separator = '';
1389                for (var key in derivativesParameters) {
1390                    if (derivativesParameters.hasOwnProperty(key) && derivativesParameters[key] !== 'gui.issuer' && derivativesParameters[key]) {
1391                        queryString += separator + key + "=" + derivativesParameters[key];
1392                        if(!separator){
1393                            separator = '&';
1394                        }
1395                    }
1396                }
1397
1398                /* Call the new link */
1399                window.location = baseUrl + queryString;
1400            }
1401        },
1402        initDerivatives:function() {
1403            /* The parameters name */
1404            var derivativesParameters = {
1405                sortField: '',
1406                eusipaCategory: '',
1407                optionType: '',
1408                issuer:'',
1409                underlyer:''
1410            };
1411
1412            /* The fastsearch parameter name */
1413            var fastSearchParameters = {
1414                fields: 'M_NAME,M_SYMB,M_ISIN,M_MARKET:value:description,SC_GROUPED:value:description,M_CUR:value:description,MIC,EUSIPA,DOMICILE,M_BC',
1415                assetClasses:'EQU,IND,COM,CUR,BON,DIV,INT,LIQ',
1416                size:'5',
1417                useWildcards:'true',
1418                mouseOnPanel:false,
1419                mouseOnSearchInput:false
1420            };
1421
1422            /* Isolate the dropdown elements */
1423            var $selectBox = $('div.webfg-select-box');
1424
1425            /* Basic check */
1426            if($selectBox && $selectBox.length > 0){
1427                /* Initialisation of the parameters */
1428                $selectBox.each(function() {
1429                    /* Get the key / value pair out of the element and set them */
1430                    var parameterName = $(this).find('button').data('param');
1431                    var parameterValue = $(this).find('button').data('selected');
1432                    if(parameterName && parameterValue){
1433                        derivativesParameters[parameterName] = parameterValue;
1434
1435                        $(this).find('a.dropdown-item').each(function(){
1436                            $(this).on('click', function(e){
1437                                /* Do nothing on click */
1438                                e.preventDefault();
1439
1440                                /* Check upon the current underlyer */
1441                                if(!$underlyingInput.val() || $underlyingInput.val().length <= 0){
1442                                    $underlyingInput.data('underlying-id', '');
1443                                    derivativesParameters.underlyer = '';
1444                                }
1445
1446                                /* Submit the form with all the values */
1447                                Solid.submitDerivatives(
1448                                    $(this).attr('href'),
1449                                    $(this).data('element'),
1450                                    derivativesParameters,
1451                                    parameterName
1452                                );
1453                            });
1454                        });
1455                    }
1456                });
1457            }
1458
1459            /* The elements needed to make the search of underlying available */
1460            var $underlyingRow = $('div#derivatives-underlying-row');
1461            var $body = $('body');
1462            if($underlyingRow && $underlyingRow.length > 0 && $body && $body.length > 0){
1463                var $underlyingInput = $underlyingRow.find('input');
1464                var $underlyingPanel = $underlyingRow.find('div.derivatives-underlying-results-panel');
1465
1466                /* This snippet sets the underlying id (listing id) if needed */
1467                var underlyingId = $underlyingInput.data('underlying-id');
1468                if(underlyingId && underlyingId.length > 0){
1469                    derivativesParameters.underlyer = underlyingId;
1470                }
1471
1472                /* This snippet will decide whether the search results panel must be displayed */
1473                $body.on('click', function(){
1474                    if(!fastSearchParameters.mouseOnPanel && $underlyingPanel.find('table').length > 0){
1475                        $underlyingPanel.addClass('d-none');
1476                    }
1477                });
1478
1479                if($underlyingInput && $underlyingPanel){
1480                    /* Will contain the ajax request */
1481                    var ajaxRequest;
1482
1483                    /* Add an on mouse over and on mouse out event handler to the panel */
1484                    $underlyingPanel.on('mouseover', function(){
1485                        fastSearchParameters.mouseOnPanel = true;
1486                    });
1487
1488                    $underlyingPanel.on('mouseout', function(){
1489                        fastSearchParameters.mouseOnPanel = false;
1490                    });
1491
1492                    /* Add a key pressed listener to the input field */
1493                    $underlyingInput.on('keyup', function() {
1494                        /* Cancel the ajax request */
1495                        if(ajaxRequest){
1496                            ajaxRequest.abort();
1497                        }
1498
1499                        /* Retrieve the value from the input field */
1500                        var searchTerm = $underlyingInput.val();
1501
1502                        /* Proceed if the patter matches */
1503                        if (searchTerm.match(/[a-zA-Z\.]{3,}/)) {
1504                            /* The base URL */
1505                            var url = $underlyingInput.data('url');
1506                            if(url){
1507                            /* The request parameters (hardcoded, I know it's not good ;-) )*/
1508                            var queryString = 'fields=' + fastSearchParameters.fields + "&flavor=" + fastSearchParameters.assetClasses;
1509                            queryString += '&size=' + fastSearchParameters.size + '&useWildcards=' + fastSearchParameters.useWildcards;
1510                            queryString += '&searchTerm=' + searchTerm + '&showMoreResults=false';
1511
1512                            ajaxRequest = $.ajax({
1513                                url:url + '?' + queryString,
1514                                success: function(data){
1515                                    /* The element that will contain the table */
1516                                    $underlyingPanel.find('.row .col').html(data);
1517
1518                                    /* Compute the position of the element that will be displayed */
1519                                    var underlyingInputPosition = $underlyingInput.position();
1520                                    var top = underlyingInputPosition.top + $underlyingInput.height() + 15;
1521                                    var left = (underlyingInputPosition.left + $underlyingInput.width()) - $underlyingPanel.width() - 15;
1522
1523                                    /* Add the mandatory css to the underlying panel */
1524                                    $underlyingPanel.css('position', 'absolute');
1525                                    $underlyingPanel.css('top',  top + 'px');
1526                                    $underlyingPanel.css('left', left + 'px');
1527
1528                                    /* Add an event handler to all the table rows */
1529                                    $underlyingPanel.find('table tbody tr').each(function(){
1530                                        $(this).on('click', function(){
1531                                            /* Get the listing id out of the table */
1532                                            var requestValue = $(this).data('listing');
1533
1534                                            /* Submit the values to get the new list of derivatives */
1535                                            Solid.submitDerivatives(
1536                                                $underlyingPanel.data('url'),
1537                                                requestValue,
1538                                                derivativesParameters,
1539                                                'underlyer'
1540                                            );
1541                                        });
1542                                    });
1543
1544                                    /* Show the panel */
1545                                    $underlyingPanel.removeClass('d-none');
1546                                }
1547                            });
1548                            }
1549                        }
1550                    });
1551                }
1552            }
1553        },
1554        initPreferences:function(){
1555            /* Check for the presence of the success div and get it's landingpage data attribute */
1556            var $successElem = $('div.webfg.row').find('div.alert-success');
1557            if($successElem && $successElem.length > 0) {
1558                var url = $successElem.data('landingpage');
1559                /* If the URL has been set redirect the user to the correct page */
1560                if(url && url.length > 0){
1561                    setTimeout(function(){
1562                        window.location = url;
1563                    }, 10000);
1564                }
1565            }
1566
1567            var $showDisclaimerSelectbox = $('div.webfg form#preferences-form select#showDisclaimer');
1568            var $showDisclaimerDialog = $('div.webfg form#preferences-form div#showDisclaimerDialog');
1569            if($showDisclaimerSelectbox){
1570                var val = ($showDisclaimerSelectbox.val() === 'true');
1571                if (val){
1572                    $showDisclaimerDialog.hide();
1573                }else{
1574                    $showDisclaimerDialog.show();
1575                }
1576                $showDisclaimerSelectbox.on('change', function () {
1577                    var val = ($showDisclaimerSelectbox.val() === 'true');
1578                    if (val){
1579                        $showDisclaimerDialog.hide();
1580                    }else{
1581                        $showDisclaimerDialog.show();
1582                    }
1583                });
1584            }
1585
1586            var $showCBOESelectbox = $('div.webfg form#preferences-form select#showCBOE');
1587            var $showCBOEDialog = $('div.webfg form#preferences-form div#showCBOEDialog');
1588            if($showCBOESelectbox){
1589                var val = ($showCBOESelectbox.val() === 'true');
1590                if (val){
1591                    $showCBOEDialog.show();
1592                }else{
1593                    $showCBOEDialog.hide();
1594                }
1595                $showCBOESelectbox.on('change', function () {
1596                    var val = ($showCBOESelectbox.val() === 'true');
1597                    if (val){
1598                        $showCBOEDialog.show();
1599                    }else{
1600                        $showCBOEDialog.hide();
1601                    }
1602                });
1603            }
1604
1605            /* Gets the 'defaultAccount' select box */
1606            var $defaultDepositSelectbox = $('div.webfg form#preferences-form select#defaultDeposit');
1607            if($defaultDepositSelectbox){
1608                var $defaultAccountBalance = $('span#defaultAccountBalance');
1609
1610                /* The id of the default deposit */
1611                var selectedDefaultDeposit = $defaultDepositSelectbox.data('currentdefaultdeposit');
1612
1613                /* Get fetch the list of portfolios */
1614                var portfolios = $().trading().portfolios();
1615                $.when(portfolios).done(function(portfolioList) {
1616                    if (portfolioList && $.isArray(portfolioList)) {
1617                        $.each(portfolioList, function(index, value){
1618                            /* The portfolio id */
1619                            var productId = value["productId"];
1620
1621                            /* The portfolio owner must also be part of the select box */
1622                            var portfolioOwnerObj = value["owner"]["shortName"];
1623                            var portfolioOwner = portfolioOwnerObj ? portfolioOwnerObj : '';
1624
1625                            /* Defines whether or not the current portfolio is the selected one */
1626                            var selected = selectedDefaultDeposit !== undefined && selectedDefaultDeposit !== '' && productId === selectedDefaultDeposit;
1627
1628                            /* Create the option element */
1629                            var selectedText = selected ? 'selected' : '';
1630                            var optionText = value["formattedNumber"] + ' - ' + portfolioOwner;
1631                            var optionOpen = '<option value="' + value["productId"] + '"' + selectedText + '>';
1632                            var optionClose = '</option>';
1633                            $defaultDepositSelectbox.append(optionOpen + optionText 
1633+ optionClose);
1634                        });
1635
1636                        /* Attach an event listener to the deposit select box */
1637                        $defaultDepositSelectbox.on('change', function(){
1638                            /* Remove the current options to replace them with the new one
1639                            $defaultAccountSelectbox.find('option').remove();*/
1640
1641                            /* Remove the account/deposit balance information */
1642                            $defaultAccountBalance.html('');
1643
1644                            /* Build the new option list */
1645                            var defaultDepositSelectboxVal = $defaultDepositSelectbox.val();
1646
1647                            /* Informs the client about the balance of the current deposit */
1648                            Solid.setPreferencesDepositBalance(defaultDepositSelectboxVal);
1649
1650
1651                        });
1652
1653                        /* Get the selected option in order to retrieve the correct accounts */
1654                        selectedDefaultDeposit = $defaultDepositSelectbox.val();
1655                        if(selectedDefaultDeposit === undefined || selectedDefaultDeposit === ''){
1656                            selectedDefaultDeposit = $defaultDepositSelectbox.prop("selectedIndex", 0).val();
1657                        }
1658
1659
1660                    }
1661                    else {
1662                        console.error("No portfolios could be retrieved")
1663                    }
1664                });
1665            }
1666        },
1667        formatNumber:function(value){
1668            value = parseFloat(value).toFixed(2);
1669            value += '';
1670            var x = value.split('.');
1671            var x1 = x[0];
1672            var x2 = x.length > 1 ? '.' + x[1] : '';
1673            var rgx = /(\d+)(\d{3})/;
1674            while (rgx.test(x1)) {
1675                x1 = x1.replace(rgx, '$1' + '\'' + '$2');
1676            }
1677            return x1 + x2;
1678        },
1679        setPreferencesDepositBalance:function(depositId){
1680            /* The span for which the balance will be set */
1681            var $defaultDepositBalance = $('span#defaultDepositBalance');
1682
1683            if($defaultDepositBalance){
1684                /* Reset the value */
1685                $defaultDepositBalance.html('');
1686
1687                /* Set the balance of the currently selected deposit */
1688                $.when($().trading().portfolio(depositId)).done(function(portfolio){
1689                    if(portfolio && portfolio.accountGroup && portfolio.depositDetail){
1690                        var balanceCurrency = portfolio.accountGroup.balance.currency.isoCode;
1691                        var evalValue = portfolio.depositDetail.evalValue.value;
1692                        $defaultDepositBalance.html(balanceCurrency + " " + Solid.formatNumber(evalValue));
1693                    }
1694                    else{
1695                        $defaultDepositBalance.html('');
1696                    }
1697                });
1698            }
1699        },
1700        activityWatcher:function(maxInactivityInMinutes, _publicHost) {
1701            /* Log the current timeout */
1702            console.info('Activity watcher has been set to: ' + maxInactivityInMinutes + ' minutes');
1703
1704            /* Copied from https://thisinterestsme.com/javascript-detect-user-activity/ */
1705
1706            /* The number of minutes that have passed since the user was active */
1707            let minutesSinceLastActivity = 0;
1708
1709            /* The maximum inactivity in minutes */
1710            let maxInactivity = (maxInactivityInMinutes);
1711
1712            /* Setup the setInterval method to run every second. 1000 milliseconds = 1 second */
1713            setInterval(function(){
1714                minutesSinceLastActivity++;
1715
1716                // Log only when approaching timeout , to avoid console spam.
1717                if (maxInactivity - minutesSinceLastActivity <= 2 ) {
1718                    console.log('User inactive for ' + minutesSinceLastActivity + ' minutes. Timeout in ' + (maxInactivity - minutesSinceLastActivity) + ' minutes.');
1719                }
1720
1721                /* If the user has been inactive or idle for longer then the seconds specified in maxInactivity */
1722                if(minutesSinceLastActivity > maxInactivity) {
1723                    console.info("The maximum allowed inactivity period has been reached! The user will now be logged out.");
1724                    let $logoutBtn = $('a.logOutLink');
1725                        if ($logoutBtn) {
1726                            checkLogout(_publicHost);
1727                        } else {
1728                            console.warn("Could not find the logout button!");
1729                        }
1730                }
1731            }, 60000);
1732
1733            /* The function that will be called whenever a user is active */
1734            function activity(){
1735                /*reset the secondsSinceLastActivity variable back to 0 */
1736                minutesSinceLastActivity = 0;
1737            }
1738
1739            /* An array of DOM events that should be interpreted as user activity */
1740            let activityEvents = ['mousedown', 'keydown', 'scroll', 'touchstart'];
1741
1742            /* Add these events to the document. register the activity function as the listener parameter */
1743            activityEvents.forEach(function(eventName) {
1744                document.addEventListener(eventName, activity, true);
1745            });
1746        },
1747        initStocksUpDown:function(){
1748            /* The request parameters for the theScreener stocks up / downgrades */
1749            var parameters = {
1750                country: '',
1751                sector: ''
1752            };
1753
1754            /* The table configuration */
1755            var tableConfig = {
1756                sort:false,
1757                autoPagingAndFiltering: false,
1758                pagination: true,
1759                displayLength: 10
1760            };
1761
1762            /* The list of select boxes */
1763            $("div#thescreener-stocks-up-title-row div.webfg-select-box").each(function(){
1764                var paramName = $(this).find('button').data('param');
1765                var selected = $(this).find('button').data('selected');
1766
1767                if(paramName && paramName.length > 0){
1768                    parameters[paramName] = selected ? selected : "";
1769
1770                    $(this).find('div.dropdown-menu a').each(function(){
1771                        $(this).on('click', function(e){
1772                            e.preventDefault();
1773
1774                            /* Get the value of the currently selected element and set the parameters object */
1775                            var paramValue = $(this).data('element');
1776                            parameters[paramName] = paramValue ? paramValue : "";
1777
1778                            /* Build the query string */
1779                            var qs = '';
1780                            for(var key in parameters){
1781                                if(qs !== ''){
1782                                    qs += '&'
1783                                }
1784                                qs += key + "=" + parameters[key];
1785                            }
1786
1787                            /* Redirect to the requested page */
1788                            window.location = $(this).attr('href') + '?' + qs;
1789                        });
1790                    });
1791                }
1792            });
1793
1794            /* Add pagination to the tables */
1795            $('div#thescreener-stocks-up-row table').solidTable(tableConfig);
1796            $('div#thescreener-stocks-down-row table').solidTable(tableConfig);
1797
1798            /* Initialisation of the tooltip */
1799            $('[data-bs-toggle="tooltip"]').tooltip({trigger: 'hover',
1800                html: true,
1801                placement: 'bottom',
1802                sanitize: false});
1803        },
1804        initTradingOpportunities:function(type){
1805            /* The request parameters for the theScreener stocks up / downgrades */
1806            var parameters = {
1807                country: '',
1808                sector: ''
1809            };
1810
1811            /* The type of list that we want to display */
1812            if(type){
1813                $('a#tab' + type).trigger('click');
1814            }
1815
1816            /* The list of select boxes */
1817            $("div#thescreener-trading-opportunities-select-box-row div.webfg-select-box").each(function(){
1818                var paramName = $(this).find('button').data('param');
1819                var selected = $(this).find('button').data('selected');
1820
1821                if(paramName && paramName.length > 0){
1822                    parameters[paramName] = selected ? selected : "";
1823
1824                    $(this).find('div.dropdown-menu a').each(function(){
1825                        $(this).on('click', function(e){
1826                            e.preventDefault();
1827
1828                            /* Get the value of the currently selected element and set the parameters object */
1829                            var paramValue = $(this).data('element');
1830                            parameters[paramName] = paramValue ? paramValue : "";
1831
1832                            /* Build the query string */
1833                            var qs = '';
1834                            for(var key in parameters){
1835                                if(qs !== ''){
1836                                    qs += '&'
1837                                }
1838                                qs += key + "=" + parameters[key];
1839                            }
1840
1841                            /* Redirect to the requested page */
1842                            window.location = $(this).attr('href') + '?' + qs;
1843                        });
1844                    });
1845                }
1846            });
1847
1848            $('[data-bs-toggle="tooltip"]').tooltip({html:true});
1849        },
1850        handleWebfgContextMenu:function(){
1851            //need a click event hanlder for clicks outside the context menu
1852            var $dim = $("body > .surrogate") === true ? $("body > .surrogate") : $("<div class='surrogate'></div>").prependTo("body");
1853
1854            var $contextMenuElem = $('div.webfg-context-menu');
1855            $contextMenuElem.click(function(e) {
1856                /* Prevent the actual action from being triggered */
1857                //e.preventDefault();
1858                var $thisMenu = $(this).find(".contextMenu");
1859                var $otherMenu = $(".contextMenu").not($thisMenu);
1860                //Close all other dropdowns
1861                $otherMenu.removeClass("open");
1862
1863                if($thisMenu.hasClass("open")) {
1864                    //close this menu
1865                    $thisMenu.removeClass("open");
1866                } else {
1867                    //open this menu
1868                    $thisMenu.addClass("open");
1869                    $(".surrogate").addClass("active");
1870                }
1871
1872            });
1873            //the offcontext click is triggered
1874            $(".surrogate").click(function(e){
1875                $(".surrogate").removeClass("active");
1876                $(".contextMenu").removeClass("open");
1877            });
1878            //A function within the context menu was clicked
1879            $(".contextMenu a").click(function(e){
1880                $(".surrogate").removeClass("active");
1881                $(".contextMenu").removeClass("open");
1882            });
1883
1884             /* Handling of the context menu
1885             if($contextMenuElem && $contextMenuElem.length > 0) {
1886                 $contextMenuElem.find('a.context-menu-toggle-link').on('click', function(e) {
1887                     /* Prevent the actual action from being triggered */
1888                   /* e.preventDefault();
1889                    $(this).siblings('div.contextMenu').toggle();
1890                });
1891            }*/
1892        },
1893        convertBarcharts: function (selector) {
1894            var cellSelectorClass = 'ytd_perf_pr';
1895            var barChartClass = 'barchart';
1896            ((selector === undefined) ? $('table') : (typeof selector === 'string' ? $(selector) : selector)).each(function () {
1897                var table = $(this);
1898                var isMainField = true;
1899                var containsNested = false;
1900                var barChartHeader = table.find('> thead > tr > th.' + cellSelectorClass);
1901                if (!barChartHeader.length) {
1902                    barChartHeader = table.find('> thead > tr > th.nested > div.nested > span.' + cellSelectorClass);
1903                    if (barChartHeader.length) {
1904                        isMainField = false;
1905                    } else {
1906                        // No BarChart in this table ..
1907                        return;
1908                    }
1909                } else {
1910                    containsNested = barChartHeader.hasClass('nested');
1911                }
1912                barChartHeader.addClass(barChartClass);
1913                if (table.hasClass('streamingTable')) {
1914                    // Update streaming renderer ..
1915                    if (barChartHeader.data('r') === 'default' || barChartHeader.data('r') === undefined) {
1916                        barChartHeader.data('r', 'BarChart');
1917                    }
1918                }
1919                var dataCells;
1920                if (isMainField) {
1921                    dataCells = table.find('> tbody > tr > td.' + cellSelectorClass);
1922                } else {
1923                    dataCells = table.find('> tbody > tr > td.nested > div.nested > span.' + cellSelectorClass);
1924                }
1925                var maxValue = 0;
1926                dataCells.each(function () {
1927                    var rawValue = parseFloat($(this).data('raw'));
1928                    if (!isNaN(rawValue)) {
1929                        $(this).data('parsed', rawValue);
1930                        //I dont get that....this guy made a master...but this code does not make sense to me....
1931                        if (rawValue < 0) {
1932                            rawValue = -rawValue;
1933                        }
1934                        if (rawValue > maxValue) {
1935                            maxValue = rawValue;
1936                        }
1937                    } else {
1938                        $(this).data('parsed', 0);
1939                    }
1940                }).addClass(barChartClass);
1941                if (maxValue > 0) {
1942                    dataCells.each(function () {
1943                        var cell = $(this), currentValue = cell.data('parsed');
1944                        var container = containsNested ? cell.find('> div:first') : cell;
1945                        container.attr('title', $.trim(container.text())).data('maxValue', maxValue).removeClass('pos neg eq').empty();
1946                        var html = isMainField ? '<div/>' : '<span/>';
1947                        var negBar = $(html).addClass("float-end barChartNeg").hide();
1948                        var posBar = $(html).addClass("float-start barChartPos").hide();
1949                        var cellTitle = cell.attr("title");
1950                        var cellTitleClass = 'pos';
1951                        if(currentValue < 0){
1952                            cellTitleClass = 'neg'
1953                        }
1954                        container
1955                            .append($(html).addClass(cellTitleClass).append(cellTitle))
1956                            .append($(html).addClass('width50P float-start').append(negBar))
1957                            .append($(html).addClass('width50P float-end').append(posBar))
1958                        if (currentValue > 0.0000001) {
1959                            posBar.css("width", Math.max(currentValue / maxValue * 100, 5).toFixed(0) + "%").show();
1960                        } else if (currentValue < -0.0000001) {
1961                            negBar.css("width", Math.max(-currentValue / maxValue * 100, 5).toFixed(0) + "%").show();
1962                        }
1963                    });
1964                }
1965            })
1966        },
1967        patchLightboxAjaxLinks: function (linkElements, defaultDialogOptions, defaultAjaxOptions, forceDataType) {
1968            linkElements.each(function (i, a) {
1969                a = $(a);
1970                if (a.data('patched')) {
1971                    return;
1972                }
1973                a.data('patched', true);
1974                var title = a.data('title');
1975                var loadingText = a.data('loading-text') || '';
1976                var dialogOptionsName = a.data('dialog-options') || defaultDialogOptions || '';
1977                var ajaxOptionsName = a.data('ajax-options') || defaultAjaxOptions || '';
1978                var dialogOptions = window[dialogOptionsName];
1979                if (!dialogOptions) {
1980                    dialogOptions = {};
1981                }
1982                var ajaxOptions = window[ajaxOptionsName];
1983                if (!ajaxOptions) {
1984                    ajaxOptions = {
1985                        error: function(jqXHR, textStatus, errorThrown) {
1986                            this.find('.modal-body').text(errorThrown);
1987                        }
1988                    };
1989                }
1990                if (forceDataType) {
1991                    ajaxOptions.dataType = forceDataType;
1992                }
1993                var url = a.attr('href');
1994                a.prop('href', '#');
1995                a.click(function (e) {
1996                    e.preventDefault();
1997                    e.stopPropagation();
1998                    // Bind lightbox ..
1999                    $.fn.lightBoxAjax({url: url, title: title, dialogOptions: dialogOptions, ajaxOptions: ajaxOptions, loadingText: loadingText});
2000                });
2001            });
2002        },
2003        initCBOE: function(cur, isin, market, isCBOE, portfolioId) {
2004            // The current currency, isin and marketId come from a solidListing!
2005            var ajaxUserPref = $().trading().userPreferences();
2006            $.when(ajaxUserPref).done(function (dataPref) {
2007                var userPreferences = Array.isArray(dataPref) ? dataPref[0] : dataPref;
2008                var ajaxTradingForm = $().trading().tradingForm(cur, isin, market, userPreferences.language, portfolioId);
2009                $.when(ajaxTradingForm).done(function (dataTradingForm) {
2010                    tradingForm = Array.isArray(dataTradingForm) ? dataTradingForm[0] : dataTradingForm;
2011                    cboeSpread = tradingForm.spreadCboeWarningShown;
2012
2013                    if (portfolioId != null && tradingForm.tradingPosition !== undefined) {
2014                        $('nav.nav-thirdLevel').hide();
2015                        if (tradingForm.tradingPosition.quantity !== undefined)
2016                            $('#quantityPosition').html(tradingForm.tradingPosition.quantity);
2017                        if (tradingForm.tradingPosition.available !== undefined)
2018                            $('#availablePosition').html(tradingForm.tradingPosition.available);
2019                        if (tradingForm.tradingPosition.value !== undefined && tradingForm.tradingPosition.value.value !== undefined)
2020                            $('#amountPosition').html(tradingForm.tradingPosition.value.value.toFixed(2) + ' ' + tradingForm.tradingPosition.value.currency.isoCode);
2021                        $('nav.nav-thirdLevel').show();
2022
2023                        if ($("#sellradio").is(":checked")) {
2024                            /* only for sell! set in quantity form if exist! */
2025                            var availablePosition = $('#availablePosition');
2026                            if (availablePosition.length > 0) {
2027                                $('#quantity').val(availablePosition.html());
2028                            }
2029                        }
2030                    }
2031
2032                    $('div.short-name.cboeQualifier').html(tradingForm.marketMapping.exchangeName);
2033                    if(tradingForm.showOsirisQuote) {
2034                        $('#lastQuoteValue').hide();
2035                        $('.lastQuoteDate').hide();
2036                        $('.nc2_subfield_data').hide();
2037                        const date = new Date(tradingForm.osirisQuote.price.date);
2038                        const year = date.getFullYear();
2039                        const month = (date.getMonth() + 1).toString().padStart(2, '0');
2040                        const day = date.getDate().toString().padStart(2, '0');
2041                        const lang = document.documentElement.lang;
2042                        if (lang.includes('en')) {
2043                            var englishFormathDate = month + '/' + day + '/' + year;
2044                            $('#osirisQuoteDate').html(englishFormathDate);
2045                            $('#osirisQuoteDate').show();
2046                        } else {
2047                            var otherFormatDate = day + '.' + month + '.' + year;
2048                            $('#osirisQuoteDate').html(otherFormatDate);
2049                            $('#osirisQuoteDate').show();
2050                        }
2051                        if (tradingForm.osirisQuote.price.isPercent == "true") {
2052                            $('#osirisQuoteValue').html(tradingForm.osirisQuote.price.value + '%');
2053                            $('#osirisQuoteValue').show();
2054                        } else {
2055                            $('#osirisQuoteValue').html(tradingForm.osirisQuote.price.amount.value);
2056                            $('#osirisQuoteValue').show();
2057                        }
2058                    }
2059
2060                    var $warningOrderTradingForm = $('#warningOrderTradingForm'); // already hide!
2061                    var $warningMsgOrderTradingForm = $('#warningMsgOrderTradingForm');
2062                    if(tradingForm.delayedOrderMarket){
2063                        $warningMsgOrderTradingForm.html(labelsError['delayedOrderMarket']);
2064                        $warningOrderTradingForm.show();
2065                    }else if(tradingForm.pennyStocksMarket){
2066                        $warningMsgOrderTradingForm.html(labelsError['pennyStocksMarket']);
2067                        $warningOrderTradingForm.show();
2068                    }
2069
2070                    if (isCBOE) {
2071                        var ajaxMe = $().trading().me();
2072                        $.when(ajaxMe).then(function (dataMe) {
2073                            var me = Array.isArray(dataMe) ? dataMe[0] : dataMe;
2074                            me.qualifiers.forEach(function (entry) {
2075                                if (entry.includes("CBOEQuotationEligible")) {
2076                                    cboeQualifier = true;
2077                                }
2078                            });
2079
2080                            if (userPreferences.showCBOE === true) {
2081                                cboePreferences = true;
2082                            }
2083                            //if CBOEQuotationEligible is false or CBOEQuotationEligible is available but isCBOE data is not
2084                            // available display old view
2085                            if (!cboeQualifier || (cboeQualifier && !isCBOE)) {
2086                                return;
2087                            } else {
2088                                if (cboeQualifier) {
2089                                    $('.cboe-div-container div.cboSwitch').show();
2090                                }
2091                                $('.cboe-span-dataType').show();
2092                            }
2093                            if (cboePreferences && cboeQualifier && isCBOE && !cboeExclusion) {
2094                                $('.cboe-div-container div.cboSwitch :checkbox').click();
2095                                $('.cboe-div-container span.market-tooltip-name button.cboe-tooltip-icon.spread-tooltip-off').show();
2096
2097                                if (cboeSpread) {
2098                                    $('h5.spread-h5').show();
2099                                    $('button.spread-tooltip-on').show();
2100                                    $('button.spread-tooltip-off').hide();
2101                                    $('div.spread').addClass('spread-div');
2102                                    $('table#index-details-header-table-cboe').addClass('spread-color');
2103                                    $('div.screenerBlock').addClass('spread-screenerBlock');
2104                                    $('#index-details-header-quotes-row.webfg .widthContainer #index-detail
2104s-header-table tbody tr td').addClass('spread-table-td');
2105                                    $('#index-details-header-quotes-row.webfg .widthContainer #index-details-header-table-cboe tbody tr td').addClass('spread-table-td');
2106                                }
2107                            } else if (((cboeExclusion && cboePreferences) || (!cboePreferences && !cboePreferences)) && cboeQualifier && isCBOE) {
2108                                $('.cboe-info-div h5.realTime').hide();
2109                                $('.cboe-info-div h5.defered').show();
2110                                $('.marketName').html(tradingForm.marketMapping.name);
2111                                $('.marketName').prop('title', tradingForm.marketMapping.name);
2112                            }
2113
2114
2115                        }).fail(function () {
2116                            console.log("No Data to display cboe");
2117                        });
2118                    }
2119                }).fail(function (xhr) {
2120                    $('div.market-tooltip-main.headerAlternative').show();
2121                    $('div.market-tooltip-main.headerAlternativeLogged').hide();
2122                    console.log("No Data to display tradingform");
2123                    tradingForm = {};
2124                    xhrSolid = xhr;
2125                });
2126            }).fail(function () {
2127                console.log("No Data to display userPreferences");
2128            });
2129        },
2130        switchCBOEFuncionality: function () {
2131            $('table.noCboe').removeClass('bt');
2132            $('table.isCboe').removeClass('bt');
2133            if($('.switch :checkbox').is(":checked")) {
2134                //display cboe table
2135                $('.isCboe').show();
2136                $('.noCboe').hide();
2137                //modify title for cboe table
2138                $('.marketName').html('CBOE');
2139                $('.marketName').prop('title', 'CBOE');
2140                //display realtime for cboe table
2141                $('table#index-details-header-table-cboe').show();
2142                $('table#index-details-header-table').hide();
2143                //change the trend arrow if is cbeo data
2144                $('div.webfg-trend.trendIsCBOE').show();
2145                $('div.webfg-trend.trendNoCBOE').hide();
2146                $('.cboe-info-div h5.timeCboe').show();
2147                $('.cboe-info-div h5.timeNormal').hide();
2148                //switch on or off the spread style.
2149                if(cboeSpread) {
2150                    $('h5.spread-h5').show();
2151                    $('button.spread-tooltip-on').show();
2152                    $('button.spread-tooltip-off').hide();
2153                    $('div.spread').addClass('spread-div');
2154                    $('table#index-details-header-table-cboe').addClass('spread-color');
2155                    $('div.screenerBlock').addClass('spread-screenerBlock');
2156                    $('#index-details-header-quotes-row.webfg .widthContainer #index-details-header-table tbody tr td').addClass('spread-table-td');
2157                    $('#index-details-header-quotes-row.webfg .widthContainer #index-details-header-table-cboe tbody tr td').addClass('spread-table-td');
2158                } else{
2159                    $('button.spread-tooltip-off').show();
2160                }
2161            } else {
2162                $('.noCboe').show();
2163                $('.isCboe').hide();
2164                $('.marketName').html(tradingForm.marketMapping.name);
2165                $('.marketName').prop('title', tradingForm.marketMapping.name);
2166                $('table#index-details-header-table-cboe').hide();
2167                $('table#index-details-header-table').show();
2168                $('div.webfg-trend.trendIsCBOE').hide();
2169                $('div.webfg-trend.trendNoCBOE').show();
2170                $('.cboe-info-div h5.timeCboe').hide();
2171                $('.cboe-info-div h5.timeNormal').show();
2172                if(cboeSpread) {
2173                    $('h5.spread-h5').hide();
2174                    $('button.spread-tooltip-on').hide();
2175                    $('div.spread').removeClass('spread-div');
2176                    $('table#index-details-header-table-cboe').removeClass('spread-color');
2177                    $('div.screenerBlock').removeClass('spread-screenerBlock');
2178                    $('#index-details-header-quotes-row.webfg .widthContainer #index-details-header-table tbody tr td').removeClass('spread-table-td');
2179                    $('#index-details-header-quotes-row.webfg .widthContainer #index-details-header-table-cboe tbody tr td').removeClass('spread-table-td');
2180                } else {
2181                    $('button.spread-tooltip-off').hide();
2182                }
2183            }
2184
2185        },
2186        returnPlaylist: function(hasPlaylistId){
2187            if(hasPlaylistId){
2188                $('nav.nav-thirdLevel.playlistNav').removeClass("d-none");
2189            }else{
2190                $('nav.nav-thirdLevel.playlistNav').addClass("d-none");
2191            }
2192
2193        }
2194    }
2195})(jQuery);
2196
2197var dialogOptionsNews = {
2198    //width:700,
2199    height:600,
2200    modal:true,
2201    draggable:false,
2202    resizable:false
2203};
2204
2205var dialogOptionsAddInstrument = {
2206    modal:true,
2207    height:400,
2208    width:600
2209};
2210
2211var modalDialogOptions = {
2212    modal:true
2213};
2214
2215var ajaxOptionsPortfolioAddInstrument = {
2216    success:function () {
2217        var forward = $('#context').val();
2218        $("#elasticSearch").solidFastSearch({
2219            query:{
2220                fields: "M_NAME,M_SYMB,M_ISIN,M_MARKET:value:description,SC_GROUPED:value:description,M_CUR:value:description,M_BC",
2221                flavor: "EQU,OPT,BON,FON,ETF,TFO",
2222                size: 15,
2223                useWildcards: true
2224            },
2225            action: function(context) {
2226                if (context.highlighted) {
2227                    var listingId = context.highlighted.data('listing');
2228                    if (listingId) {
2229                        window.location = Application.contextPath() + "/portfolio/add/instrumentToThisPortfolio/" + $("#portfolioId").val() + "/" + listingId +"?context="+forward;
2230                    }
2231                }
2232            },
2233            alignElement: $("#elasticSearch").closest('.input-group')
2234        });
2235    }
2236};
2237
2238var ajaxOptionsWatchlistAddInstrument = {
2239    success:function () {
2240        var path = "/watchlist/add/listing/";
2241        var suffix = '';
2242        if ($("#context").val() == "show") {
2243            suffix = '?context=show';
2244        }
2245        $("#elasticSearch").solidFastSearch({
2246            query:{
2247                fields: "M_NAME,M_SYMB,M_ISIN,M_MARKET:value:description,SC_GROUPED:value:description,M_CUR:value:description,M_BC",
2248                // Same flavors as in Solid.initElasticSearch ..
2249                flavor: "EQU,IND,BON,ETF,FON,TFO,CUR,COM,INT,OPT,DER,FUT,TER,CTR,DIV",
2250                size: 15,
2251                useWildcards: true
2252            },
2253            action: function(context) {
2254                if (context.highlighted) {
2255                    var listingId = context.highlighted.data('listing');
2256                    if (listingId) {
2257                        window.location = Application.contextPath() + path + $("#watchlistId").val() + "/" +
2258                            encodeURIComponent(listingId) + suffix;
2259                    }
2260                }
2261            },
2262            alignElement: $("#elasticSearch").closest('.input-group')
2263        });
2264    }
2265};
2266
2267var flyoutMenuSettings = {
2268    content:"Dummy Content",
2269    current:undefined,
2270    show:{
2271        solo: true,
2272        event:'mouseover'
2273    },
2274    hide:{
2275        fixed:true,
2276        delay:500
2277    },
2278    position:{
2279        viewport:$(window)
2280    },
2281    style:{
2282        classes:"ui-tooltip-blue ui-tooltip-no-padding",
2283        tip:{
2284            corner:false
2285        }
2286    }
2287};
2288(function ($) {
2289    'use strict';
2290    var DATA_KEY = '.solidTable';
2291
2292    var DEFAULTS = {
2293        autoPagingAndFiltering: true, // -> shorthand for {pagination: true, filtering: true}
2294        sDom: "<'row'<'col-sm-12'<'pull-right'f><'pull-left'l>r<'clearfix'>>>t<'row'<'col-sm-12'<'pull-left'i><'pull-right'p><'clearfix'>>>",
2295
2296        // Columns (custom settings) ..
2297        columns: undefined,
2298
2299        // Filtering ..
2300        filtering: false, // Don't use filtering by default .. (i.e. if autoPagingAndFiltering = false)
2301        filterDelay: 350,
2302        resetPageOnFiltering: false, // Set page to 0 on/after filtering ..
2303
2304        // Sorting ..
2305        sort: true,
2306        specifySortableColumns: false, // true = sortable columns must be specified explicitly, false = not sortable columns must be specified explicitly!
2307        sortingUrl: undefined,
2308        sortData: {}, // -> This is always sent to the server ..
2309        sortDataAttribute: 'raw',
2310        initiallySorted: false,
2311        indicesOnTop: true,
2312
2313        // Paging ..
2314        displayLength: 25,
2315        pagination: false, // Don't use paging by default .. (i.e. if autoPagingAndFiltering = false)
2316
2317        // Renderer for setRowData method ..
2318        rowRenderer: undefined,
2319        cellRenderer: undefined,
2320
2321        // Server-side paging & data ..
2322        dataUrl: undefined,
2323        totalLength: undefined,
2324
2325        // Could the data potentially change during lifecycle ..
2326        dynamicData: false,
2327
2328        oLanguage : {
2329            //sSearch: 'Search',
2330            oPaginate:{
2331                sPrevious: 'Previous',
2332                sNext: 'Next',
2333                sLast: 'Last',
2334                sFirst: 'First'
2335            },
2336            sInfoThousands: '\''//,
2337            //
2338            ////sLengthMenu:      'Show _MENU_ elements',
2339            //
2340            //sZeroRecords: 'No data', // -> Empty row text (due to filtering) ..
2341            //sEmptyTable: 'No data available in the table', // -> Empty-row text ..
2342            //
2343            //sInfo: '_START_ to _END_ of _TOTAL_  records',
2344            //sInfoEmpty: 'No entries',
2345            //sInfoFiltered: '(filtered out of _MAX_ entries)', // -> Suffix added to sInfo
2346            //sInfoPostFix: '',
2347            //sInfoThousands: '\'',
2348            //
2349            //
2350            //sLoadingRecords: 'Loading', // -> On ajax request ..
2351            //sProcessing: 'Please wait' // -> When sorting / filtering ..
2352        }
2353
2354        // TODO: Should we introduce a creation callback ?
2355    };
2356
2357    var methods = {
2358        setRowData: function(rowData, options) {
2359            var tableData = this.data(DATA_KEY);
2360            var body = createRows(tableData, rowData);
2361            var settings = $.extend({
2362                resetFilter: true,
2363                resetSort: false,
2364                resetPage: true
2365            }, options);
2366            // Update filtering ..
2367            tableData.rows = body.find('> tr');
2368            if (tableData.filter) {
2369                // Filtering feature is enabled ..
2370                if (settings.resetFilter) {
2371                    tableData.filter.clear();
2372                } else {
2373                    tableData.filter.update(true);
2374                }
2375            } else {
2376                // Simply set displayed rows to "all" rows ..
2377                tableData.displayRows = tableData.rows;
2378                tableData.filteredRows = $([]);
2379            }
2380            // Update pageCount ..
2381            if (tableData.pagination) {
2382                tableData.pagination.recalculate();
2383                // Show correct page ..
2384                if (settings.resetPage) {
2385                    tableData.pagination.setPage(0);
2386                } else {
2387                    tableData.pagination.updatePage();
2388                }
2389            }
2390            // Update sort ...
2391            if (tableData.sort) {
2392                var sortSettings = convertSortSettings(tableData.sort.columns, settings.dataSort);
2393                if (sortSettings) {
2394                    // Data is sorted -> give visual feedback ..
2395                    tableData.sort.setSorted(sortSettings.column, sortSettings.ascending);
2396                } else if (settings.resetSort) {
2397                    tableData.sort.setSorted();
2398                } else {
2399                    tableData.sort.update();
2400                }
2401            }
2402        },
2403        reload: function(overrides) {
2404            var tableData = this.data(DATA_KEY);
2405            if (tableData.settings.dataUrl) {
2406                // Reload data from server ..
2407                loadDataFromServer(tableData, overrides);
2408            }
2409        },
2410        destroy: function() {
2411            this.trigger('SolidTable.beforeDestroy');
2412            var tableData = this.data(DATA_KEY);
2413            tableData.rows.show();
2414            this.removeData(DATA_KEY);
2415            if (tableData.sort) {
2416                // Remove sort decoration from header ..
2417                tableData.sort.destroy();
2418            }
2419            if (tableData.filter) {
2420                // TODO: Destroy filter .. ?
2421            }
2422            if (tableData.pagination) {
2423                // TODO: Destroy pagination .. ?
2424            }
2425            tableData.table.insertBefore(tableData.rootElement);
2426            tableData.rootElement.remove();
2427            this.trigger('SolidTable.destroyed');
2428        }
2429    };
2430
2431    /**
2432     * SolidTable plugin.
2433     * @class SolidTable
2434     * @public
2435     * @memberOf $.fn
2436     * @param options
2437     * @returns {*|jQuery}
2438     */
2439    $.fn.solidTable = function (options) {
2440        if (typeof options === 'string') {
2441            if (methods[options]) {
2442                var args = Array.prototype.slice.call(arguments, 1);
2443                return this.each(function() {
2444                    var $table = $(this);
2445                    if (!$table.data(DATA_KEY)) {
2446                        $.error('Element is not a SolidTable: ' + this);
2447                    }
2448                    methods[options].apply($table, args);
2449                });
2450            } else {
2451                $.error('Invalid option: ' + options);
2452            }
2453        }
2454        var baseSettings = prepareBaseSettings(options);
2455        return this.each(function() {
2456            var $table = $(this);
2457            var settings = $.extend({}, baseSettings);
2458            var $rows = $table.find("> tbody > tr");
2459            var rowCount = $rows.length;
2460            if (settings.dataUrl) {
2461                if (settings.totalLength === undefined) {
2462                    $.error('SolidTable: totalLength must be set if dataUrl is set');
2463                }
2464                rowCount = settings.totalLength;
2465            }
2466            var multiplePage = rowCount > settings.displayLength;
2467            // Enable optional paging & filtering if necessary ..
2468            if (typeof settings.autoPagingAndFiltering === 'object') {
2469                if (settings.autoPagingAndFiltering.pagination) {
2470                    settings.pagination = multiplePage;
2471                }
2472                if (settings.autoPagingAndFiltering.filtering) {
2473                    settings.filtering = multiplePage;
2474                }
2475            } else if (settings.autoPagingAndFiltering) {
2476                settings.pagination = multiplePage;
2477                settings.filtering = multiplePage;
2478            }
2479            // Apply sort settings provided in table markup ..
2480            if ($table.data('sort') === 0) {
2481                // Disable sorting ...
2482                settings.sort = false;
2483            } else {
2484                if ($table.data('initial-sort')) {
2485                    // Apply initial sort settings ...
2486                    settings.initiallySorted = $table.data('initial-sort');
2487                    // Make sure no sort is triggered since data is already sorted!
2488                    settings.triggerSort = false;
2489                }
2490                if ($table.data('sort-key')) {
2491                    settings.sortData.sortKey = $table.data('sort-key');
2492                }
2493            }
2494            var tableData = {
2495                table: $table,
2496                rows: $rows,
2497                displayRows: $rows,
2498                filteredRows: $([]),
2499                settings: settings,
2500                currentPage: 0
2501            };
2502            tableData.rows.each(function(i) {
2503                if ($(this).data('fixed')) {
2504                    if (!tableData.fixed) {
2505                        tableData.fixed = [];
2506                    }
2507                    tableData.fixed.push({row: this, position: i});
2508                }
2509            });
2510            prepareGroups(tableData);
2511            $table.data(DATA_KEY, tableData);
2512            tableData.columns = extractColumnDefinitions(tableData);
2513            if (settings.sort) {
2514                tableData.sort = createSort(tableData);
2515            }
2516            if (settings.pagination || settings.dynamicData && isAutoPagination(settings)) {
2517                tableData.pagination = createPagination(tableData);
2518                if (settings.dynamicData && isAutoPagination(settings)  && !multiplePage) {
2519                    tableData.pagination.element.hide();
2520                }
2521            }
2522            if (settings.filtering) {
2523                tableData.filter = createFilter(tableData);
2524            }
2525            layoutElements(tableData);
2526            // TODO: Allow to load initial data from server ..
2527            if (tableData.pagination) {
2528                tableData.pagination.recalculate(); // Calculate number of pages ..
2529                if (!settings.dataUrl) {
2530                    tableData.pagination.setPage(0); // Update visible rows & paging visual state ..
2531                } else {
2532                    tableData.pagination.update(); // Update visual state of paging ..
2533                }
2534            }
2535            $table.trigger('SolidTable.created');
2536        });
2537    };
2538
2539    function prepareBaseSettings(options) {
2540        // Merge options using deep-merge ..
2541        var baseSettings = $.extend(true, {}, DEFAULTS, options);
2542        if (!baseSettings.sortCallback) {
2543            // Select default sort callback ..
2544            baseSettings.sortCallback = baseSettings.sortingUrl ? $.fn.solidTable.serverSideSort : $.fn.solidTable.defaultSort;
2545        }
2546        // Apply default renderers if none specified ..
2547        if (!baseSettings.rowRenderer) {
2548            baseSettings.rowRenderer = $.fn.solidTable.defaultRowRenderer;
2549            if (!baseSettings.cellRenderer) {
2550                baseSettings.cellRenderer = $.fn.solidTable.defaultCellRenderer;
2551            }
2552            if (!baseSettings.nestedCellRenderer) {
2553                baseSettings.nestedCellRenderer = $.fn.solidTable.defaultNestedCellRenderer;
2554            }
2555        }
2556        return baseSettings;
2557    }
2558
2559    function prepareGroups(tableData) {
2560        var bodyGroups = tableData.table.find('> tbody[data-group]');
2561        if (bodyGroups.length) {
2562            // There are groups ..
2563            var groups = [];
2564            bodyGroups.each(function(i, body) {
2565                var groupBody = $(body);
2566                var currentGroup;
2567                groupBody.find('> tr').each(function(i) {
2568                    if (i == 0) {
2569                        // The first row of a group is the "group title row" ..
2570                        groups.push(currentGroup = {
2571                            key: groupBody.data('group'),
2572                            groupBody: groupBody,
2573                            groupRow: this,
2574                            rows: []
2575                        });
2576                    } else {
2577                        if ($(this).data('fixed')) {
2578                            if (!currentGroup.fixed) {
2579                                currentGroup.fixed = [];
2580                            }
2581                            currentGroup.fixed.push({row: this, position: i - 1});
2582                        }
2583                        currentGroup.rows.push(this);
2584                    }
2585                });
2586            });
2587            tableData.groups = groups;
2588            // Disable paging ..
2589            tableData.settings.pagination = false;
2590        }
2591    }
2592
2593    function loadDataFromServer(tableData, overrides) {
2594        // Data-Tables compatible ajax request:
2595        tableData.table.trigger('SolidTable.beforeDataRequest');
2596        var pageNumber;
2597        if (overrides && overrides.pageNumber !== undefined) {
2598            pageNumber = overrides.pageNumber;
2599        } else {
2600            pageNumber = tableData.pagination ? tableData.pagination.getPage() : 0;
2601        }
2602        var sortColumn;
2603        var sortField;
2604        var sortDirection;
2605        var sortSettings;
2606        if (overrides && overrides.sortSettings !== undefined) {
2607            sortSettings = overrides.sortSettings;
2608        } else if (tableData.sort && tableData.sort.sortColumn) {
2609            sortSettings = tableData.sort.getSettings();
2610        }
2611        if (sortSettings) {
2612            sortColumn = sortSettings.column.index;
2613            sortField = sortSettings.column.fieldName;
2614            if (sortSettings.column.entry != 'value') {
2615                sortField += ':' + sortSettings.column.entry;
2616            }
2617            sortDirection = sortSettings.ascending ? 'asc' : 'desc';
2618        }
2619        var data = {
2620            iTotalRecords: tableData.settings.totalLength,
2621            iDisplayStart: pageNumber * tableData.settings.displayLength,
2622            iDisplayLength: tableData.settings.displayLength,
2623            iSortCol_0: sortColumn,
2624            sSortField_0: sortField,
2625            sSortDir_0: sortDirection,
2626            sSearch: tableData.filter ? tableData.filter.getFilter() : undefined,
2627            sEcho: 0
2628        };
2629        var customData = tableData.settings.dataAjaxOptions;
2630        if (typeof customData === 'function') {
2631            customData = tableData.settings.dataAjaxOptions(tableData, overrides);
2632        }
2633        var success = false;
2634        $.ajax($.extend(true, {
2635            type: "GET",
2636            url: tableData.settings.dataUrl,
2637            data: data
2638        }, customData, {
2639            success: function (data/*, textStatus, jqXHR*/) {
2640                if (data) {
2641                    var rowCountChanged = (tableData.settings.totalLength != data.iTotalDisplayRecords);
2642                    tableData.settings.totalLength = data.iTotalDisplayRecords;
2643                    var body = createRows(tableData, data.aaData);
2644                    // If data was requested from server, filtering is also done on server ..
2645                    tableData.displayRows = tableData.rows = body.find('> tr');
2646                    tableData.filteredRows = $([]);
2647
2648                    if (tableData.pagination) {
2649                        var oldPageCount = tableData.pageCount;
2650                        if (rowCountChanged) {
2651                            tableData.pagination.recalculate();
2652                        }
2653                        if (tableData.pagination.getPage() != pageNumber) {
2654                            // Page number was manually overridden ??
2655                            tableData.pagination.setPage(pageNumber, true);
2656                        } else if (rowCountChanged && oldPageCount != tableData.pageCount) {
2657                            //if (tableData.pagination.getPage() >= tableData.pageCount) {
2658                            //    // TODO: This should not be done here!!!
2659                            //    // Show first page!!
2660                            //    tableData.pagination.setPage(0);
2661                            //} else {
2662                            //    tableData.pagination.update();
2663                            //}
2664                            tableData.pagination.update();
2665                        }
2666                    }
2667                    tableData.table.trigger('SolidTable.dataRequested');
2668                    success = true;
2669                } else {
2670                    success = false;
2671                }
2672            },
2673            error: function() {
2674                tableData.table.trigger('SolidTable.dataRequestFailed');
2675            },
2676            async: false
2677        }));
2678        return success;
2679    }
2680
2681    function extractFieldName(cell, cellDefinition) {
2682        var fieldName = cell.data('k');
2683        if (fieldName) {
2684            // SOLID field ..
2685            var split = fieldName.split(':');
2686            var entry = 'value';
2687            if (split.length > 1) {
2688                fieldName = split[0];
2689                entry = split[1];
2690            }
2691            cellDefinition.fieldName = fieldName;
2692            cellDefinition.entry = entry;
2693        }
2694        return cellDefinition;
2695    }
2696
2697    function extractColumnDefinitions(tableData) {
2698        var columnSettings = tableData.settings.columns;
2699        var columns = [];
2700        var sortDefault = !tableData.settings.specifySortableColumns;
2701        tableData.table.find('thead > tr:first > th').each(function(idx) {
2702            var header = $(this);
2703            var columnDefinition = extractFieldName(header, {
2704                index: idx,
2705                element: header
2706            });
2707            if (header.data('sort') === 0) {
2708                // Sort was disabled in table markup ..
2709                columnDefinition.sortable = false;
2710            }
2711            var nestedFields, nestedFieldSeparator;
2712            if (header.hasClass('nested')) {
2713                nestedFields = [];
2714                header.find('> div.nested > .subfield').each(function(i) {
2715                    var cellElement = $(this);
2716                    nestedFields.push(extractFieldName(cellElement, {
2717                        index: i,
2718                        element: cellElement,
2719                        cssClass: cellElement.attr('class')
2720                    }));
2721                });
2722                if (nestedFields.length > 1) {
2723                    var current = nestedFields[0].element[0];
2724                    var end = nestedFields[1].element[0];
2725                    var separator = $('<div/>');
2726                    while (current.nextSibling && (current = current.nextSibling) !== end) {
2727                        separator.append(current.cloneNode(true));
2728                    }
2729                    nestedFieldSeparator = separator.html();
2730                }
2731            }
2732            var overrideSettings;
2733            if (columnSettings) {
2734                // User specified some (additional) column definitions ..
2735                overrideSettings = columnSettings[idx];
2736                if (!overrideSettings && columnDefinition.fieldName) {
2737                    var complexFieldKey = (columnDefinition.fieldName + ':' + columnDefinition.entry);
2738                    if (columnDefinition.entry === 'value') {
2739                        overrideSettings = columnSettings[columnDefinition.fieldName] || columnSettings[complexFieldKey];
2740                    } else {
2741                        overrideSettings = columnSettings[complexFieldKey];
2742                    }
2743                }
2744            }
2745            columns.push($.extend({
2746                // Default settings (can be overridden) ..
2747                sortable: sortDefault,
2748                sortType: 'natural',
2749                cssClass: header.attr('class'),
2750                nestedFields: nestedFields,
2751                nestedFieldSeparator: nestedFieldSeparator
2752            }, overrideSettings, columnDefinition));
2753        });
2754        return columns;
2755    }
2756
2757    // =========
2758    //  Sorting
2759    // =========
2760
2761    function createSort(tableData) {
2762        // Create column definitions ..
2763        var columns = tableData.columns;
2764        function sortCallback() {
2765            var colIdx = $(this).index();
2766            var columnInfo = tableData.sort.columns[colIdx];
2767            var isAscending = columnInfo.element.hasClass('sorting_asc');
2768            doSort(tableData, columnInfo, !isAscending);
2769        }
2770        $.each(columns, function() {
2771            if (!this.sortable) {
2772                // -> Not sortable ..
2773                return;
2774            }
2775            this.element.addClass('sorting').on('click', sortCallback);
2776            if (typeof $.fn.solidTable.sortValueExtractor[this.sortType] !== 'function') {
2777                $.error('Unsupported sort type: ' + this.sortType);
2778            }
2779        });
2780
2781        var settings = tableData.settings;
2782        var sortSettings = convertSortSettings(columns, settings.initiallySorted);
2783        if (sortSettings && sortSettings.column) {
2784            if (settings.triggerSort) {
2785                setTimeout(function() {
2786                    // Trigger sort ..
2787                    doSort(tableData, sortSettings.column, sortSettings.ascending);
2788                }, 0);
2789            } else {
2790                // Just mark specified column as sorted in correct order ..
2791                updateSortColumn(columns, sortSettings.column, sortSettings.ascending);
2792            }
2793        }
2794
2795        return {
2796            indicesOnTop: settings.indicesOnTop,
2797            columns: columns,
2798            sortColumn: sortSettings ? sortSettings.column : undefined,
2799            getSettings: function() {
2800                if (tableData.sort.sortColumn) {
2801                    return {
2802                        column: tableData.sort.sortColumn,
2803                        ascending: !tableData.sort.sortColumn.element.hasClass('sorting_desc')
2804                    };
2805                }
2806                return null;
2807            },
2808            sort: function(columnIndex) {
2809                if (columns[columnIndex]) {
2810                    sortCallback.call(columns[columnIndex].element);
2811                } else {
2812                    $.error("Not a sort column: " + columnIndex);
2813                }
2814            },
2815            update: function() {
2816                // Trigger sort on current sort-column without changing order (asc/desc) ..
2817                if (tableData.sort.sortColumn) {
2818                    var isAscending = tableData.sort.sortColumn.element.hasClass('sorting_asc');
2819                    doSort(tableData, tableData.sort.sortColumn, isAscending)
2820                }
2821            },
2822            setSorted: function(column, ascending) {
2823                // This function is called if the table content was entirely replaced ..
2824                // -> Simply adapt sort-mark of columns ..
2825                updateSortColumn(columns, column, ascending);
2826                tableData.sort.sortColumn = column;
2827            },
2828            destroy: function() {
2829                $.each(tableData.sort.columns, function() {
2830                    this.element.removeClass("sorting sorting_asc sorting_desc").off('click', sortCallback);
2831                });
2832                delete tableData.sort;
2833            }
2834        }
2835    }
2836
2837    function convertSortSettings(columns, sortSettings) {
2838        var columnIdx;
2839        var field;
2840        var entry = 'value';
2841        var ascending = true;
2842
2843        function applyField(unparsed) {
2844            field = unparsed;
2845            var split = field.split(':');
2846            if (split.length > 1) {
2847                field = split[0];
2848                if (split[1]) {
2849                    entry = split[1];
2850                }
2851                if (split.length > 2) {
2852                    ascending = 'desc' != split[2];
2853                }
2854            }
2855        }
2856
2857        if (sortSettings !== false && sortSettings !== undefined) {
2858            if (typeof sortSettings === 'object') {
2859                if (sortSettings instanceof Array) {
2860                    if (sortSettings.length > 0) {
2861                        if (typeof sortSettings[0] === 'number') {
2862                            columnIdx = sortSettings[0];
2863                            if (sortSettings.length > 1) {
2864                                ascending = 'desc' != sortSettings[1];
2865                            }
2866                        } else {
2867                            if (sortSettings.length > 2) {
2868                                // -> ['FIELD', 'entry', order]
2869                                field = sortSettings[0];
2870                                entry = sortSettings[1];
2871                                ascending = 'desc' != sortSettings[2];
2872                            } else if (sortSettings.length == 2) {
2873                                if (sortSettings[1] == 'asc' || sortSettings[1] == 'desc') {
2874                                    // -> ['FIELD', order], ['FIELD:entry', order]
2875                                    applyField(sortSettings[0]);
2876                                    ascending = 'desc' != sortSettings[1];
2877                                } else {
2878                                    // -> ['FIELD', 'entry'] ..
2879                                    field = sortSettings[0];
2880                                    entry = sortSettings[1];
2881                                }
2882                            } else {
2883                                // -> ['FIELD'], ['FIELD:entry'], ['FIELD:entry:order'] ..
2884                                applyField(sortSettings[0]);
2885                            }
2886                        }
2887                    }
2888                } else {
2889                    field = sortSettings.field;
2890                    entry = sortSettings.entry || 'value';
2891                    columnIdx = sortSettings.column;
2892                    ascending = 'desc' != sortSettings.order;
2893                }
2894            } else {
2895                if (typeof sortSettings === 'number') {
2896                    columnIdx = sortSettings;
2897                } else if (typeof sortSettings === 'string') {
2898                    applyField(sortSettings);
2899                }
2900            }
2901            var column;
2902            if (field) {
2903                // Must be a field name ..
2904                for (var i = 0; i < columns.length; ++i) {
2905                    if (columns[i] && columns[i].fieldName == field && columns[i].entry == entry) {
2906                        column = columns[i];
2907                        break;
2908                    }
2909                }
2910            } else if (columnIdx !== undefined) {
2911                // Must be a column number ..
2912                column = columns[columnIdx];
2913            }
2914            if (column && column.sortable) {
2915                return {
2916                    column: column,
2917                    ascending: ascending
2918                }
2919            }
2920        }
2921        return null;
2922    }
2923
2924    function doSort(tableData, columnInfo, ascending) {
2925        // Abort current sort operation (if any) ..
2926        if (tableData.sort.activeSort && tableData.sort.activeSort.abort) {
2927            tableData.sort.activeSort.abort();
2928        }
2929        tableData.table.trigger('SolidTable.beforeSort');
2930        if (tableData.settings.dataUrl) {
2931            // Special handling for server side paging / sorting ..
2932            // Load new data from server ..
2933            if (loadDataFromServer(tableData, {sortSettings: {
2934                    column: columnInfo,
2935                    ascending: !columnInfo.element.hasClass('sorting_asc')
2936                }})) {
2937                // Success -> Set new column as sort column ..
2938                tableData.sort.sortColumn = columnInfo;
2939                updateSortColumn(tableData.sort.columns, columnInfo, ascending);
2940                tableData.table.trigger('SolidTable.sorted');
2941            } else {
2942                // Server data request failed / was cancelled / ...
2943                tableData.table.trigger('SolidTable.sortCancelled');
2944            }
2945            return;
2946        }
2947
2948        var sortDone = false;
2949        var sortControl = tableData.settings.sortCallback.call(tableData.table, columnInfo.index, ascending, tableData, function(rows) {
2950            sortDone = true;
2951            if (tableData.sort.activeSort) {
2952                delete tableData.sort.activeSort;
2953            }
2954            if (rows !== false) {
2955                // Sort was successful ..
2956                // -> Update table ..
2957                if (tableData.groups) {
2958                    $.each(tableData.groups, function(i, group) {
2959                        group.rows = rows[i];
2960                        group.groupBody.append($(group.rows));
2961                    });
2962                } else {
2963                    tableData.rows = $(rows);
2964                    tableData.table.find('> tbody').append(tableData.rows);
2965                }
2966                // Set the new sort column ..
2967                tableData.sort.sortColumn = columnInfo;
2968                // Visualize sorting on correct column ..
2969                updateSortColumn(tableData.sort.columns, columnInfo, ascending);
2970                // Update filtering (if any) ..
2971                if (tableData.filter) {
2972                    tableData.filter.update();
2973                } else {
2974                    tableData.displayRows = tableData.rows;
2975                    tableData.filteredRows = $([]);
2976                }
2977                if (tableData.pagination) {
2978                    // Update the current page content ..
2979                    tableData.pagination.updatePage();
2980                }
2981                tableData.table.trigger('SolidTable.sorted');
2982            } else {
2983                tableData.table.trigger('SolidTable.sortCancelled');
2984            }
2985        });
2986        if (!sortDone) {
2987            // It's (probably) an asynchronous sort -> save control in order to allow aborting the active sort ..
2988            tableData.sort.activeSort = sortControl;
2989        }
2990    }
2991
2992    function updateSortColumn(columns, column, ascending) {
2993        // Reset any other sort ..
2994        for (var j = 0; j < columns.length; ++j) {
2995            if (columns[j]) {
2996                columns[j].element.removeClass('sorting_asc sorting_desc');
2997            }
2998        }
2999        if (column) {
3000            // Set correct order on specified column ..
3001            if (ascending) {
3002                column.element.addClass('sorting_asc');
3003            } else {
3004                column.element.addClass('sorting_desc');
3005            }
3006        }
3007    }
3008
3009    // Extract the value of a single cell used to sort the table rows ...
3010    $.fn.solidTable.sortValueExtractor = {
3011        natural: function(row, cell, columnInfo, tableData) {
3012            var value = cell.data(tableData.settings.sortDataAttribute);
3013            if (value === undefined) {
3014                value = $.trim(getTexts(cell[0], []).join(' ')).toLowerCase();
3015            } else if (typeof value === 'string') {
3016                value = value.toLowerCase();
3017            }
3018            return value;
3019        },
3020        string: function(row, cell, columnInfo, tableData) {
3021            var value = cell.data(tableData.settings.sortDataAttribute);
3022            if (value === undefined) {
3023                value = $.trim(getTexts(cell[0], []).join(' ')).toLowerCase();
3024            } else if (typeof value === 'string') {
3025                value = value.toLowerCase();
3026            } else {
3027                value = value.toString().toLowerCase();
3028            }
3029            return value;
3030        },
3031        date: function(row, cell, columnInfo, tableData) {
3032           var value = cell.data(tableData.settings.sortDataAttribute);
3033           if (value === undefined) {
3034               value = $.trim(getTexts(cell[0], []).join(' '));
3035               }
3036               var indices = [];
3037               if(value){
3038                   for(var i = 0; i < value.length; i++) {
3039                    if (value[i].toLowerCase() === "." || value[i].toLowerCase() === "/" ) indices.push(i);
3040                   }
3041               }
3042                  if(value && indices.length == 2 && value.includes('.')){
3043                        var day = value.split('.')[0];
3044                        var month = value.split('.')[1];
3045                        var year = value.split('.')[2];
3046                        return parseFloat(year+month+day);
3047                  }
3048                  else if(value && value.includes('/') && indices.length == 2){
3049                        var month = value.split('/')[0];
3050                        var day = value.split('/')[1];
3051                        var year = value.split('/')[2];
3052                        return parseFloat(year+month+day);
3053                  }
3054                  else{
3055                       value = value.toLowerCase();
3056                  }
3057
3058             return value;
3059        },
3060        dateTime: function(row, cell, columnInfo, tableData) {
3061            var value = cell.data(tableData.settings.sortDataAttribute);
3062            if (value === undefined) {
3063                value = $.trim(getTexts(cell[0], []).join(' '));
3064            }
3065
3066            if (!value) return value;
3067
3068            var parts = value.split(' ');
3069            var datePart = parts[0];
3070            var timePart = parts[1] || '00:00';
3071
3072            var timeComponents = timePart.split(':');
3073            var hours = timeComponents[0] || '00';
3074            var minutes = timeComponents[1] || '00';
3075
3076            var indices = [];
3077            for (var i = 0; i < datePart.length; i++) {
3078                if (datePart[i] === '.' || datePart[i] === '/') indices.push(i);
3079            }
3080
3081            var day, month, year;
3082
3083            if (datePart.includes('.') && indices.length == 2) {
3084                var dateParts = datePart.split('.');
3085                day = dateParts[0];
3086                month = dateParts[1];
3087                year = dateParts[2];
3088            } else if (datePart.includes('/') && indices.length == 2) {
3089                var dateParts = datePart.split('/');
3090                month = dateParts[0];
3091                day = dateParts[1];
3092                year = dateParts[2];
3093            } else {
3094                return value.toLowerCase();
3095            }
3096
3097            var dateObj = new Date(
3098                parseInt(year),
3099                parseInt(month) - 1,
3100                parseInt(day),
3101                parseInt(hours),
3102                parseInt(minutes)
3103            );
3104
3105            return dateObj.getTime();
3106        },
3107        numeric: (function() {
3108            function toNumber(strValue) {
3109                if(strValue == ""){
3110                    return 0;
3111                }
3112                // Undefined, empty string, or non numerical -> Set to: NaN
3113                // TODO: Improve number conversion .. (i.e. strip non-numerical characters) ..
3114                if(strValue.includes("(")){
3115                    strValue=strValue.split("(")[0];
3116                }
3117                //strValue=strValue.replaceAll('.','');
3118                strValue=strValue.replaceAll(',','');
3119                strValue=strValue.replaceAll('\'','');
3120
3121                let numValue = parseFloat(strValue);
3122                let units = 1;
3123                if(strValue.includes(" M")) units = 1000000;
3124                if(strValue.includes(" B")) units = 1000000000;
3125                if(strValue.includes(" Md")) units = 1000000000000;
3126
3127                let result = numValue * units;
3128                return result;
3129            }
3130
3131            return function(row, cell, columnInfo, tableData) {
3132                var value = cell.data(tableData.settings.sortDataAttribute);
3133                if (value === undefined) {
3134                    value = toNumber(getTexts(cell[0], []).join(' '));
3135                } else if (typeof value !== 'number') {
3136                    value = toNumber(value.toString());
3137                }
3138                return value;
3139            }
3140        })()
3141    };
3142
3143    $.fn.solidTable.defaultSortComparator = function(a, b, ascending) {
3144        return (ascending ? 1 : -1) * (a.value > b.value ? 1 : (a.value < b.value ? -1 : 0));
3145    };
3146
3147    $.fn.solidTable.defaultSort = function(colIdx, ascending, tableData, callback) {
3148        var columnInfo = tableData.sort.columns[colIdx];
3149        var valueExtractor = $.fn.solidTable.sortValueExtractor[columnInfo.sortType];
3150        // Get sort data for each row ..
3151        if (tableData.groups) {
3152            var groupRows = [];
3153            $.each(tableData.groups, function(idx, group) {
3154                groupRows.push(sortRows(group, tableData, colIdx, columnInfo, valueExtractor, ascending));
3155            });
3156            callback(groupRows);
3157        } else {
3158            callback(sortRows(tableData, tableData, colIdx, columnInfo, valueExtractor, ascending));
3159        }
3160    };
3161
3162    function sortRows(container, tableData, colIdx, columnInfo, valueExtractor, ascending) {
3163        var allData = [];
3164        $.each(container.rows, function() {
3165            var row = $(this);
3166            if (!row.data('fixed')) {
3167                var listingId = row.data('l');
3168                var instrType = row.data('t');
3169                var cell = row.find('> :eq(' + colIdx + ')');
3170                allData.push({
3171                    listingId: listingId,
3172                    instrType: instrType,
3173                    value: valueExtractor.call(tableData.table, row, cell, columnInfo, tableData),
3174                    row: this
3175                });
3176            }
3177        });
3178        // Sort array of sort data ..
3179        if (tableData.sort.indicesOnTop) {
3180            allData.sort(function(a, b) {
3181                if ((a.instrType === 'IND' || b.instrType === 'IND') && a.instrType !== b.instrType) {
3182                    return a.instrType === 'IND' ? -1 : 1;
3183                }
3184                return $.fn.solidTable.defaultSortComparator(a, b, ascending);
3185            });
3186        } else {
3187            allData.sort(function(a, b) {
3188                return $.fn.solidTable.defaultSortComparator(a, b, ascending);
3189            });
3190        }
3191        // Extract row elements from sort data ..
3192        var sortedRows = [];
3193        for (var i = 0; i < allData.length; ++i) {
3194            sortedRows.push(allData[i].row);
3195        }
3196        if (container.fixed) {
3197            $.each(container.fixed, function () {
3198                sortedRows.splice(this.position, 0, this.row);
3199            });
3200        }
3201        return sortedRows;
3202    }
3203
3204    $.fn.solidTable.serverSideSort = function(colIdx, ascending, tableData, callback) {
3205        var columnInfo = tableData.sort.columns[colIdx];
3206        var valueExtractor = $.fn.solidTable.sortValueExtractor[columnInfo.sortType];
3207        // Extract data ...
3208        var sortData;
3209        var rowLookup;
3210        if (tableData.groups) {
3211            rowLookup = {};
3212            sortData = {};
3213            $.each(tableData.groups, function(idx, group) {
3214                var groupRowLookup = rowLookup[group.key] = [];
3215                sortData[group.key] = extractServerSortData(group, groupRowLookup, tableData, colIdx, columnInfo, valueExtractor);
3216            });
3217        } else {
3218            rowLookup = [];
3219            sortData = extractServerSortData(tableData, rowLookup, tableData, colIdx, columnInfo, valueExtractor);
3220        }
3221        // Do server-side sorting ..
3222        var sortedRows = false;
3223        return $.ajax({
3224            type: "POST",
3225            url: tableData.settings.sortingUrl,
3226            data: $.extend({}, tableData.settings.sortData, {
3227                data: JSON.stringify(sortData),
3228                field: columnInfo.fieldName ? (columnInfo.fieldName + ':' + columnInfo.entry) : undefined,
3229                // indicesOnTop: true = indices on top, false = no special sorting ..
3230                indicesOnTop: tableData.sort.indicesOnTop,
3231                asc: ascending,
3232                grouped: !!tableData.groups
3233            }),
3234            success: function (data/*, textStatus, jqXHR*/) {
3235                // Apply sort order ..
3236                if (tableData.groups) {
3237                    var groupRows = [];
3238                    $.each(tableData.groups, function(idx, group) {
3239                        groupRows.push(applyServerSortOrder(group, data[group.key], rowLookup[group.key]));
3240                    });
3241                    callback(groupRows);
3242                } else {
3243                    callback(applyServerSortOrder(tableData, data, rowLookup));
3244                }
3245            },
3246            error: function() {
3247                // -> Returns false if there was an error ..
3248                callback(false);
3249            },
3250            async: true
3251        });
3252    };
3253
3254    function extractServerSortData(container, rowLookup, tableData, colIdx, columnInfo, valueExtractor) {
3255        var listingIds = [];
3256        var instrumentTypes = [];
3257        var cellValues = [];
3258        $.each(container.rows, function() {
3259            var row = $(this);
3260            if (!row.data('fixed')) {
3261                var lid = row.data('l');
3262                listingIds.push(lid);
3263                instrumentTypes.push(row.data('t'));
3264                var cell = row.find('> :eq(' + colIdx + ')');
3265                cellValues.push(valueExtractor.call(tableData.table, row, cell, columnInfo, tableData));
3266                rowLookup.push(this);
3267            }
3268        });
3269        return {
3270            listingIds: listingIds,
3271            instrumentTypes: instrumentTypes,
3272            values: cellValues
3273        };
3274    }
3275
3276    function applyServerSortOrder(container, data, rowLookup) {
3277        var sortedRows = [];
3278        $.each(data, function (i, index) {
3279            sortedRows.push(rowLookup[index]);
3280        });
3281        if (container.fixed) {
3282            $.each(container.fixed, function () {
3283                sortedRows.splice(this.position, 0, this.row);
3284            });
3285        }
3286        return sortedRows;
3287    }
3288
3289    function getTexts(node, texts) {
3290        if (node.nodeType == 3) {
3291            if (!/^[\s]*$/.test(node.nodeValue)) {
3292                // Split text by whitespaces and add to array of texts ..
3293                texts = texts.concat($.trim(node.nodeValue).split(/[\s]+/));
3294            }
3295        } else {
3296            for (var i = 0, len = node.childNodes.length; i < len; ++i) {
3297                texts = getTexts(node.childNodes[i], texts);
3298            }
3299        }
3300        return texts;
3301    }
3302
3303    $.fn.solidTable.getCellText = getTexts;
3304
3305    // ========
3306    //  Paging
3307    // ========
3308
3309    function createPagination(tableData) {
3310        var i18n = tableData.settings.oLanguage.oPaginate;
3311        var mailboxId = document.getElementById("mailBoxTable");
3312
3313        function createButton(linkClass, title, icon) {
3314            return $('<li/>').append(
3315                $('<a/>')
3316                    .addClass('paginate_button ' + linkClass)
3317                    .attr('title', title)
3318                    .append($('<span/>').addClass('fa fa-' + icon))
3319            );
3320        }
3321
3322        var element = $('<div/>').addClass('tablePagination');
3323        var buttons = {
3324            first: createButton('first', i18n.sFirst, 'backward'),
3325            prev: createButton('previous', i18n.sPrevious, 'chevron-left'),
3326            pages: [$('<li><a></a></li>'), $('<li><a></a></li>'), $('<li><a></a></li>')],
3327            next: createButton('next', i18n.sNext, 'chevron-right'),
3328            last: createButton('last', i18n.sLast, 'forward')
3329        };
3330        $('<ul/>').addClass('pagination')
3331            .append(buttons.first).append(buttons.prev).append(buttons.pages).append(buttons.next).append(buttons.last)
3332            .appendTo(element);
3333        // Add click handlers ..
3334        buttons.first.find('a').on('click', function() {
3335            !buttons.first.hasClass('disabled') && setPage(0);
3336        });
3337        buttons.prev.find('a').on('click', function() {
3338            !buttons.prev.hasClass('disabled') && setPage(tableData.currentPage - 1);
3339        });
3340        buttons.next.find('a').on('click', function() {
3341            !buttons.next.hasClass('disabled') && setPage(tableData.currentPage + 1);
3342        });
3343        buttons.last.find('a').on('click', function() {
3344            !buttons.last.hasClass('disabled') && setPage(tableData.pageCount - 1);
3345        });
3346        var directCallback = function() {
3347            !$(this).parent().hasClass('active') && setPage($(this).data('pageIdx'));
3348        };
3349        $.each(buttons.pages, function() {
3350            this.find('a').on('click', directCallback);
3351        });
3352
3353        function addOrRemoveClass(elts, className, remove) {
3354            $.each(elts, function() {
3355                if(mailboxId !== null) {
3356                    if (remove) {
3357                        this.find("a").removeClass(className);
3358                    } else {
3359                        this.find("a").addClass(className);
3360                    }
3361                }else{
3362                    if (remove) {
3363                        this.removeClass(className);
3364                    } else {
3365                        this.addClass(className);
3366                    }
3367                }
3368            });
3369        }
3370
3371        function calculatePageCount() {
3372            // TODO: Support grouped tables .. $table.find('> tbody[data-group]').length > 0
3373            var rowCount = tableData.displayRows.length;
3374            if (tableData.settings.totalLength !== undefined) {
3375                // This property is expected if server-side paging/sorting/filtering is active ..
3376                rowCount = tableData.settings.totalLength;
3377            }
3378            if (tableData.settings.displayLength > 0 && rowCount > 0) {
3379                tableData.pageCount = Math.ceil(rowCount / tableData.settings.displayLength);
3380            } else {
3381                tableData.pageCount = 1;
3382            }
3383        }
3384
3385        function setPage(page, noDataUpdate) {
3386            showPage(page, noDataUpdate);
3387        }
3388
3389        function updatePage() {
3390            showPage(tableData.currentPage);
3391        }
3392
3393        function showPage(pageNumber, noDataUpdate) {
3394            tableData.table.trigger('SolidTable.beforePageUpdate');
3395            // Make sure page is within interval [0, tableData.pageCount[
3396            var pageToShow = Math.max(0, Math.min(pageNumber, tableData.pageCount - 1));
3397            if (tableData.settings.dataUrl) {
3398                // Data comes from the server (i.e. server side sort & pagination) -> we need to acquire the data NOW!
3399                if (!noDataUpdate && !loadDataFromServer(tableData, {pageNumber: pageToShow})) {
3400                    return;
3401                }
3402                tableData.currentPage = pageToShow;
3403            } else {
3404                tableData.currentPage = pageToShow;
3405                var settings = tableData.settings;
3406                var rowsPerPage = settings.displayLength < 0 ? tableData.rows.length : settings.displayLength;
3407                var from = tableData.currentPage * rowsPerPage;
3408                var to = from + rowsPerPage;
3409                // .prevObject refers to the original selector -> tableData.rows ..
3410                tableData.displayRows.slice(0, from).hide()
3411                    .prevObject.slice(from, to).show()
3412                    .prevObject.slice(to).hide();
3413            }
3414            // Update visuals ..
3415            updatePagination();
3416            tableData.table.trigger('SolidTable.pageUpdated');
3417        }
3418
3419        function updatePagination() {
3420            var visiblePages = Math.min(tableData.pageCount, buttons.pages.length);
3421            $.each(buttons.pages, function(i) {
3422                if (i < visiblePages) {
3423                    // Don't use this.show() as it has some strange side effects ..
3424                    this.removeAttr('style');
3425                } else {
3426                    this.hide();
3427                }
3428            });
3429            var fromIdx;
3430            if (tableData.currentPage == 0) {
3431                // First page active ..
3432                fromIdx = 0;
3433            } else if (tableData.currentPage == (tableData.pageCount - 1)) {
3434                // Last page active ..
3435                fromIdx = Math.max(tableData.currentPage - visiblePages + 1, 0);
3436            } else {
3437                // Somewhere in the middle ..
3438                // -> Show active in middle ..
3439                fromIdx = Math.max(tableData.currentPage - Math.floor(visiblePages / 2), 0);
3440            }
3441            addOrRemoveClass([buttons.first, buttons.prev], 'disabled', tableData.currentPage !== 0);
3442            addOrRemoveClass([buttons.next, buttons.last], 'disabled', tableData.currentPage < (tableData.pageCount - 1));
3443            var thousandsSeparator = tableData.settings.oLanguage.sInfoThousands || '';
3444            for (var i = 0; i < visiblePages; ++i) {
3445                if (tableData.currentPage == fromIdx + i) {
3446                    if(mailboxId !== null) {
3447                        buttons.pages[i].find("a").addClass('active');
3448                    }else{
3449                        buttons.pages[i].addClass('active');
3450                    }
3451                } else {
3452                    if(mailboxId !== null) {
3453                        buttons.pages[i].find("a").removeClass('active');
3454                    }else{
3455                        buttons.pages[i].removeClass('active')
3456                    }
3457                }
3458                var displayNumber = fromIdx + i + 1;
3459                if (thousandsSeparator && displayNumber > 999) {
3460                    displayNumber = displayNumber.toString().replace(/\B(?=(\d{3})+(?!\d))/g, thousandsSeparator);
3461                }
3462                buttons.pages[i].find('a').text(displayNumber).data('pageIdx', fromIdx + i);
3463            }
3464        }
3465
3466        return {
3467            element: element,
3468            getPage: function() {
3469                return tableData.currentPage;
3470            },
3471            recalculate: calculatePageCount, // Recalculates the number of displayable pages ..
3472            setPage: setPage, // -> Set the current page & updates the displayed table rows ..
3473            updatePage: updatePage, // -> Updates the displayed table rows ..
3474            update: updatePagination // -> Updates the pagination visuals, not the displayed table rows ..
3475        };
3476    }
3477
3478    // ===========
3479    //  Filtering
3480    // ===========
3481
3482    function createFilter(tableData) {
3483        var element = $('<div/>').addClass('tableFilter');
3484        var previousFilterString = null;
3485        var timeout = null;
3486        var filterDelay = typeof tableData.settings.filterDelay === 'number' ? Math.max(tableData.settings.filterDelay, 100) : 350;
3487        var filterField = $('<input type="text"/>')
3488            .addClass('form-control input-sm')
3489            .on('keyup', function() {
3490                // Clear previous filtering ..
3491                timeout && clearTimeout(timeout);
3492                // Trigger delayed filtering ..
3493                timeout = setTimeout(function() {
3494                    timeout = null;
3495                    applyFilter();
3496                }, filterDelay);
3497            }).appendTo($('<label/>').appendTo(element));
3498
3499        function applyFilter() {
3500            var filterString = $.trim(filterField.val());
3501            if (previousFilterString !== filterString) {
3502                tableData.table.trigger('SolidTable.beforeFilter');
3503                previousFilterString = filterString;
3504                if (tableData.settings.dataUrl) {
3505                    var overridings = undefined;
3506                    if (tableData.pagination && tableData.settings.resetPageOnFiltering) {
3507                        overridings = {pageNumber: 0};
3508                    }
3509                    if (loadDataFromServer(tableData, overridings) && tableData.pagination) {
3510                        // Update visual state of paging as there could be less total rows now ..
3511                        // TODO: We should make sure that the current page corresponds to the page loaded from the server .. !!!!
3512                        tableData.pagination.recalculate();
3513                        tableData.pagination.update();
3514                    }
3515                    return;
3516                }
3517
3518                if (filterString) {
3519                    // Create regex per filter keyword ..
3520                    var allRegex = filterString.split(/[\s]+/);
3521                    for (var i = 0; i < allRegex.length; ++i) {
3522                        allRegex[i] = new RegExp(escapeRegExp(allRegex[i]), "i");
3522 // Ignore case!
3523                    }
3524                    if (tableData.groups) {
3525                        $.each(tableData.groups, function() {
3526                            filterRows(this.rows, allRegex, this);
3527                        });
3528                    } else {
3529                        filterRows(tableData.rows, allRegex, tableData);
3530                    }
3531                } else {
3532                    // Reset filtering ..
3533                    resetFilteredRows();
3534                }
3535                // Update filtered rows visibility ..
3536                if (tableData.pagination) {
3537                    tableData.filteredRows.hide();
3538                    // Recalculate pageCount ..
3539                    tableData.pagination.recalculate();
3540                    if (tableData.settings.resetPageOnFiltering) {
3541                        // Show first page ..
3542                        tableData.pagination.setPage(0);
3543                    } else {
3544                        // Display the "current" page .. (i.e. maybe there are less pages available after filtering)
3545                        tableData.pagination.updatePage();
3546                    }
3547                } else {
3548                    if (tableData.groups) {
3549                        $.each(tableData.groups, function() {
3550                            this.filteredRows.hide();
3551                            this.displayRows.show();
3552                            if (!this.displayRows.length) {
3553                                this.groupBody.hide();
3554                            } else {
3555                                this.groupBody.show();
3556                            }
3557                        });
3558                    } else {
3559                        tableData.filteredRows.hide();
3560                        tableData.displayRows.show();
3561                    }
3562                }
3563                tableData.table.trigger('SolidTable.filtered');
3564            }
3565        }
3566
3567        function filterRows(rows, allRegex, container) {
3568            var visibleRows = [];
3569            var hiddenRows = [];
3570            $.each(rows, function() {
3571                // For each row, find cells and create concatenated string ..
3572                var allTexts = [];
3573                $(this).find('>').each(function() {
3574                    allTexts = getTexts(this, allTexts);
3575                });
3576                var rowString = allTexts.join(' ');
3577                // Check whether row matches all regex patterns ..
3578                var hideRow = false;
3579                $.each(allRegex, function(i, regex) {
3580                    if (!regex.test(rowString)) {
3581                        hideRow = true;
3582                        return false;
3583                    }
3584                });
3585                // Mark row so we can re-apply easily after sort ..
3586                if (hideRow) {
3587                    hiddenRows.push(this);
3588                    $(this).data('.solidTable.filtered', true);
3589                } else {
3590                    $(this).removeData('.solidTable.filtered');
3591                    visibleRows.push(this);
3592                }
3593            });
3594            container.displayRows = $(visibleRows);
3595            container.filteredRows = $(hiddenRows);
3596        }
3597
3598        function resetFilteredRows() {
3599            if (tableData.groups) {
3600                $.each(tableData.groups, function() {
3601                    this.filteredRows = $([]);
3602                    this.displayRows = $(this.rows);
3603                    this.displayRows.each(function () {
3604                        if ($(this).data('.solidTable.filtered')) {
3605                            $(this).removeData('.solidTable.filtered');
3606                        }
3607                    });
3608                });
3609            } else {
3610                tableData.displayRows = tableData.rows;
3611                tableData.filteredRows = $([]);
3612                tableData.rows.each(function () {
3613                    if ($(this).data('.solidTable.filtered')) {
3614                        $(this).removeData('.solidTable.filtered');
3615                    }
3616                });
3617            }
3618        }
3619
3620        // Return filter context ..
3621        return {
3622            element: element,
3623            getFilter: function() {
3624                return previousFilterString;
3625            },
3626            update: function(force) {
3627                if (force) {
3628                    // We must re-apply the current filter ..
3629                    if (previousFilterString) {
3630                        previousFilterString = null;
3631                        applyFilter();
3632                    }
3633                } else {
3634                    // This function is usually triggered after sorting ..
3635                    // (i.e. the rows are still the same, but the order may have changed)
3636                    // TODO: Probably not necessary for grouped table since paging is inactive!!
3637                    var groups = tableData.groups ? tableData.groups : [tableData];
3638                    $.each(groups, function(i, group) {
3639                        var hiddenRows = [];
3640                        var visibleRows = [];
3641                        $.each(group.rows, function () {
3642                            if ($(this).data('.solidTable.filtered')) {
3643                                hiddenRows.push(this);
3644                            } else {
3645                                visibleRows.push(this);
3646                            }
3647                        });
3648                        group.displayRows = $(visibleRows);
3649                        group.filteredRows = $(hiddenRows);
3650                    });
3651                }
3652            },
3653            clear: function() {
3654                // Clear filter field & reset rows ..
3655                previousFilterString = null;
3656                filterField.val('');
3657                resetFilteredRows();
3658            }
3659        };
3660    }
3661
3662    function escapeRegExp(str) {
3663        return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
3664    }
3665
3666    // ========
3667    //  Layout
3668    // ========
3669
3670    function layoutElements(tableData) {
3671        var root = $('<div/>').addClass('solidTableWrapper');
3672        // Save root object to remove the table decoration on SolidTable destroy ..
3673        tableData.rootElement = root;
3674        var result = $.fn.solidTable.parse(tableData.settings.sDom);
3675        $.each(result.elements, function() {
3676            // Place all elements before root element (i.e. wrapper) ..
3677            root.append(this);
3678        });
3679        // Now replace special elements ..
3680        if (result.lengthChooser) {
3681            result.lengthChooser.remove();
3682        }
3683        if (result.information) {
3684            result.information.remove();
3685        }
3686        if (result.processing) {
3687            result.processing.remove();
3688        }
3689        if (result.filtering) {
3690            if (tableData.filter) {
3691                result.filtering.replaceWith(tableData.filter.element);
3692            } else {
3693                result.filtering.remove();
3694            }
3695        }
3696        if (result.pagination) {
3697            if (tableData.pagination) {
3698                result.pagination.replaceWith(tableData.pagination.element);
3699            } else {
3700                result.pagination.remove();
3701            }
3702        }
3703        // Finally reposition table ..
3704        tableData.table.before(root);
3705        if (result.table) {
3706            result.table.replaceWith(tableData.table);
3707        }
3708    }
3709
3710    $.fn.solidTable.parse = function(domString) {
3711        var rootContext = {
3712            elements: []
3713        };
3714
3715        function extractClass(element, domStr, idx) {
3716            var quote = domStr[idx];
3717            var closeQuoteIdx = domStr.indexOf(quote, idx + 1);
3718            if (closeQuoteIdx < 0) {
3719                $.error('Invalid dom string: ' + domStr + '. Missing closing quote character [' +
3720                    quote + '] for class name starting at index ' + idx);
3721            }
3722            var className = $.trim(domStr.substring(idx + 1, closeQuoteIdx));
3723            if (className.length && className[0] == '#') {
3724                element.attr('id', className.substring(1));
3725            } else {
3726                element.addClass(className);
3727            }
3728            return closeQuoteIdx;
3729        }
3730
3731        var context = rootContext;
3732        for (var i = 0; i < domString.length; ++i) {
3733            var nextChar = domString[i];
3734            switch (nextChar) {
3735                case '<':
3736                    // Start of tag ..
3737                    context = {
3738                        parentContext: context,
3739                        elements: [],
3740                        element: $('<div/>')
3741                    };
3742                    break;
3743                case '>':
3744                    // End of tag ..
3745                    if (context.parentContext) {
3746                        // Add elements to context element ..
3747                        $.each(context.elements, function() {
3748                            context.element.append(this);
3749                        });
3750                        // Add current contexts element to parent context element list ..
3751                        context.parentContext.elements.push(context.element);
3752                        // Restore old context ..
3753                        context = context.parentContext;
3754                    } else {
3755                        $.error('Found unexpected character at index ' + i+": " + nextChar);
3756                    }
3757                    break;
3758                case '\'':
3759                case '"':
3760                    // Start of class name ..
3761                    if (!context.element) {
3762                        $.error('Invalid syntax for dom string. Found ' + nextChar + ' at index: ' + i);
3763                    }
3764                    i = extractClass(context.element, domString, i);
3765                    break;
3766                case 'l': // Length changing
3767                    context.elements.push(rootContext.lengthChooser = $('<div/>'));
3768                    break;
3769                case 'f': // Filtering input
3770                    context.elements.push(rootContext.filtering = $('<div/>'));
3771                    break;
3772                case 't': // The table!
3773                    context.elements.push(rootContext.table = $('<div/>'));
3774                    break;
3775                case 'i': // Information
3776                    context.elements.push(rootContext.information = $('<div/>'));
3777                    break;
3778                case 'p': // Pagination
3779                    context.elements.push(rootContext.pagination = $('<div/>'));
3780                    break;
3781                case 'r': // Processing
3782                    context.elements.push(rootContext.processing = $('<div/>'));
3783                    break;
3784                default:
3785                    $.error('Found unexpected character at index ' + i+": " + nextChar);
3786                    break;
3787            }
3788        }
3789        return rootContext;
3790    };
3791
3792    // ===========
3793    //  Rendering
3794    // ===========
3795    // -> dynamic data ..
3796
3797    function createRows(tableData, rowData) {
3798        // TODO: Support grouping ..
3799        if (tableData.groups) {
3800            delete tableData.groups;
3801        }
3802        var table = tableData.table;
3803        var body = $('<tbody/>');
3804        $.each(rowData, function(i) {
3805            var row = tableData.settings.rowRenderer.call(table, tableData, this, i);
3806            if (row) {
3807                body.append(row);
3808            }
3809        });
3810        table.find('> tbody').replaceWith(body);
3811        return body;
3812    }
3813
3814    $.fn.solidTable.defaultRowRenderer = function(tableData, rowData, rowIdx) {
3815        var rowElement = $('<tr/>');
3816        var cellRenderer = tableData.settings.cellRenderer;
3817        $.each(tableData.columns, function() {
3818            var cellData = rowData[this.index] !== undefined ? rowData[this.index] :
3819                (rowData[this.fieldName] !== undefined ? rowData[this.fieldName] : rowData[this.fieldName + ':' + this.entry]);
3820            var cell = cellRenderer.call(tableData.table, tableData, this, rowData, cellData, rowIdx) || $('<td/>');
3821            rowElement.append(cell);
3822        });
3823        return rowElement
3824    };
3825
3826    $.fn.solidTable.defaultCellRenderer = function(tableData, column, rowData, cellData, rowIdx) {
3827        var cell = $('<td/>');
3828        if (cellData !== undefined) {
3829            if (column.nestedFields) {
3830                // Add class "nested" to cell ..
3831                cell.addClass("nested");
3832                // Wrap cellData with span element ..
3833                var mainCell = $('<span/>').appendTo(cell);
3834                // Add nested container ..
3835                var nestedContainer = $('<div/>').addClass("nested");
3836                var nestedData;
3837                if (rowData instanceof Array) {
3838                    // The current cell-data must be of type object!!!
3839                    nestedData = typeof cellData === 'object' ? cellData.nested : undefined;
3840                    mainCell.text(cellData.value);
3841                } else {
3842                    nestedData = typeof cellData === 'object' && cellData.nested ? cellData.nested : rowData;
3843                    mainCell.text(cellData.value !== undefined ? cellData.value : cellData);
3844                }
3845                if (nestedData) {
3846                    var indexed = nestedData !== rowData;
3847                    var cellRenderer = tableData.settings.nestedCellRenderer;
3848                    $.each(column.nestedFields, function (i) {
3849                        if (i > 0) {
3850                            nestedContainer.append(column.nestedFieldSeparator);
3851                        }
3852                        var nestedCellData = (indexed && nestedData[this.index] !== undefined) ? nestedData[this.index] :
3853                            (nestedData[this.fieldName] !== undefined ? nestedData[this.fieldName] : nestedData[this.fieldName + ':' + this.entry]);
3854                        nestedContainer.append(cellRenderer.call(tableData.table, tableData, column, rowData, cellData, this, nestedCellData, rowIdx));
3855                    });
3856                }
3857                cell.append(nestedContainer);
3858            } else {
3859                cell.text(cellData);
3860            }
3861        }
3862        if (column.cssClass) {
3863            cell.addClass(column.cssClass);
3864        }
3865        return cell;
3866    };
3867
3868    $.fn.solidTable.defaultNestedCellRenderer = function(tableData, column, rowData, cellData, nestedField, nestedData/*, rowIdx*/) {
3869        return $('<span/>').addClass(this.cssClass).text(nestedData);
3870    };
3871
3872    // Defaults ..
3873
3874    $.fn.solidTable.setDefaults = function (options) {
3875        $.extend(true, DEFAULTS, options);
3876    };
3877
3878})(jQuery);
3879// application.js
3880//--= pre           null
3881//--= post          solid.service.application.resources.NewLineRemover
3882
3883window.APPLICATION = true;
3884}

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.