1// DAR 2var lowopifzeroprd_ur115_20X = 'index.php?route=module/lowopifzeroprd/'; 3var lowopifzeroprd_url23X_30X = 'index.php?route=extension/module/lowopifzeroprd/'; 4var lowopifzeroprd_url401X = 'index.php?route=extension/lowopifzeroprd/module/lowopifzeroprd|'; 5var lowopifzeroprd_url402X = 'index.php?route=extension/lowopifzeroprd/module/lowopifzeroprd.'; 6 7var lowopifzeroprd = { 8 9 /* ------------------------------------------------------------------ * 10 * UPDATE / INJECT PRODUCT SCHEMA FOR GOOGLE SHOPPING * 11 * ------------------------------------------------------------------ */ 12 'updateschema': function (discountedNumeric) { 13 try { 14 /* remove any previously injected schema */ 15 $('#product-schema').remove(); 16 17 /* grab product meta from DOM */ 18 var productName = $('#product-title h1').clone().children().remove().end().text().trim() || 19 $('h1').first().clone().children().remove().end().text().trim(); 20 21 var brandName = $('.product-brand').first().text().trim(); 22 23 var skuMatch = $('#product-description').text().match(/SKU:\s*([A-Za-z0-9\-_]+)/i); 24 var sku = skuMatch ? skuMatch[1] : ''; 25 26 /* build schema object */ 27 var schemaData = { 28 "@context": "https://schema.org/", 29 "@type" : "Product", 30 "name" : productName, 31 "sku" : sku, 32 "brand" : { 33 "@type": "Brand", 34 "name" : brandName 35 }, 36 "offers" : { 37 "@type" : "Offer", 38 "priceCurrency" : "GBP", 39 "price" : discountedNumeric, 40 "availability" : "https://schema.org/InStock", 41 "url" : window.location.href 42 } 43 }; 44 45 /* inject new script tag */ 46 $('<script>', { 47 id : 'product-schema', 48 type: 'application/ld+json', 49 text: JSON.stringify(schemaData) 50 }).appendTo('head'); 51 } catch (e) { 52 if (window.console) { console.warn('lowopifzeroprd â schema inject failed:', e); } 53 } 54 }, 55 56 /* ------------------------------------------------------------------ * 57 * CALCULATE â10 % PRICE AND DISPLAY AS: <h2><del>OLD</del> NEW</h2> * 58 * ------------------------------------------------------------------ */ 59 'setprc': function () { 60 61 var postdata = $('#product input[type="text"], #product input[type="number"], #product input[type="hidden"], #product input[type="radio"]:checked, #product input[type="checkbox"]:checked, #product select, #product textarea'); 62 if ($('.product-info .cart').length) { // OC-1.5.X fallback 63 postdata = $('.product-info input[type="text"], .product-info input[type="number"], .product-info input[type="hidden"], .product-info input[type="radio"]:checked, .product-info input[type="checkbox"]:checked, .product-info select, .product-info textarea'); 64 } 65 66 $.ajax({ 67 url : lowopifzeroprd_url23X_30X + 'setprc', 68 type: 'post', 69 data: postdata, 70 dataType: 'json', 71 72 beforeSend: function () { $('.ulprc').after('<i class="fa fa-circle-o-notch fa-spin"></i>'); }, 73 complete : function () { $('.fa-spin').remove(); }, 74 75 success: function (json) { 76 if (json['success'] !== 1) return; 77 78 /* ---------- helpers ---------- */ 79 var fmtDisc = function (raw) { 80 /* strip currency, calc 10 % off, round correctly to 2 dp */ 81 var num = parseFloat(raw.replace(/[^0-9.\-]+/g, '')); 82 // multiply first, then round as an integer to avoid FP errors (e.g. 8.95 â 8.06, not 8.05) 83 var disc = (Math.round((num * 0.9) * 100) / 100).toFixed(2); 84 return raw.replace(/[\d\.,]+/, disc); 85 }; 86 87 /* remove any previously injected elements */ 88 $('.oldprc, .discprc').remove(); // tidy up earlier runs 89 90 /* ---------- determine prices ---------- */ 91 var originalTxt = json['price']; // ânormalâ price from the back-end 92 var discountedTxt = fmtDisc(originalTxt); // â10 % of the normal price 93 94 /* ---------- NEW MARK-UP ------------------------------------- * 95 * <h2 class="newprc"> 96 * <del style="color:#222222;">£99.99</del> £89.99 97 * </h2> 98 * ------------------------------------------------------------- */ 99 $('.newprc').html( 100 '<del style="color:#797979;">' + originalTxt + '</del> ' + discountedTxt 101 ); 102 103 /* ---------- TAX (unchanged) --------------------------------- */ 104 if (json['tax']) { 105 $('.extaxprc').html(json['tax']); 106 } 107 108 /* ---------- SCHEMA UPDATE ----------------------------------- */ 109 var discountedNumeric = parseFloat(discountedTxt.replace(/[^0-9.\-]+/g, '')); 110 lowopifzeroprd.updateschema(discountedNumeric); 111 } 112 }); 113 }, 114 115 116 /* ------------------------------------------------------------------ * 117 * PRICE ELEMENT SETUP / LISTENERS * 118 * ------------------------------------------------------------------ */ 119 'prcupdate': function () { 120 $('#product').parent().find('ul.list-unstyled').find('h2') 121 .parent().parent().addClass('ulprc'); 122 $('ul.ulprc li span').addClass('oldprc'); // normal price 123 $('ul.ulprc li h2').addClass('newprc'); // discounted price 124 if ($('.oldprc').length) { 125 $('ul.ulprc').find('li').eq(2).addClass('extaxprc'); 126 } else { 127 $('ul.ulprc').find('li').eq(1).addClass('extaxprc'); 128 } 129 130 // live listeners 131 $('input[name="quantity"]').on('keyup change', function () { 132 lowopifzeroprd.setprc(); 133 }); 134 $('#product select, #product input[type="checkbox"], #product input[type="radio"]') 135 .change(function () { 136 lowopifzeroprd.setprc(); 137 }); 138 139 /* --- NEW: run once on page load -------------------------------- */ 140 lowopifzeroprd.setprc(); // ensures plain products get the discount 141 }, 142 143 144 /* ------------------------------------------------------------------ * 145 * âAdd-to-cart in gridâ PRICE TAG HANDLING * 146 * ------------------------------------------------------------------ */ 147 'atgrid': function () { 148 var product_ids = [];
149 $("[onclick*='cart.add'], [onclick*='addToCart']").each(function () { 150 var target = $(this).closest('.product-thumb, .product-wrapper'); 151 var product_id = $(this).attr('onclick').match(/[0-9]+/).toString(); 152 if (target.length && !target.hasClass('lowopifzeroprd_atgridcol')) { 153 target.addClass('lowopifzeroprd_atgridcol lowopifzeroprd_atgridcol' + product_id); 154 product_ids.push(product_id); 155 } 156 }); 157 158 if (product_ids.length) { 159 $.ajax({ 160 url : lowopifzeroprd_url23X_30X + 'getcache', 161 type : 'post', 162 data : { product_ids: product_ids }, 163 cache: true, 164 success: function (json) { 165 if (json['prod']) { 166 $("[onclick*='cart.add'], [onclick*='addToCart']").each(function () { 167 var product_id = $(this).attr('onclick').match(/[0-9]+/).toString(); 168 var target = $(this).closest('.product-thumb, .product-wrapper'); 169 if (json['prod'][product_id] && json['pfxtxt'].length && !target.hasClass('pfxtxt')) { 170 target.addClass('pfxtxt') 171 .find('.price') 172 .prepend(json['pfxtxt']); 173 } 174 }); 175 } 176 } 177 }); 178 } 179 }, 180 181 /* ------------------------------------------------------------------ * 182 * PRODUCT PAGE HANDLING * 183 * ------------------------------------------------------------------ */ 184 'prodpage': function () { 185 var product_ids = [], product_id = false; 186 if ($(".button-group-page input[name='product_id']").length) product_id = $(".button-group-page input[name='product_id']").val(); 187 else if ($('#input-product-id').length) product_id = $('#input-product-id').val(); 188 else if ($(".product-info input[name='product_id']").length) product_id = $(".product-info input[name='product_id']").val(); 189 else if ($("#product input[name='product_id']").length) product_id = $("#product input[name='product_id']").val(); 190 if (product_id) product_ids.push(product_id); 191 192 if (product_ids.length) { 193 if (!$("#product ul.price .product-price").length && !$('#product .price-wrapper .product-price').length) { 194 lowopifzeroprd.prcupdate(); /* hook price elements */ 195 } 196 197 $.ajax({ 198 url : lowopifzeroprd_url23X_30X + 'getcache', 199 type : 'post', 200 data : { product_ids: product_ids }, 201 cache: true, 202 success: function (json) { 203 if (json['prod'] && json['prod'][product_id] && json['pfxtxt'].length) { 204 var target = $('#product'), 205 target2 = $("#product ul.price .product-price"), 206 target3 = $('#product .price-wrapper .product-price'); 207 208 [target, target2, target3].forEach(function (el) { 209 if (el.length && !el.hasClass('pfxtxt')) { 210 // el.addClass('pfxtxt').prepend(json['pfxtxt']); 211 } 212 }); 213 } 214 if (json['povid'] && $('#product').length) { 215 $('#product input[type="radio"], #product input[type="checkbox"]').each(function () { 216 if (parseInt($(this).val(), 10) === parseInt(json['povid'][product_id], 10)) { 217 $(this).prop('checked', true).attr('checked', 'checked').trigger('change'); 218 } 219 }); 220 $('#product option').each(function () { 221 if (parseInt($(this).val(), 10) === parseInt(json['povid'][product_id], 10)) { 222 $(this).prop('selected', true).attr('selected', 'selected').trigger('change'); 223 } 224 }); 225 } 226 } 227 }); 228 } 229 }, 230 231 /* ------------------------------------------------------------------ * 232 * INITIALISATION * 233 * ------------------------------------------------------------------ */ 234 'initjson': function () { 235 lowopifzeroprd.atgrid(); 236 $(document).ajaxStop(function () { 237 lowopifzeroprd.atgrid(); 238 }); 239 lowopifzeroprd.prodpage(); 240 } 241 242}; 243 244/* bootstrap */ 245$(document).ready(function () { 246 lowopifzeroprd.initjson(); 247});
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.