1if (typeof window.JItemAction === "undefined") { 2 // class JItemAction 3 JItemAction = function (node, config) { 4 node = typeof node === "object" && node && node instanceof Node ? node : null; 5 config = typeof config === "object" && config ? config : {}; 6 7 this.node = node; 8 9 var _private = { 10 inited: false, 11 data: null, 12 config: { 13 bindEvents: true, 14 changeState: true, 15 fireGoals: true, 16 }, 17 }; 18 19 let _config = Object.assign({}, _private.config, config); 20 21 Object.defineProperties(this, { 22 inited: { 23 get: function () { 24 return _private.inited; 25 }, 26 set: function (value) { 27 if (value) { 28 _private.inited = true; 29 } 30 }, 31 }, 32 33 config: { 34 get: function () { 35 return _config; 36 }, 37 }, 38 39 data: { 40 get: function () { 41 let data = null; 42 43 if (this.valid) { 44 data = this.node.dataset; 45 } 46 47 if (_private.data) { 48 data = _private.data; 49 } 50 51 return Object.assign({}, data); 52 }, 53 set: function (data) { 54 _private.data = data; 55 }, 56 }, 57 }); 58 59 this.init(); 60 }; 61 62 JItemAction.prototype = { 63 constructor: JItemAction, 64 busy: false, 65 parentNode: null, 66 prevState: null, 67 activeClass: "added in", 68 69 get class() { 70 return this.constructor.name; 71 }, 72 73 get action() { 74 return ""; 75 }, 76 77 get requestUrl() { 78 return `aspro:max.ItemAction.${this.action}`; 79 }, 80 81 get valid() { 82 return this.node && this.action; 83 }, 84 85 get state() { 86 if (!this.config.changeState) { 87 return true; 88 } 89 return this.valid && BX.hasClass(this.node, this.activeClass); 90 }, 91 92 set state(value) { 93 if (this.valid && this.config.changeState) { 94 this.node.removeAttribute("style"); //for sku 95 if (value != this.state) { 96 if (value) { 97 BX.addClass(this.node, this.activeClass); 98 } else { 99 BX.removeClass(this.node, this.activeClass); 100 } 101 102 let title = this.getStateTitle(value); 103 this.node.setAttribute("title", title); 104 105 let button = this.node.querySelector(".info-buttons__item-text"); 106 if (button) { 107 button.setAttribute("title", title); 108 } 109 110 if (BX.hasClass(this.node, "btn")) { 111 const $likeText = this.node.querySelector(".like-text"); 112 if ($likeText) { 113 $likeText.textContent = title; 114 } 115 } 116 } 117 } 118 }, 119 120 init: function () { 121 if (!this.inited) { 122 this.inited = true; 123 124 if (this.valid) { 125 this.node.itemAction = this; 126 this.parentNode = this.node.parentElement; 127 128 if (this.data.offers === "Y") { 129 this.data = this.node.dataset; 130 } 131 132 if (this.config.bindEvents) { 133 this.unbindAllEvents(); 134 this.bindEvents(); 135 } 136 } 137 } 138 }, 139 140 bindEvents: function () { 141 if (this.valid) { 142 if (typeof this.handlers.onClickNode === "function") { 143 BX.bind(this.node, "click", BX.proxy(this.handlers.onClickNode, this)); 144 } 145 } 146 }, 147 148 unbindEvents: function () { 149 if (this.valid) { 150 if (typeof this.handlers.onClickNode === "function") { 151 BX.unbind(this.node, "click", BX.proxy(this.handlers.onClickNode, this)); 152 } 153 } 154 }, 155 156 unbindAllEvents: function () { 157 if (this.valid) { 158 BX.unbindAll(this.node, "click"); 159 } 160 }, 161 162 fireEvent: function (event) { 163 if (this.valid && !this.busy && typeof event === "object" && event) { 164 let eventType = event.type; 165 if (eventType) { 166 if (eventType === "click") { 167 BX.proxy(this.handlers.onClickNode, this)(event); 168 } 169 } 170 } 171 }, 172 173 isStateChanged: function () { 174 return this.prevState !== null && this.prevState != this.state; 175 }, 176 177 isItemChanged: function () { 178 return this.node !== null && this.node.dataset["item"] != this.data.item; 179 }, 180 181 getStateTitle: function (state) { 182 if (this.valid) { 183 if (state) { 184 return this.node.getAttribute("data-title_added") || ""; 185 } else { 186 return this.node.getAttribute("data-title") || ""; 187 } 188 } 189 190 return ""; 191 }, 192 193 getStateGoalCode: function (state) { 194 return "goal_" + this.action + (state ? "_add" : "_remove"); 195 }, 196 197 showStateNotice: function (state) { 198 this.showNotice([this.node], state); 199 }, 200 showNotice: function (items, state = 1) { 201 if (this.valid && typeof JNoticeSurface === "function") { 202 let surface = JNoticeSurface.get(); 203 let actionCapitalize = this.action.replace(/^\w/, c => c.toUpperCase()); 204 let noticeFunc = "onAdd2" + actionCapitalize; 205 206 if (noticeFunc && typeof surface[noticeFunc] === "function") { 207 surface[noticeFunc](items, state); 208 } 209 } 210 }, 211 212 updateState: function () { 213 if (this.valid && !this.busy) { 214 this.busy = true; 215 216 this.node.blur(); 217 218 this.prevState = this.state; 219 220 this.sendRequest(); 221 } 222 }, 223 224 collectRequestData: async function () { 225 const data = { fields: {} }; 226
227 data["fields"] = this.data; 228 data["fields"]["state"] = Number(this.state); 229 230 return data; 231 }, 232 233 sendRequest: function () { 234 if (this.valid) { 235 this.collectRequestData() 236 .then(data => { 237 BX.ajax.runAction(this.requestUrl, { data }).then( 238 response => { 239 if (typeof this.onRequestSuccess === "function") { 240 this.onRequestSuccess(response); 241 } 242 243 if (typeof this.onRequestComplete === "function") { 244 this.onRequestComplete(data); 245 } 246 }, 247 response => { 248 if (typeof this.onRequestFailure === "function") { 249 this.onRequestFailure(response); 250 } 251 252 if (typeof this.onRequestComplete === "function") { 253 this.onRequestComplete(data); 254 } 255 } 256 ); 257 }) 258 .catch(() => { 259 setTimeout(() => { 260 if (this.isStateChanged()) { 261 // toggle state back 262 this.state = this.prevState; 263 this.prevState = null; 264 } 265 266 if (this.parentNode) { 267 BX.removeClass(this.parentNode, "loadings"); 268 } 269 270 this.busy = false; 271 }, 0); 272 }); 273 } 274 }, 275 276 onRequestComplete: function (config) { 277 setTimeout(() => { 278 if (this.parentNode) { 279 BX.removeClass(this.parentNode, "loadings"); 280 } 281 this.busy = false; 282 }, 0); 283 }, 284 285 onRequestSuccess: function (response) { 286 if (response.status === "success") { 287 if (this.action && response.data) { 288 let actionUpper = this.action.toUpperCase(); 289 290 if (typeof arAsproCounters !== "object") { 291 arAsproCounters = {}; 292 } 293 294 if (typeof arAsproCounters[actionUpper] !== "object") { 295 arAsproCounters[actionUpper] = {}; 296 } 297 298 const data = response.data; 299 if ("items" in data) { 300 arAsproCounters[actionUpper].ITEMS = data.items; 301 } 302 303 if ("count" in data) { 304 arAsproCounters[actionUpper].COUNT = data.count; 305 } 306 307 if ("title" in data) { 308 arAsproCounters[actionUpper].TITLE = data.title; 309 } 310 311 // update badges 312 if ( 313 this.class && 314 typeof window[this.class] === "function" && 315 typeof window[this.class].markBadges === "function" 316 ) { 317 window[this.class].markBadges(); 318 } 319 320 let state = this.state; 321 322 // mark items 323 if ( 324 this.class && 325 typeof window[this.class] === "function" && 326 typeof window[this.class].markItems === "function" 327 ) { 328 window[this.class].markItems(); 329 } 330 331 if (this.isStateChanged()) { 332 // show notice 333 this.showStateNotice(state); 334 335 if (this.config.fireGoals) { 336 // fire goal 337 BX.onCustomEvent("onCounterGoals", [ 338 { 339 goal: this.getStateGoalCode(state), 340 params: { 341 id: this.node.getAttribute("data-item"), 342 }, 343 }, 344 ]); 345 } 346 } 347 348 this.onCompleteEvent(); 349 } 350 } else { 351 console.error(response); 352 353 if (this.isStateChanged()) { 354 // toggle state back 355 this.state = this.prevState; 356 } 357 358 // show error notice 359 if (typeof JNoticeSurface === "function") { 360 let surface = JNoticeSurface.get(); 361 response.error = this.getMessageFromErrors(response.errors); 362 363 surface.onResultError && surface.onResultError(response); 364 } 365 } 366 }, 367 368 onRequestFailure: function (xhr) { 369 if (this.isStateChanged()) { 370 // toggle state back 371 this.state = this.prevState; 372 } 373 374 // show error notice 375 if (typeof JNoticeSurface === "function") { 376 let surface = JNoticeSurface.get(); 377 xhr.statusText = this.getMessageFromErrors(xhr.errors); 378 379 surface.onRequestError && surface.onRequestError(xhr); 380 } 381 }, 382 383 getMessageFromErrors: function (errors) { 384 let messages = []; 385 if (errors.length) {
386 errors.forEach(error => { 387 messages.push(error.message); 388 }); 389 } 390 return messages.join("<br>"); 391 }, 392 393 onCompleteEvent: function () {}, 394 395 handlers: { 396 onClickNode: function (event) { 397 if (this.valid && !this.busy) { 398 if (!event) { 399 event = window.event; 400 } 401 402 let target = event.target || event.srcElement; 403 404 if (typeof target !== "undefined" && target) { 405 this.busy = true; 406 407 this.node.blur(); 408 409 this.prevState = this.state; 410 this.state = !this.state; 411 412 this.sendRequest(); 413 } 414 } 415 }, 416 }, 417 }; 418 419 JItemAction.checkItemAction = function (node) { 420 return node.itemAction && node.itemAction instanceof JItemAction; 421 }; 422 423 JItemAction.getItemAction = function (node) { 424 return node.itemAction; 425 }; 426 427 // factory: returns a concrete JItemAction instance 428 JItemAction.factory = function (node, config) { 429 if (typeof node === "object" && node && node instanceof Node) { 430 if (JItemAction.checkItemAction(node)) { 431 return JItemAction.getItemAction(node); 432 } else { 433 let action = (node.getAttribute("data-action") || "").trim(); 434 if (action) { 435 let actionCapitalize = action.replace(/^\w/, c => c.toUpperCase()); 436 let className = "JItemAction" + actionCapitalize; 437 if (typeof window[className] === "function") { 438 return new window[className](node, config); 439 } 440 } 441 } 442 } 443 444 return new window.JItemAction(node, config); 445 }; 446 447 // class JItemActionFavorite 448 JItemActionFavorite = function (node, config) { 449 JItemAction.apply(this, arguments); 450 }; 451 452 JItemActionFavorite.prototype = Object.create(JItemAction.prototype); 453 JItemActionFavorite.prototype.constructor = JItemActionFavorite; 454 Object.defineProperties(JItemActionFavorite.prototype, { 455 action: { 456 get() { 457 return "favorite"; 458 }, 459 }, 460 }); 461 462 JItemActionFavorite.prototype.getStateGoalCode = function (state) { 463 return "goal_wish" + (state ? "_add" : "_remove"); 464 }; 465 466 // set current count into badges 467 JItemActionFavorite.markBadges = function () { 468 if ( 469 typeof arAsproCounters === "object" && 470 arAsproCounters && 471 typeof arAsproCounters.FAVORITE === "object" && 472 arAsproCounters.FAVORITE && 473 typeof arAsproCounters.FAVORITE.COUNT !== "undefined" 474 ) { 475 let blocks = Array.prototype.slice.call(document.querySelectorAll(".basket-link.delay .js-count")); 476 if (blocks.length) { 477 for (let i in blocks) { 478 blocks[i].textContent = arAsproCounters.FAVORITE.COUNT; 479 if (arAsproCounters.FAVORITE.COUNT > 0) { 480 BX.removeClass(blocks[i], "empted"); 481 BX.addClass(blocks[i].closest(".basket-link.delay"), "basket-count"); 482 BX.removeClass(blocks[i].closest(".basket-link.delay"), "counter-state--empty"); 483 } else { 484 BX.addClass(blocks[i], "empted"); 485 BX.removeClass(blocks[i].closest(".basket-link.delay"), "basket-count"); 486 BX.addClass(blocks[i].closest(".basket-link.delay"), "counter-state--empty"); 487 } 488 } 489 } 490 } 491 }; 492 493 // setup active state for all current items 494 JItemActionFavorite.markItems = function () { 495 if ( 496 typeof arAsproCounters === "object" && 497 arAsproCounters && 498 typeof arAsproCounters.FAVORITE === "object" && 499 arAsproCounters.FAVORITE && 500 typeof arAsproCounters.FAVORITE.ITEMS === "object" && 501 arAsproCounters.FAVORITE.ITEMS 502 ) { 503 let blocks = Array.prototype.slice.call( 504 document.querySelectorAll('.js-item-action.added.in[data-action="favorite"]') 505 ); 506 if (blocks.length) { 507 for (let y in blocks) { 508 let id = BX.data(blocks[y], "item"); 509 if (id) { 510 if (!arAsproCounters.FAVORITE.ITEMS[id] || BX.data(blocks[y], "offers") === "Y") { 511 let itemAction = JItemAction.checkItemAction(blocks[y]) ? JItemAction.getItemAction(blocks[y]) : ""; 512 513 if (BX.data(blocks[y], "offers") === "Y") { 514 if (itemAction && itemAction.isItemChanged()) { 515 itemAction = new this(blocks[y]); 516 } 517 } 518 519 if (!itemAction) { 520 itemAction = new this(blocks[y]); 521 } 522 523 itemAction.state = false;
524 } 525 } 526 } 527 } 528 529 if (arAsproCounters.FAVORITE.ITEMS) { 530 for (let i in arAsproCounters.FAVORITE.ITEMS) { 531 let id = arAsproCounters.FAVORITE.ITEMS[i]; 532 let blocks = Array.prototype.slice.call( 533 document.querySelectorAll('.js-item-action[data-action="favorite"][data-item="' + id + '"]:not(.added.in)') 534 ); 535 536 if (blocks.length) { 537 for (let y in blocks) { 538 let itemAction = JItemAction.checkItemAction(blocks[y]) 539 ? JItemAction.getItemAction(blocks[y]) 540 : new this(blocks[y]); 541 itemAction.state = true; 542 } 543 } 544 } 545 } 546 } 547 }; 548 549 JItemAction.actual = function () { 550 if (typeof JItemActionFavorite === "function") { 551 JItemActionFavorite.markItems(); 552 JItemActionFavorite.markBadges(); 553 } 554 }; 555 556 // bind handler for click on .js-item-action 557 BX.bindDelegate( 558 document, 559 "click", 560 { 561 class: "js-item-action", 562 }, 563 function (event) { 564 if (!event) { 565 event = window.event; 566 } 567 568 BX.PreventDefault(event); 569 570 let target = event.target || event.srcElement; 571 572 if (typeof target !== "undefined" && target) { 573 if (!target.closest(".opt_action")) { 574 JItemAction.factory(this).fireEvent(event); 575 } 576 } 577 } 578 ); 579 580 // on complete loading content by ajax 581 BX.addCustomEvent("onCompleteAction", function (eventdata) { 582 try { 583 if (eventdata.action === "ajaxContentLoaded") { 584 JItemAction.actual(); 585 } 586 } catch (e) { 587 console.error(e); 588 } 589 }); 590 591 BX.addCustomEvent("onSetBasketStatusBtn", function (eventdata) { 592 JItemAction.actual(); 593 }); 594 595 BX.addCustomEvent("onSetItemButtonStatus", function (eventdata) { 596 JItemAction.actual(); 597 }); 598 599 BX.addCustomEvent("onAjaxResponesTabs", function (eventdata) { 600 JItemAction.actual(); 601 }); 602 603 BX.addCustomEvent("onFinalActionSKUInfo", function (eventdata) { 604 JItemAction.actual(); 605 }); 606 607 /* 608 // set current items states 609 readyDOM(function () { 610 JItemAction.actual(); 611 }); */ 612}
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.