1; 2 3var Commerce = (function() { 4 var CommerceEvent = function(target, name, data) { 5 this.event = new CustomEvent(name, { 6 cancelable: true, 7 bubbles: true, 8 detail: data 9 }); 10 11 target.dispatchEvent(this.event); 12 13 if (window.jQuery) { 14 this.$event = $.Event(name); 15 jQuery(target).trigger(this.$event, data); 16 } 17 18 this.isPrevented = function() { 19 if (this.event.defaultPrevented || this.event.returnValue === false) { 20 return true; 21 } 22 23 if (window.jQuery) { 24 if (this.$event.isDefaultPrevented() || typeof this.$event.result != 'undefined' && this.$event.result === false) { 25 return true; 26 } 27 } 28 29 return false; 30 }; 31 32 return this; 33 }; 34 35 function triggerEvent(target, name, data) { 36 return new CommerceEvent(target, name, data); 37 } 38 39 /** 40 * Convert object to FormData, based on object-to-formdata by Parmesh Krishen 41 * @link https://github.com/therealparmesh/object-to-formdata 42 * @license MIT 43 */ 44 function objectToFormData(object) { 45 function isArray(value) { 46 return Array.isArray(value); 47 } 48 49 function isBlob(value) { 50 return value && 51 typeof value.size === 'number' && 52 typeof value.type === 'string' && 53 typeof value.slice === 'function'; 54 } 55 56 function isFile(value) { 57 return isBlob(value) && 58 typeof value.name === 'string' && 59 (typeof value.lastModifiedDate === 'object' || 60 typeof value.lastModified === 'number'); 61 } 62 63 function serialize(value, fd, prefix) { 64 fd = fd || new FormData(); 65 66 if (value === undefined) { 67 return fd; 68 } else if (value === null) { 69 fd.append(prefix, ''); 70 } else if (typeof value === 'boolean') { 71 fd.append(prefix, value); 72 } else if (isArray(value)) { 73 if (value.length) { 74 value.forEach(function(val, index) { 75 serialize(val, fd, prefix + '[' + index + ']'); 76 }); 77 } else { 78 fd.append(prefix + '[]', ''); 79 } 80 } else if (value instanceof Date) { 81 fd.append(prefix, value.toISOString()); 82 } else if (value === Object(value) && !isFile(value) && !isBlob(value)) { 83 Object.keys(value).forEach(function(prop) { 84 var val = value[prop]; 85 86 if (isArray(val)) { 87 while (prop.length > 2 && prop.lastIndexOf('[]') === prop.length - 2) { 88 prop = prop.substring(0, prop.length - 2); 89 } 90 } 91 92 var key = prefix ? prefix + '[' + prop + ']' : prop; 93 94 serialize(val, fd, key); 95 }); 96 } else { 97 fd.append(prefix, value); 98 } 99 100 return fd; 101 } 102 103 return serialize(object); 104 } 105 106 /** 107 * Form serialization, based on jQuery serializeObject 108 * @copyright 2014, macek <[email protected]> 109 * @link https://github.com/macek/jquery-serialize-object 110 * @license BSD 111 */ 112 function serializeForm(form) { 113 var self = this, 114 json = {}, 115 push_counters = {}, 116 patterns = { 117 "validate": /^[a-zA-Z][a-zA-Z0-9_]*(?:\[ *(?:\d*|[a-zA-Z0-9_]+) *\])*$/, 118 "key": /[a-zA-Z0-9_]+|(?=\[\])/g, 119 "push": /^$/, 120 "fixed": /^\d+$/, 121 "named": /^[a-zA-Z0-9_]+$/ 122 }; 123 124 this.build = function(base, key, value) { 125 base[key] = value; 126 return base; 127 }; 128 129 this.push_counter = function(key) { 130 if (push_counters[key] === undefined) { 131 push_counters[key] = 0; 132 } 133 return push_counters[key]++; 134 }; 135
136 Array.from(new FormData(form)).forEach(function(row) { 137 // Skip invalid keys 138 if (!patterns.validate.test(row[0])) { 139 return; 140 } 141 142 var k, 143 keys = row[0].match(patterns.key), 144 merge = row[1], 145 reverse_key = row[0]; 146 147 while ((k = keys.pop()) !== undefined) { 148 // Adjust reverse_key 149 reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), ''); 150 151 // Push 152 if (k.match(patterns.push)) { 153 merge = self.build([], self.push_counter(reverse_key), merge); 154 } 155 156 // Fixed 157 else if (k.match(patterns.fixed)) { 158 merge = self.build([], k, merge); 159 } 160 161 // Named 162 else if (k.match(patterns.named)) { 163 merge = self.build({}, k, merge); 164 } 165 } 166 167 json = extendObject({}, json, merge); 168 }); 169 170 return json; 171 } 172 173 function serializeDataAttributes(element) { 174 var data = {}; 175 176 [].forEach.call(element.attributes, function(attr) { 177 if (/^data-/.test(attr.name)) { 178 var camelCaseName = attr.name.substr(5).replace(/-(.)/g, function ($0, $1) { 179 return $1.toUpperCase(); 180 }); 181 182 data[camelCaseName] = attr.value; 183 } 184 }); 185 186 return data; 187 } 188 189 function extendObject(out) { 190 out = out || {}; 191 192 for (var i = 1; i < arguments.length; i++) { 193 var obj = arguments[i], key; 194 195 if (!obj) { 196 continue; 197 } 198 199 if (obj instanceof Array == true) { 200 for (key = 0; key < obj.length; key++) { 201 if (typeof obj[key] == 'undefined') { 202 continue; 203 } 204 205 if (typeof obj[key] === 'object') { 206 out[key] = extendObject(out[key], obj[key]); 207 } else { 208 out[key] = obj[key]; 209 } 210 } 211 } else { 212 for (key in obj) { 213 if (!obj.hasOwnProperty(key)) { 214 continue; 215 } 216 217 if (typeof obj[key] === 'object') { 218 out[key] = extendObject(out[key], obj[key]); 219 } else { 220 out[key] = obj[key]; 221 } 222 } 223 } 224 } 225 226 return out; 227 } 228 229 function markupToElement(markup) { 230 var template = document.createElement('template'); 231 template.innerHTML = markup.trim(); 232 return template.content.firstChild; 233 } 234 235 function getCartsHashes() { 236 var carts = document.querySelectorAll('[data-commerce-cart]'), 237 form = document.querySelector('[data-commerce-order]'), 238 hashes = { 239 carts: [] 240 }; 241 242 Array.prototype.forEach.call(carts, function(cart) { 243 hashes.carts.push(cart.getAttribute('data-commerce-cart')); 244 }); 245 246 if (form) { 247 hashes.form = form.getAttribute('data-commerce-order'); 248 } 249 250 var event = triggerEvent(document, 'collect-hashes.commerce', { 251 hashes: hashes 252 }); 253 254 if (!event.isPrevented()) { 255 return hashes; 256 } 257 258 return hashes; 259 } 260
261 function reloadMarkupFromResponse(markup) { 262 if (typeof markup.carts == 'object') { 263 for (var hash in markup.carts) { 264 var carts = document.querySelectorAll('[data-commerce-cart="' + hash + '"]'); 265 266 if (carts.length) { 267 for (var i = 0; i < carts.length; i++) { 268 var newCart = markupToElement(markup.carts[hash]), 269 event = triggerEvent(carts[i], 'cart-reload.commerce', {newCart: newCart}); 270 271 if (event.isPrevented()) { 272 return; 273 } 274 275 carts[i].replaceWith(newCart); 276 triggerEvent(newCart, 'cart-reloaded.commerce'); 277 } 278 } 279 } 280 } 281 282 if (typeof markup.form == 'object') { 283 var node; 284 285 if (typeof markup.form.delivery != 'undefined') { 286 node = document.querySelector('[data-commerce-deliveries]'); 287 288 if (node) { 289 node.innerHTML = markup.form.delivery; 290 } 291 } 292 293 if (typeof markup.form.payments != 'undefined') { 294 node = document.querySelector('[data-commerce-payments]'); 295 296 if (node) { 297 node.innerHTML = markup.form.payments; 298 } 299 } 300 301 triggerEvent(document.querySelector('[data-commerce-order]'), 'form-reloaded.commerce'); 302 } 303 } 304 305 function handleActionEvent(e) { 306 if (this.tagName == 'FORM' && e.type != 'submit') { 307 return; 308 } 309 310 var self = this, 311 action = self.getAttribute('data-commerce-action'), 312 row = self.getAttribute('data-commerce-row'), 313 data = serializeDataAttributes(self), 314 cartContainer = self.closest('[data-commerce-cart]'), 315 parent; 316 317 if (!row) { 318 parent = self.closest('[data-commerce-row]'); 319 320 if (parent) { 321 row = parent.getAttribute('data-commerce-row'); 322 } 323 } 324 325 var cart = { 326 instance: self.getAttribute('data-instance') || (cartContainer ? cartContainer.getAttribute('data-instance') : null) || 'products', 327 hash: cartContainer ? cartContainer.getAttribute('data-commerce-cart') : null 328 }; 329 330 if (action == 'redirect-to-payment') { 331 e.preventDefault(); 332 var link = self.getAttribute('data-redirect-link'); 333 334 if (link && link != '') { 335 location.href = link; 336 } else { 337 document.querySelector('form#payment_request').submit(); 338 } 339 340 return; 341 } 342 343 if (action == 'add') { 344 e.preventDefault(); 345 346 if (e.type == 'submit') { 347 data = serializeForm(self); 348 } 349 350 data.cart = cart; 351 352 if (data.batch && typeof data.batch == 'object') { 353 for (var i in data.batch) { 354 if (!data.batch[i].id) { 355 delete data.batch[i]; 356 } 357 } 358 359 Commerce.action('cart/addmultiple', data, self); 360 } else { 361 Commerce.action('cart/add', data, self); 362 } 363 364 return; 365 } 366 367 if (e.type == 'click') { 368 e.preventDefault(); 369 370 switch (action) { 371 case 'increase': 372 case 'decrease': { 373 var rowField = cartContainer.querySelector('[data-commerce-row="' + row + '"]'), 374 countField = rowField.matches('input[name="count"]') ? rowField : rowField.querySelector('input[name="count"]'); 375 376 if (countField) { 377 var min = parseFloat(countField.getAttribute('data-min')), 378 max = parseFloat(countField.getAttribute('data-max')), 379 count = parseFloat(countField.value) || 0, 380 diff = data.count ? parseFloat(data.count) || 1 : 1; 381 382 count += action == 'increase' ? diff : -diff; 383 count = Math.max(0, count); 384 385 if (!count && (min !== min || min === 0)) { 386 Commerce.action('cart/remove', {row: row, cart: cart, data: data}, self); 387 } else if ((min !== min || count >= min) && (max !== max || count <= max )) { 388 count.value = count; 389 Commerce.action('cart/update', {row: row, cart: cart, data: data, attributes: {count: count}}, self); 390 } 391 } 392 393 return; 394 } 395 396 case 'remove': { 397 Commerce.action('cart/remove', {row: row, cart: cart, data: data}, self); 398 return; 399 } 400 401 case 'clean': { 402 Commerce.action('cart/clean', {cart: cart, data: data}, self); 403 return; 404 } 405 } 406 } 407 408 if (e.type == 'change') { 409 switch (action) { 410 case 'recount': { 411 var count = parseFloat(self.value) || 0, 412 min = parseFloat(self.getAttribute('data-min')) || 0, 413 max = parseFloat(self.getAttribute('data-max')) || count; 414 415 if (count >= 0) { 416 if (!count && !min) { 417 Commerce.action('cart/remove', {row: row, cart: cart, data: data}, self); 418 } else if (count >= min && count <= max) { 419 Commerce.action('cart/update', {row: row, cart: cart, data: data, attributes: {count: count}}, self); 420 } 421 } 422 423 return; 424 } 425 } 426 } 427 } 428 429 function handleOrderChange(e) { 430 if (['delivery_method', 'payment_method'].indexOf(e.target.name) !== -1) { 431 Commerce.updateOrderData(this); 432 } 433 } 434 435 function delegateEvent(events, selector, handler) { 436 if (!(events instanceof Array)) { 437 events = [events]; 438 } 439
440 events.forEach(function(event) { 441 document.addEventListener(event, function(e) { 442 for (var target = e.target; target && target != this; target = target.parentNode) { 443 if (target.matches(selector)) { 444 handler.call(target, e); 445 break; 446 } 447 } 448 }, false); 449 }); 450 } 451 452 function request(url, data, callback) { 453 if (!data) { 454 data = {}; 455 } 456 457 fetch(url, { 458 method: 'POST', 459 body: objectToFormData(data) 460 }) 461 .then(function(response) { 462 return response.json(); 463 }) 464 .then(function(response) { 465 Commerce.serverResponse = response; 466 callback.call(Commerce, response); 467 }); 468 } 469 470 if (window.jQuery) { 471 jQuery(document).on('submit click change', '[data-commerce-action]', function(e) { 472 handleActionEvent.call(this, e); 473 }); 474 475 jQuery(document).on('change', '[data-commerce-order]', function(e) { 476 handleOrderChange.call(this, e); 477 }); 478 } else { 479 delegateEvent(['submit', 'click', 'change'], '[data-commerce-action]', handleActionEvent); 480 481 delegateEvent('change', '[data-commerce-order]', handleOrderChange); 482 } 483 484 delegateEvent('cart-remove-complete.commerce', '.comparison-table, .wishlist-table', function(e) { 485 window.location.reload(); 486 }); 487 488 document.addEventListener('DOMContentLoaded', function() { 489 if (Commerce.params.isCartPage) { 490 Commerce.reloadCarts({order_completed: true}); 491 } 492 }); 493 494 return { 495 params: {}, 496 497 action: function(action, data, initiator) { 498 if (window.jQuery && initiator instanceof jQuery) { 499 initiator = initiator.get(0); 500 } 501 502 if (!initiator) { 503 initiator = document.body; 504 } 505 506 triggerEvent(initiator, 'action-start.commerce', { 507 action: action, 508 data: data 509 }); 510 511 var matches; 512 513 if (matches = action.match(/^([a-z]+)\/([a-z]+)$/)) { 514 var eventName = matches[1].charAt(0).toUpperCase() + matches[1].slice(1) + '-' + matches[2].charAt(0).toUpperCase() + matches[2].slice(1); 515 eventName = eventName.toLowerCase(); 516 517 var event = triggerEvent(initiator, eventName + '.commerce', data); 518 if (event.isPrevented()) { 519 return; 520 } 521 522 var hashes = getCartsHashes(); 523 524 (function(eventName, data, initiator) { 525 request(Commerce.params.path + 'commerce/action', { 526 action: action, 527 data: data, 528 hashes: hashes 529 }, function(response) { 530 if (response.markup) {
531 reloadMarkupFromResponse(response.markup); 532 } 533 534 if (!document.body.contains(initiator)) { 535 var container = initiator; 536 537 while (container.parentElement) { 538 container = container.parentElement; 539 } 540 541 if (container.hasAttribute('data-commerce-cart')) { 542 initiator = document.querySelector('[data-commerce-cart="' + container.getAttribute('data-commerce-cart') + '"]'); 543 544 if (!initiator) { 545 initiator = document.body; 546 } 547 } 548 } 549 550 triggerEvent(initiator, eventName + '-complete.commerce', { 551 response: response, 552 data: data 553 }); 554 555 triggerEvent(initiator, 'action-complete.commerce', { 556 response: response, 557 action: action, 558 data: data 559 }); 560 }); 561 })(eventName, data, initiator); 562 } 563 }, 564 565 add: function(id, count, options) { 566 options = options || {}; 567 var data = extendObject({}, options, { 568 id: id, 569 count: count || 1, 570 cart: { 571 instance: options.instance || 'products' 572 } 573 }); 574 575 return Commerce.action('cart/add', data); 576 }, 577 578 remove: function(row, options) { 579 options = options || {}; 580 return Commerce.action('cart/remove', { 581 row: row, 582 cart: { 583 instance: options.instance || 'products' 584 } 585 }); 586 }, 587 588 clean: function(instance) { 589 return Commerce.action('cart/clean', { 590 cart: { 591 instance: instance || 'products' 592 } 593 }); 594 }, 595 596 reloadCarts: function(options) { 597 if (typeof options == 'undefined') { 598 options = {}; 599 } 600 601 options.hashes = getCartsHashes(); 602 603 if (options.hashes.carts.length || options.hashes.form) { 604 request(Commerce.params.path + 'commerce/cart/contents', options, function(response) { 605 if (response.status == 'success' && response.markup) {
606 reloadMarkupFromResponse(response.markup); 607 triggerEvent(document, 'carts-reloaded.commerce'); 608 } 609 }); 610 } 611 }, 612 613 updateOrderData: function(form) { 614 if (window.jQuery && form instanceof jQuery) { 615 form = form.get(0); 616 } 617 618 var data = serializeForm(form); 619 620 data.hashes = getCartsHashes(); 621 622 triggerEvent(form, 'order-data-update.commerce', { 623 data: data 624 }); 625 626 request(Commerce.params.path + 'commerce/data/update', data, function(response) { 627 triggerEvent(form, 'order-data-updated.commerce', { 628 data: data, 629 response: response 630 }); 631 632 if (response.status == 'success') { 633 if (response.markup) { 634 reloadMarkupFromResponse(response.markup); 635 } 636 } 637 }); 638 }, 639 640 setCurrency: function(code) { 641 request(Commerce.params.path + 'commerce/currency/set', {code: code}, function(response) { 642 if (response.status == 'success') { 643 location.reload(); 644 } 645 }); 646 }, 647 648 formatPrice: function(price) { 649 var input = price, 650 cleaned = price.toString().replace(',', '.').replace(' ', ''), 651 number = parseFloat(cleaned), 652 minus = '', 653 curr = Commerce.params.currency; 654 655 if (number != cleaned) { 656 return input; 657 } 658 659 if (number < 0) { 660 minus = '-'; 661 number = -number; 662 } 663 664 var integer = parseInt(number.toFixed(curr.decimals)) + '', 665 left = integer.split(/(?=(?:\d{3})+$)/).join(curr.thsep), 666 right = (curr.decimals ? curr.decsep + Math.abs(number - integer).toFixed(curr.decimals).replace(/-/, 0).slice(2) : ''); 667 668 return minus + curr.left + left + right + curr.right; 669 }, 670 671 getServiceFunctions: function() { 672 return { 673 objectToFormData: objectToFormData, 674 serializeForm: serializeForm, 675 serializeDataAttributes: serializeDataAttributes, 676 extendObject: extendObject, 677 markupToElement: markupToElement, 678 delegateEvent: delegateEvent, 679 triggerEvent: triggerEvent, 680 request: request, 681 }; 682 } 683 }; 684}());
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.