1(function ($, Drupal, settings, once){ 2 3 Drupal.behaviors.DoliData = { 4 brandObject : Drupal.behaviors.getBrandInfo, 5 data: null, 6 7 // Not In Use 8 grabData: async function() { 9 var data = this.data; 10 11 // If can't get from local variable call Ajax to Server 12 if (!data){ 13 data = await this.requestCurrentBrandData(); 14 this.data = data; 15 } 16 17 return data; 18 19 }, 20 21 // Not In Use 22 requestCurrentBrandData :async function(){ 23 if (!drupalSettings || !drupalSettings.verbAlgolia) { 24 return null; 25 } 26 const brand = drupalSettings.verbAlgolia.brand; 27 const clientId = brand.toLowerCase(); // No need to change "railbooker" to "railbookers" unless you are directly calling Dolli, but we grabbing from internal server; 28 const fileDestination = "/sites/default/files/json/"; 29 const fileName = clientId + "--dollie-products.json"; 30 const url = fileDestination + fileName; 31 32 try { 33 var response = await $.ajax({ 34 url: url, 35 dataType: 'json' 36 }); 37 return response; 38 } catch (error) { 39 throw new Error('Error fetching JSON: ' + error); 40 } 41 }, 42 43 // This is the new way to Grab Data 44 requestGroupCall : async function(productsCodes) { 45 if (!productsCodes) {return []} 46 if (!drupalSettings || !drupalSettings.verbAlgolia) { 47 return []; 48 } 49 const dollieurl = drupalSettings.verbAlgolia.dollieUrl; 50 const brand = drupalSettings.verbAlgolia.brand.toLowerCase(); 51 const clientId = brand == 'railbooker' ? "railbookers" : brand; 52 const provider = "1"; 53 const path = "/tour/products"; 54 const url = dollieurl + path + 55 "?provider=" + provider + 56 "&clientId="+ clientId + 57 "&productCode="+ productsCodes; 58 59 try { 60 var response = await $.ajax({ 61 url: url, 62 dataType: 'json' 63 }); 64 return response; 65 } catch (error) { 66 throw new Error('Error fetching JSON: ' + error); 67 } 68 69 } 70 } 71 72 Drupal.behaviors.filterDoliData = { 73 filter: function(ids, items){ 74 var filterData = items.filter((item) => { 75 return ids.includes(item.id); 76 }); 77 return filterData; 78 }, 79 80 getAllId: function (items) { 81 let idArray = []; 82 83 items.forEach((item)=>{ 84 if(item.id){ 85 idArray.push(item.id); 86 } 87 }); 88 return idArray; 89 }, 90 91 grabImageData: function(images) { 92 const OrderToGrabBy = ['image', 'heroImage', 'detailsImage' ]; // This is what normally returns from item 93 94 var newImage = {path:'null',description:"null"}; 95 96 // The reason using some is beacue we need to break out 97 //https://stackoverflow.com/questions/2641347/short-circuit-array-foreach-like-calling-break 98 OrderToGrabBy.some((imageType)=>{ 99 if((img = images[imageType]) ){ 100 if (typeof img == "object"){ 101 newImage = img; 102 return true; 103 } 104 else if (typeof img == "string") { 105 newImage = {path: img, description: "" } 106 return true; 107 } 108 } 109 }); 110 111 return newImage; 112 }, 113 114 // Not sorting, like Order 115 // Sorting like grabbing only the data we need 116 sortItems : function (items){ 117 var newitems = []; 118 items.forEach((item)=>{ 119 if(newItem = this.sortItem(item)) { 120 newitems.push(newItem); 121 } 122 }); 123 124 return newitems; 125 }, 126 127 sortItem : function(item){ 128 129 if(!item?.basicInfo?.name) return; // Don't add empty items 130 131 var newItem= {}; 132 newItem.title = item?.basicInfo?.name 133 newItem.url = item?.viewExtensions?.url; 134 newItem.image = item?.viewExtensions?.images ? this.grabImageData(item?.viewExtensions?.images) : {path:'null',description:"null"}; 135 136 const offers = item?.viewExtensions?.offers;// Cant use [0] cause some offer dont start in 0 137 if(offers && Object.values(offers)[0]) { 138 var offer = Object.values(offers)[0] 139 const isFlashSale = offer?.isFlashSale; 140 const flag = offer?.flag; 141 142 newItem.isFlashSale = isFlashSale; 143 newItem.flag = flag; 144 } 145 146 return newItem; 147 } 148 } 149 150 Drupal.behaviors.renderHelper = { 151 152 parser: new DOMParser(), 153 154 anchortemplate: ` 155 <a href="{{url}}"> 156 {{item}} 157 </a>`, 158 159 cardTemplate : ` 160 <article class="card-grid__single-card card"> 161 <div class="card__inner"> 162 <div class="card__image"> 163 {{image}} 164 </div> 165 <div class="card__content"> 166 {{content}} 167 </div> 168 </div> 169 </article>`, 170 171 imageTemplate : `<img src="{{image_url}}" alt="{{alt_text}}" />`, 172 173 flagTemplate : `<span class="card__tag">{{text}}</span>`, 174 175 noTripsMessage: 176 `<section class="no-trips-found"> 177 <h2> Sorry! </h2> 178 <p> 179 No results were found<br> 180 Try searching something else 181 </p> 182 </section>`, 183 184 createCard : function(image, content){ 185 var renderedItem = 186 this.cardTemplate 187 .replace('{{image}}', image) 188 .replace('{{content}}', content); 189 return renderedItem; 190 }, 191 192 wrapInAnchor : function (url, item) { 193 var renderedItem = 194 this.anchortemplate 195 .replace("{{url}}", url) 196 .replace('{{item}}', item); 197 return renderedItem; 198 }, 199 200 createImageField: function (image_url, alt_text){ 201 var renderedItem = 202 this.imageTemplate 203 .replace("{{image_url}}", image_url) 204 .replace('{{alt_text}}', alt_text); 205 return renderedItem; 206 }, 207 208 createFlagField: function (text){ 209 var renderedItem = 210 this.flagTemplate 211 .replace("{{text}}", text); 212 return renderedItem;; 213 }, 214 215 createCardFromItem: function(item){ 216 var image = this.createImageField(item.image.path, item.image.description); 217 var title = "<h4 class='card__title'>" + item.title + "</h4>"; 218 219 if(item.flag) { 220 image += this.createFlagField(item.flag); 221 } 222 223 var card = this.createCard(image, title) 224 var Anchorcard = this.wrapInAnchor(item.url, card);
225 const DomItem = this.makeIntoDomElement(Anchorcard); 226 227 return DomItem; 228 229 }, 230 231 createCards : function(items) { 232 var array = []; 233 items.forEach((item)=>{ 234 array.push(this.createCardFromItem(item)); 235 }); 236 return array; 237 }, 238 239 makeIntoDomElement: function(htmlString){ 240 var HtmlDomItem = this.parser.parseFromString(htmlString, "text/html"); // This creates an html tag which we don't want 241 var DomItem = HtmlDomItem.documentElement.querySelector("body"); // Have to Grab the node it created 242 return DomItem.firstChild; 243 } 244 245 } 246 247 Drupal.behaviors.placeItems = { 248 249 placeItems : function(items){ 250 const grid = document.querySelector('.card-grid__inner'); 251 grid.innerHTML = ''; 252 253 items.forEach((item)=>{ 254 grid.appendChild(item); 255 }); 256 257 }, 258 259 displayEmptyMessage: function(text) { 260 const grid = document.querySelector('.mm__bottom-left'); 261 const noMessageDom = Drupal.behaviors.renderHelper.makeIntoDomElement(text); 262 grid.prepend(noMessageDom); 263 }, 264 265 removeEmptyMessage: function(){ 266 const item = document.querySelector('.no-trips-found'); 267 if(item) { 268 item.remove(); 269 } 270 } 271 } 272 273 Drupal.behaviors.algoliaEventListener = { 274 init: false, 275 276 attach: function(){ 277 if(!this.init) { 278 279 document.addEventListener("algolia-render", (e)=>{ 280 Drupal.behaviors.autoCompleteCards.searchDolliCards(e.detail.hits); 281 }); 282 283 this.init = true; 284 } 285 }, 286 } 287 288 Drupal.behaviors.autoCompleteCards = { 289 290 filterHelper : Drupal.behaviors.filterDoliData, 291 DolliHelper : Drupal.behaviors.DoliData, 292 renderHelper : Drupal.behaviors.renderHelper, 293 placeHelper : Drupal.behaviors.placeItems, 294 295 searchDolliCards: async function (algoliaHits) { 296 var IDs = this.filterHelper.getAllId(algoliaHits); 297 var dollieFilterItems = await this.DolliHelper.requestGroupCall(IDs.toString()); 298 var newItems = this.filterHelper.sortItems(dollieFilterItems); 299 var render = this.renderHelper.createCards(newItems); 300 301 this.placeHelper.removeEmptyMessage(); 302 if (render.length > 0){ 303 this.placeHelper.placeItems(render); 304 } 305 else { 306 this.placeHelper.displayEmptyMessage(this.renderHelper.noTripsMessage); 307 } 308 } 309 } 310 311 // Make the View more items to submit 312 Drupal.behaviors.submitFormInMegaMenu = { 313 attach : function(context, settings) { 314 once('algolia-view-more','.js-algoia-view-more', context).forEach(function(element) { 315 $form = document.querySelector('.ais-SearchBox .ais-SearchBox-form'); 316 element.addEventListener('click', function(){ 317 $form.submit(); 318 }); 319 320 }); 321 } 322 } 323 324 325 326 327 // https://www.drupal.org/forum/support/module-development-and-code-questions/2016-12-06/load-a-ajax-form-with-ajax-call 328 // https://drupal.stackexchange.com/questions/273249/how-to-load-and-render-a-webform-with-ajax 329 Drupal.behaviors.loadAgentAjaxForm = { 330 attach: function (context, settings) { 331 332 once('loadFormOnceVisible', '.js-load-form', context).forEach((element)=>{ 333 // Originally I only wanted load form when it was visible by opening the modal, but I guess it ignores css styles and runs when page is loaded anyway 334 let observer = new IntersectionObserver(this.intersectionObserverCallback.bind(this), {}); 335 observer.observe(element); 336 }); 337 }, 338 339 // This function Runs the observer 340 intersectionObserverCallback: function(entries, observer) { 341 entries.forEach((entry) => { 342 this.loadForm(); 343 observer.unobserve(entry.target); 344 }) 345 }, 346 347 348 loadForm: function() { 349 var that = this; 350 351 $.ajax({ 352 url: Drupal.url('admin/agent-form'), 353 type:"GET", 354 contentType:"application/json; charset=utf-8", 355 dataType:"json", 356 success: (response) => { 357 that.onloadSuccess(response); 358 } 359 }); 360 }, 361 362 onloadSuccess : function(response) { 363 // return; 364 var that = this; 365 var $wrapper = $('.js-load-form'); 366 $wrapper.html(response.form_html); 367 // Drupal.attachBehaviors($wrapper[0]); // This break js items that arent using once in js as it run through Behaviors again 368 var submitButton = $wrapper[0].querySelector('#edit-actions-submit'); // this is how the form is submitted; 369 var webform = $wrapper[0].querySelector('form'); 370 371 372 submitButton.addEventListener('click', (e)=> { 373 e.preventDefault(); 374 that.submitForm(webform); 375 }); 376 }, 377 378 submitForm: function(webform){ 379 var actionURL = Drupal.url('admin/submit-agent-form/'); 380 var that = this; 381 $.ajax({ 382 url: actionURL, 383 type: 'POST', 384 data: $(webform).serialize(), 385 dataType: 'json', 386 success: function (response) { 387 that.onSubmitSuccess(response); 388 } 389 }) 390 }, 391 392 onSubmitSuccess : function(response) { 393 if (response.status === 'success') { 394 if(response.confirm_data.confirmation_type == "url"){ 395 var newUrl = response.confirm_data.confirmation_url; 396 window.location = newUrl; 397 } 398 399 } else { 400 // Handle and display form errors. 401 var errors = response.errors; 402 $.each(errors, function (field, message) { 403 alert(message); 404 }); 405 } 406 } 407 408 } 409 410 411 Drupal.behaviors.toggleAgentFormContainer = { 412 413 AgentFormContainer : document.querySelector('header .afc'), 414 415 attach: function (context, settings) { 416 // Add event listeners so anything can toggle these 417 // const event = new Event("hideResultsContainer"); dispatch document.dispatchEvent(event); 418 once('setListenersAgentFormContainer','html').forEach(()=>{ 419 document.addEventListener('hideAgentFormContainer', this.hideAgentFormContainer.bind(this)); 420 document.addEventListener('showAgentFormContainer', this.showAgentFormContainer.bind(this)); 421 document.addEventListener('toggleAgentFormContainer', this.toggleAgentFormContainer.bind(this)); 422 }); 423 424 once('closeAgentFormContainer', "html").forEach(() => { 425 document.addEventListener('click', (event) => { 426 if(!document.querySelector('header .afc').contains(event.target)) { 427 this.hideAgentFormContainer(); 428 } 429 }) 430 }); 431 432 once('hideAgentFormContainer','.js-hide-afc', context).forEach((button)=>{ 433 button.addEventListener('click', this.hideAgentFormContainer.bind(this)); 434 }); 435 436 once('showAgentFormContainer','.js-show-afc', context).forEach((button)=>{ 437 button.addEventListener('click', this.showAgentFormContainer.bind(this)); 438 }); 439 440 once('toggleAgentFormContainer','.js-toggle-afc', context).forEach((button)=>{ 441 button.addEventListener('click', this.toggleAgentFormContainer.bind(this)); 442 }); 443 444 once('hoverAgentFormContainer','.js-hover-show-afc ', context).forEach((button)=>{ 445 button.addEventListener('mouseover', this.mouseOverButton.bind(this)); 446 // document.querySelector('header').addEventListener('mouseleave',this.mouseUpButton.bind(this)); 447 }); 448 449 }, 450 451 showAgentFormContainer : function () { 452 this.AgentFormContainer.classList.add ('afc--show'); 453 // Drupal.behaviors.toggleInputContainer.showInputContainer(); // Container has been removed 454 }, 455 456 hideAgentFormContainer : function() { 457 this.AgentFormContainer.classList.remove ('afc--show'); 458 // Drupal.behaviors.toggleInputContainer.hideInputContainer(); 459 }, 460 461 toggleAgentFormContainer : function() { 462 (this.isVisibleAgentFormContainer()) ? this.hideAgentFormContainer() : this.showAgentFormContainer(); // If Visible hide, if not show 463 }, 464 465 isVisibleAgentFormContainer : function () {
466 return this.AgentFormContainer.classList.contains('afc--show'); 467 }, 468 469 mouseOverButton: function(element) { 470 if (this.isVisibleAgentFormContainer()) { return; } // If Form is already visible ignore hover feature 471 this.AgentFormContainer.classList.add('js-afc-is-hovered'); // This class is to let the hover know it can hide container when no longer in hover 472 this.showAgentFormContainer(); 473 }, 474 475 mouseUpButton: function() { 476 if (!this.AgentFormContainer.classList.contains('js-afc-is-hovered')) { return; } 477 this.AgentFormContainer.classList.remove('js-afc-is-hovered'); 478 this.hideAgentFormContainer(); 479 } 480 481 } 482 483 484})(jQuery, Drupal, drupalSettings, once);
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.