PageSourceSearch

https://edinburgh.com/main.js

js edinburgh.com collected 2026-10-02 14:12:21 UTC 20,540 bytes, 617 lines download raw bytes

1let localSessionId = getItem( "sessionid" );
2
3/*--- temporary tech debt ---*/
4let metaData   =  {};
5let lps        =  [ 'answer', 'ebook', 'lp1', 'lp2', 'lp3' ];
6
7function noAutoAds()
8{
9   /*
10   document.querySelectorAll('ins.adsbygoogle').forEach(el => {
11      console.log( "auto-ads-timer" );
12      el.style.display = 'none';
13   });
14   */
15}
16
17function pathFinal(e)
18{
19   console.log( "pathFinal", e );
20   let   pathName =  document.location.pathname;
21         pathName =  pathName.endsWith('/')?pathName.slice(0, -1):pathName;
22   let   lp       =  pathName.split("/").pop();
23   if( lps.includes(lp) )
24      pathName = pathName.replace( lp, "ebook" );
25   else
26      pathName += "/ebook";
27   document.location.href = window.location.origin + pathName;
28}
29
30let postedSlide = false;
31window.postSlide = function(p) {
32   console.log( "window.postSlide" );
33   let widget        =  $(p.selector).parent().parent();
34   let widgetId      =  widget.attr("id") || "";
35   let widgetWidth   =  $("#"+widgetId).width();
36   
37   $(".item").each( function(){
38      let id = widgetId;
39      track( $("#" + widgetId), "action" );
40      if( $(this).attr("id") === id )
41      {
42         if( !postedSlide )
43         {
44            $(this).parent().parent().css( "display",          "flex"      );
45            $(this).parent().parent().css( "justify-content",  "center"    );
46            $(this).parent()         .css( "width",            widgetWidth );
47            $(this).parent().parent().parent().addClass( "col-lg-12" );
48         }
49         postedSlide = true;
50      }
51      else
52      {
53         $(this).parent().parent().removeAttr("style");
54         $(this).remove();
55      }
56   });
57   try { widgetAction( widgetId ); } catch(e) {}
58   
59   console.log( "auto-ads-01" );
60   noAutoAds();
61   setInterval( function(){ noAutoAds() }, 1000 );
62   console.log( "auto-ads-02" );
63};
64
65
66//--- Bot Detection ---
67const t0             =  performance.now();
68let   firstEventMs   =  null;
69function markFirst()
70{
71   if( firstEventMs === null )
72      firstEventMs = performance.now() - t0;
73}
74
75addEventListener( "mousemove",  markFirst, { once:true } );
76addEventListener( "keydown",    markFirst, { once:true } );
77addEventListener( "touchstart", markFirst, { once:true } );
78addEventListener( "pointerdown",markFirst, { once:true } );
79
80function unpopChat()
81{
82   $("#popChat").slideUp( function(){ $("#open-chat").show(); } );
83}
84
85function popChat()
86{
87   console.log( "hide open chat" );
88   $("#open-chat").hide();
89   $("#popChat").slideDown( "500", function(){ $(this).find(".ez-chat-input").focus(); } );
90}
91
92
93$(document).ready( function(){
94   
95   
96   
97   
98   window.addEventListener('loco:postSlide', (e) => {
99      console.log( "step", e.detail.step );
100      if( e.detail.step===1 )
101      {
102         let pId = $(e.detail.selector).parent().parent().attr("id");
103         $(".item").each( function(){
104            if( pId != $(this).attr("id") )
105               $(this).hide();
106         });
107         noAutoAds();
108         setInterval( function(){ noAutoAds() }, 1000 );
109      }
110      /*
111      console.log('slide', e.detail.step);
112      console.log( "parent", $(e.detail.selector).parent().parent().attr("id") );
113      console.log('slide', e.detail.selector);
114      const widget = document.querySelector(e.detail.selector)
115      */
116   })
117   
118   window.addEventListener('loco:pathFinal', (e) => {
119      console.log('final', e.detail.leadId);
120   })
121   
122   $("#open-chat").click( function(){
123      popChat();
124   });
125   
126   if( isMobile() )
127   {
128      $("#open-chat").show();
129   }
130   else
131   {
132      setTimeout( function(){ popChat(); }, 3000 );
133   }
134   $(".corplink").each( function(){
135      $(this).click( function(){ document.location.href=$(this).attr("link"); });
136   });
137   $(".scrolltop").click( function(){
138      $('html, body').animate({ scrollTop: 0 }, 500);
139   });
140   
141   /*
142   setTimeout( function(){
143      $(window).scrollTop(0);
144   }, 1000);
145   */
146   
147   $(".lassocta").click( function(e){
148      e.stopPropagation();
149      
150      let ctaType =  $(this).attr( "lassoctatype"  );
151      let ctaID   =  $(this).attr( "lassoctaid"    );
152      let html    =  "<div class='col-12' id='dynamicscript' style='justify-content: center; display:grid; place-items:center;' class='dynamicscript pg-wrap'></div>";
153      $(".container.layout").html( html );
154      
155      if( ctaType==="external-scripts" )
156      {
157         externalScript( ctaID, "dynamicscript", ($(".container.layout").attr("node") || "" ), $(".container.layout").attr("entities") );
158      }
159      if( ctaType==="flow" )
160      {
161         $(".dynamicscript").addClass("ezpath");
162         $(".dynamicscript").attr( "id", ctaID );
163         loadSlide( $(".dynamicscript"), ctaID, 1 );
164      }
165      
166      
167      /*
168      let hideAll =  false;
169      let ctaType =  $(this).attr( "lassoctatype"  );
170      let ctaID   =  $(this).attr( "lassoctaid"    );
171      if( ctaID!="" )
172      {
173         $('header').after("<div id='dynamicscript' style='justify-content: center; display:grid; place-items:center;' class='dynamicscript pg-wrap'></div>");
174         if( ctaType==="external-scripts" )
175         {
176            externalScript( ctaID, "dynamicscript", ($(".container.layout").attr("node") || "" ), $(".container.layout").attr("entities") );
177            hideAll = true;
178         }
179         if( ctaType==="flow" )
180         {
181            $(".dynamicscript").addClass("ezpath");
182            $(".dynamicscript").attr( "id", ctaID );
183            loadSlide( $(".dynamicscript"), ctaID, 1 );
184            hideAll = true;
185         }
186         if( hideAll )
187         {
188            setTimeout( function(){
189               $(".item.item-zoning > div").children().not('header, footer, style, .dynamicscript').remove();
190               $('#myElement').children().not('p, span, h2').remove();
191            }, 100 );
192         }
193      }
194      */
195   });
196   
197   localSessionId =  localSessionId===""?(new Date()).getTime():localSessionId;
198   let hostName   =  document.location.hostname.replace( "stage.", "" ).replace( "staging.", "" ).replace( "search.", "" ).replace( "search2.", "" );
199   sessionStorage.setItem( "sessionid", localSessionId );
200   if( document.location.href.includes("://search") )
201   {
202      if( getParam("source")==='afs' )
203      {
204         track(    $(".afs"), "action" );
205         widgetTrack( "afs",  "action", getParam("q") );
206      }
207   }
208   else
209   {
210      track( null, "impression" );
211   }
212   widgetTrack( "", "impression", "" );
213   $(".item").click( function(){
214      track( $(this), "action" );
215   });
216   $( ".item-bubbles a" ).click( function(){
217      widgetTrack( "bubbles", "action", $(this).text() );
218   });
219   
220   $(".serp-block a").click( function(){
221      widgetTrack( getParam("source"), "click", getParam("q") );
222   });
223   
224   $("a").each( function(){
225      let href = $(this).attr( "href" );
226      if( href.startsWith( "flow-" ) )
227      {
228         $(this).attr( "href", "#" );
229         $(this).click( function(e){
230            let popEzId = href.substr(5);
231            $("#floatpath").attr( "id",      popEzId  );
232            $("#floatpath").css(  "display", "block"  );
233            $("#floatpath").show();
234            loadLanding(   $("#"+popEzId), popEzId, 1 );
235            $(".item").hide();
236            e.preventDefault();
237         });
238      }
239      else
240      if( href.startsWith( "https://" ) || href.startsWith( "//" ) )
241      {
242         if( !href.includes(hostName) )
243            $(this).attr( "target", "_blank" );
244      }
245   });
246   
247   
248   
249   
250   
251   $(".item.item-current-image img").each(function() {
252      var $real   =  $(this);
253      var src     =  $real.attr("src");
254      if( !src )
255      {
256         $real.remove();
257         return;
258      }
259      
260      var probe = new Image();
261      probe.onerror = function() {
262         $real.remove();
263      };
264      probe.src = src;
265   });
266   
267   
268   
269   
270   
271   
272   
273   $("img.ebook").each(function() {
274      if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth === 0)
275         $(this).remove();
276      else
277         $(this).on("error", function() { $(this).remove(); });
278   });
279   
280   $(".item.item-sublist a.noblank").each(function(ndx) {
281      $(this).parent().attr( "id", "sub" + ndx );
282      let src  =  $(this).find( ".preview-image" ).css("background-image").replace("url(", "").replace(")", "").replaceAll('"', "");
283      let img  =  new Image();
284      img.src  =  src;
285      img.id   =  "i" + ndx;
286      img.onerror = function() {
287         $.ajax( {url:"//trklas.com/badpix.jsp?src=" + encodeURIComponent($(this).attr("src"))} );
288         console.log( img.id.substr(1), $(this).attr("src") );
289//       $( "#sub" + img.id.substr(1) ).remove();
290      };
291   });
292   
293   
294   $(document).on( "change", 'input', function(e){
295      $(this).val( $(this).val().trim() );
296   });
297   
298   $(document).on( "keydown", '#query', function(e){
299      if( e.keyCode===13 )
300      {
301         if( $(this).val().trim() !="" )
302            $("#search").click();
303      }
304   });
305   
306   $(document).on( "click", '#search', function(e){
307      e.preventDefault();
308      let v = $("#query").val();
309      if( v!="" )
310      {
311         widgetTrack( "search", "action", v );
312         document.location.href = searchURL( v, "search", "0" );
313      }
314   });
315});
316
317function getBaseDomain()
318{
319   try
320   {
321      var parts = window.location.hostname.split('.');
322      if( parts.length >= 2 )
323         return parts.slice(-2).join('.');
324      return hostname;
325   }
326   catch( e )
327   {
328      return null;
329   }
330}
331
332function searchURL( val, src, widgetId )
333{
334   let      channel    =  "";
335   let      mainDiv    =  $(".container.layout");
336   let      layoutId   =  mainDiv.attr( "id"       )  || "";
337   let      track      =  mainDiv.attr( "track"    )  || "";
338   let      nodeId     =  mainDiv.attr( "node"     )  || "";
339   let      entities   =  mainDiv.attr( "entities" )  || "";
340   let      suffix     =  mainDiv.attr( "suffix"   )  || "";
341   let      subId      =  mainDiv.attr( "subid"    )  || "";
342   let      typeId     =  mainDiv.attr( "type_id"  )  || "";
343   let      pixel      =  ($("#pixel-" + widgetId).val()==="yes");
344            entities   =  entities.startsWith(",")?entities.substr(1):entities;
345   let      url        =  "https://search." + getBaseDomain() + "/search?source=" + src + "&tf=" + trafficSource();
346   
347   
348// console.log( url );
349   if( val!=""       )  url   +=  "&q="         +  encodeURIComponent(val);
350   if( channel!=""   )  url   +=  "&channel="   +  channel;
351                        url   +=  "&id="        +  layoutId;
352                        url   +=  "&type_id="   +  typeId;
353                        url   +=  "&node_id="   +  nodeId;
354                        url   +=  "&entities="  +  entities;
355                        url   +=  "&suffix="    +  suffix;
356                        url   +=  "&widid="     +  widgetId;
357                        url   +=  "&pixel="     +  pixel;
358                        url   +=  "&subid="     +  subId;
359   return               url;
360}
361
362function afs( container, pubId, styleId, referrer, widId, subId )
363{
364   let ctnr                =  $(".container.layout");
365   let channel             =  ctnr.attr( "node_id"    );
366   let entities            =  ctnr.attr( "entities"   );
367       entities            =  entities.startsWith(",")?entities.substr(1):entities;
368   let terms               =  $("#" + container).attr( "terms" );
369   let resultsPageBaseUrl  =  searchURL( "", "afs", widId );
370   let pageOptions         = {   "pubId"                    :  "partner-pub-" + pubId,
371                                 "styleId"                  :  styleId,
372//                               "channel"                  :  channel,
373                                 "channel"                  :  subId,
374                                 "adtest"                   :  "off",
375                                 "relatedSearchTargeting"   :  "content",
376                                 "resultsPageBaseUrl"       :  resultsPageBaseUrl,
377                                 "resultsPageQueryParam"    :  "q",
378                                 "terms"                    :  terms,
379                                 "linkTarget"               :  "_blank",
380                                 "adPage"                   :  1,
381                                 "referrerAdCreative"       :  referrer,
382                                 "ignoredPageParams"        :  "msclkid,utm_source,utm_medium,utm_term,utm_content"
383                              };
384// console.log( "afs", "subId=" + subId );
385// console.log( "afs", JSON.stringify(pageOptions, null, 3) );
386   let rsblock = {  "container": container, "maxTop": 8, "relatedSearches": 8 };
387   if( typeof _googCsa === 'function' )
388      _googCsa( 'relatedsearch', pageOptions, rsblock );
389   else
390      console.log( "AFS ERROR" );
391}
392
393function trafficSource()
394{
395   let src = getItem( "trafficsource" );
396   if( src===null || src==="" )
397   {
398      let qs         =  qs2Hash();
399      let msclkid    =  qs["msclkid"   ]  || "";
400      let gclid      =  qs["gclid"     ]  || "";
401      let utm_source =  qs["utm_source"]  || "";
402      if(      msclkid!=""    )        src   =  "bing";
403      else if( gclid!=""      )        src   =  "google";
404      else if( utm_source=="google" )  src   =  "google";
405      else                             src   =  "organic";
406      
407      if( document.location.search.toLowerCase().includes("utm_source=bing") )
408         src = "bing";
409      
410      sessionStorage.setItem( "trafficsource", src );
411   }
412   return src;
413}
414
415function getItem( p )
416{
417   let    v = sessionStorage.getItem( p );
418   return (v===null?"":v);
419}
420
421function getParam( p )
422{
423   let v = qs2Hash()[p];
424   return (v===undefined?"":v);
425}
426
427function qs2Hash()
428{
429   let qs  = document.location.search.slice(1).split( "&" );
430   let arr = {};
431   for( let i=0; i<qs.length; i++ )
432   {
433      let pair = qs[i].split( "=" );
434      if( pair[0].trim()==="" )
435         continue;
436      arr[pair[0]] = pair[1] || "";
437   }
438   return arr;
439}
440
441function domainName()
442{
443   let      host  =  document.location.hostname.split(".");
444   let      len   =  host.length;
445   return   host[len - 2] + "." + host[len - 1];
446}
447
448function track( o, event )
449{
450   if( $(".container.layout").attr("corporate")==="true" )
451      return;
452
453   let type       =  o==null?"":o.attr("class"     ).replace("item item-", "");
454   let id         =  o==null?"":o.attr("id"        ).replace("item item-", "");
455   let nodeId     =  $(".container.layout"   ).attr( "node"       ) || "";
456   let layoutId   =  $(".container.layout"   ).attr( "id"         ) || "";
457   let shellId    =  $(".container.layout"   ).attr( "shell"      ) || "";
458   let domainId   =  $(".container.layout"   ).attr( "domain"     ) || "";
459   let typeId     =  $(".container.layout"   ).attr( "type_id"    ) || "";
460   let level      =  $(".container.layout"   ).attr( "track"      ) || "";
461   let suffix     =  $(".container.layout"   ).attr( "suffix"     ) || "";
462   let entities   =  $(".container.layout"   ).attr( "entities"   ) || "";
463       entities   =  entities.startsWith(",")?entities.substr(1):entities;
464   let qs         =        localSessionId;
465       qs        +=  "|" + shellId;
466       qs        +=  "|" + domainId;
467       qs        +=  "|" + trafficSource();
468       qs        +=  "|" + event;
469       qs        +=  "|" + entities;      // entities
470       qs        +=  "|" + layoutId;      // layout ID
471       qs        +=  "|" + id;            // widget ID
472       qs        +=  "|" + type;          // widget Type
473       qs        +=  "|" + nodeId;        // node ID
474       qs        +=  "|" + typeId;        // Layout Type ID
475       qs        +=  "|" + level;         // level
476       qs        +=  "|" + suffix;        // suffix
477   if( getItem(qs)==="" )
478   {
479      sessionStorage.setItem( qs, "yes" );
480      qs += "|"   +  document.location.pathname;
481      qs += "|"   +  document.location.search;
482      let link = "//trklas.com/track2.jsp?q=" + encodeURIComponent(cypher(qs));
483//    console.log( "sendBeacon", link );
484      try { navigator.sendBeacon(   link );  }  catch(e) {}
485   }
486   
487   if( event==='action' && $("#pixel-" + id).val()==="yes" )
488   {
489      console.log( "conversionPixel()" );
490      conversionPixel();
491   }
492   
493   
494}
495
496
497function widgetTrack( type, event, label )
498{
499   let types  = "";
500   if( event==='impression' )
501   {
502      types += $(".item-bubbles" ).length > 0 ? ",bubbles"  :"";
503      types += $(".item-afs"     ).length > 0 ? ",afs"      :"";
504      types += $("#query"        ).length > 0 ? ",search"   :"";
505      types  = types.substr(1);
506   }
507   else
508   {
509      types = type;
510   }
511   if( types!="" )
512   {
513      let layoutId   =  $(".container.layout"   ).attr( "id"         )  || "0";
514      let shellId    =  $(".container.layout"   ).attr( "shell"      );
515      let domainId   =  $(".container.layout"   ).attr( "domain"     );
516      let nodeId     =  $(".container.layout"   ).attr( "node"       );
517      qs  = localSessionId + "|" + shellId + "|" + domainId + "|" + nodeId + "|" + layoutId + "|" + types + "|" + trafficSource() + "|" + event + "|" + label;
518      if( getItem(qs)==="" )
519      {
520         sessionStorage.setItem( qs, "yes" );
521         let link = "//trklas.com/widget.jsp?q=" + encodeURIComponent(cypher(qs));
522//       console.log( "sendBeacon", link );
523         try { navigator.sendBeacon(   link );  }  catch(e) {}
524      }
525   }
526}
527
528
529function cypher( input )
530{
531   let output = "";
532   for( let i=0; i<input.length; i++ )
533   {
534      output += randomChar() + input.charAt(i);
535   }
536   return output;
537}
538
539function randomChar()
540{
541   var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
542   return characters.charAt( Math.floor(Math.random() * characters.length ) );
543}
544
545let converted = false;
546function conversionPixel()
547{
548   if( !converted )
549   {
550      console.log( "conversionPixel()" );
551      
552      let googleConvPixel  =  null;
553      let bingEvent        =  null;
554      
555      
556      try { googleConvPixel  =  {};                                     }  catch(e) { }
557      try { bingEvent        =  configVars["bing-conversion"]["event"]; }  catch(e) { }
558      try { window.uetq.push( 'event', bingEvent, {} );                 }  catch(e) { console.log("conversion", "bing",    e); }
559      try { gtag(             'event', 'conversion', googleConvPixel);  }  catch(e) { console.log("conversion", "google",  e); }
560   }
561   converted = true;
562}
563
564function postEZPath( ezPathId )
565{
566   let o    =  $( "#" + ezPathId );
567   let hide =  o.attr("hide");
568   if( hide==='yes' )
569   {
570      $(".item").hide();
571      o.parent().parent().show();
572   }
573}
574
575
576
577function hide(widId)
578{
579   $("#"+widId).hide();
580}
581
582function show(widId)
583{
584   $("#"+widId).parent().parent().css( "display", "block" );
585   $("#"+widId).fadeIn();
586}
587
588function isVisible(widId)
589{
590   return $("#"+widId).is(":visible");
591}
592
593async function externalScript( id, target, nodeId, entities )
594{
595   let   targetElm      =  document.getElementById( target );
596   const url            =  "/external-script/" + id + "/" + nodeId + "/" + entities;
597   const res            =  await fetch(url);
598   let   html           =  await res.text();
599   let   bodyWidth      =  Math.min( 800, $(window).width() - 20 );
600   html = html.replace( "<div", "<div style='width:" + bodyWidth + "px'" );
601   targetElm.innerHTML  =  html;
602   const scripts = targetElm.querySelectorAll('script');
603   scripts.forEach(function(oldScript) {
604      const newScript = document.createElement('script');
605      Array.from(oldScript.attributes).forEach(function(attr) {
606         newScript.setAttribute(attr.name, attr.value);
607      });
608      const cleaned = oldScript.textContent.replace(/[\r\n]+/g, ' ');
609      newScript.textContent = '(function(){' + cleaned + '})();';
610      oldScript.parentNode.replaceChild(newScript, oldScript);
611   });
612}
613
614function isMobile()
615{
616   return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i.test(navigator.userAgent);
617}

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.