1/* 2 3This file is part of the plugin Pay with Vipps and MobilePay for WooCommerce 4Copyright (c) 2019 WP-Hosting AS 5 6MIT License 7 8Copyright (c) 2019 WP-Hosting AS 9 10Permission is hereby granted, free of charge, to any person obtaining a copy 11of this software and associated documentation files (the "Software"), to deal 12in the Software without restriction, including without limitation the rights 13to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14copies of the Software, and to permit persons to whom the Software is 15furnished to do so, subject to the following conditions: 16 17The above copyright notice and this permission notice shall be included in all 18copies or substantial portions of the Software. 19 20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26SOFTWARE. 27 28*/ 29 30// Hook vippsInit to woocommerce/product-collection render event. LP 29.11.2024 31// IOK 2026-01-14 available from woo 9.4 - so the buy now block will not be available until that version 32document.body.addEventListener('wc-blocks_product_list_rendered', 33 function (event) { 34 document.body.dispatchEvent(new Event('vippsInit')); 35 } 36); 37 38 39jQuery( document ).ready( function() { 40 41 // This is for WooCommerce Product Bundles, which potentially have *several* variant-products or configurable products, so 42 // the standard Woo hooks don't apply. Luckily, we have other, simpler events to use. 43 // For this to work, we also have to force the compat-mode thing on. IOK 2020-04-21 44 jQuery('.cart.bundle_data').on('woocommerce-product-bundle-hide', function (e, variant) { 45 jQuery('form .button.single-product.vipps-buy-now').removeClass('variation-found'); 46 jQuery('form .button.single-product.vipps-buy-now').attr('disabled','disabled'); 47 jQuery('form .button.single-product.vipps-buy-now').addClass('disabled'); 48 // We don't know why the button is hidden, so ensure we use compatibility-mode IOK 2020-04-21 49 jQuery('.button.single-product.vipps-buy-now').addClass('compat-mode'); 50 removeErrorMessages(); 51 }); 52 jQuery('.cart.bundle_data').on('woocommerce-product-bundle-show', function (e, variant) { 53 jQuery('form .button.single-product.vipps-buy-now').addClass('variation-found'); 54 jQuery('form .button.single-product.vipps-buy-now').removeAttr('disabled'); 55 jQuery('form .button.single-product.vipps-buy-now').removeClass('disabled'); 56 removeErrorMessages(); 57 }); 58 59 // Hooks for the 'buy now with vipps' button on product pages etc 60 jQuery('body').on('found_variation', function (e,variation) { 61 const form = jQuery(e.target); 62 const target = form.find(".button.single-product.vipps-buy-now.variable-product"); 63 64 var purchasable=true; 65 if ( ! variation.is_purchasable || ! variation.is_in_stock || ! variation.variation_is_visible ) { 66 purchasable = false; 67 } 68 target.addClass('variation-found'); 69 if (purchasable) { 70 target.removeAttr('disabled'); 71 target.removeClass('disabled'); 72 removeErrorMessages(); 73 } else { 74 target.attr('disabled','disabled'); 75 target.addClass('disabled'); 76 removeErrorMessages(); 77 } 78 }); 79 jQuery('body').on('reset_data', function (e) { 80 const form = jQuery(e.target) 81 const target = form.find(".button.single-product.vipps-buy-now.variable-product"); 82 target.removeClass('variation-found'); 83 target.attr('disabled','disabled'); 84 target.addClass('disabled'); 85 removeErrorMessages(); 86 }); 87 // If this is triggered, somebody just loaded a variation form, so we need to redo the button init scripts 88 jQuery('body').on('wc_variation_form', function () { 89 vippsInit(); 90 }); 91 // Allow other guys to do this too 92 jQuery('body').on('vippsInit', function () { 93 vippsInit(); 94 }); 95 96 97 // Using ajax, get a session and a key and redirect to the "buy single product using express checkout" page. 98 function buySingleProduct (event) { 99 event.preventDefault(); 100 101 var element = jQuery(this); 102 if (jQuery('body').hasClass('processing')) return; // Trying to stop doublecclickers. IOK 2018-09-27 103 104 if (jQuery(element).hasClass('disabled')) { 105 if (typeof wc_add_to_cart_variation_params != 'undefined') { 106 if (jQuery(element).hasClass('variation-found')) { 107 window.alert(wc_add_to_cart_variation_params.i18n_unavailable_text); 108 } else { 109 window.alert(wc_add_to_cart_variation_params.i18n_make_a_selection_text); 110 } 111 } else { 112 console.log("Missing the wc_add_to_cart_variation_params"); 113 } 114 return false;
115 } 116 117 jQuery('body').addClass('processing'); 118 removeErrorMessages(); 119 jQuery(element).attr('disabled','disabled'); 120 jQuery(element).attr('inactive','inactive'); 121 jQuery(element).addClass('disabled'); 122 jQuery(element).addClass('loading'); 123 124 if (typeof wp !== 'undefined' && typeof wp.hooks !== 'undefined') { 125 wp.hooks.doAction('vippsBuySingleProduct', element, event); 126 } 127 128 var compatMode = jQuery(element).hasClass('compat-mode'); 129 if (typeof wp !== 'undefined' && typeof wp.hooks !== 'undefined') { 130 compatMode = wp.hooks.applyFilters('vippsBuySingleProductCompatMode', compatMode, element, event); 131 } 132 133 // In compatibility mode, we delegate to the existing buy now button instead of doing the logic 134 // ourselves. This allows more filters and actions in existing plugins to run. IOK 2019-02-26 135 if (compatMode) { 136 var form = jQuery(element).closest('form'); 137 var otherbutton = form.find('.single_add_to_cart_button').first(); 138 var compatAction = function () { 139 form.prepend('<input type=hidden id="vipps_compat_mode" name="vipps_compat_mode" value="1">'); 140 if (otherbutton.length>0) otherbutton.click(); 141 } 142 // If your theme or product is weird enough, you may need this 143 if (typeof wp !== 'undefined' && typeof wp.hooks !== 'undefined') { 144 compatAction = wp.hooks.applyFilters('vippsBuySingleProductCompatModeAction', compatAction, element, event); 145 } 146 compatAction(); 147 return false; 148 } 149 150 var data = {}; 151 if (element.data('product_id') || element.data('product_sku')) { 152 data = element.data(); 153 } else { 154 var form = element.closest('form.cart'); 155 if (!form) { 156 jQuery(element).removeClass('disabled'); 157 jQuery(element).removeClass('loading'); 158 jQuery(element).removeAttr('disabled'); 159 jQuery(element).removeAttr('inactive'); 160 jQuery('body').removeClass('processing'); 161 addErrorMessage('Cannot add product - unknown error'); 162 return false; 163 } 164 // Initialize with the entire content of the form if we have it. 165 var serialized = form.serializeArray(); 166 for (var i=0;i<serialized.length;i++) { 167 if (serialized[i]['name'] != 'add-to-cart') { 168 data[serialized[i]['name']] = serialized[i]['value']; 169 } 170 } 171 var prodid = jQuery(form).find('input[name="product_id"]'); 172 var varid = jQuery(form).find('input[name="variation_id"]'); 173 var quantity = jQuery(form).find('input[name="quantity"]'); 174 data['quantity'] = (quantity.length>0) ? quantity.val() : 1; 175 data['product_id'] = (prodid.length>0) ? prodid.val() : 0; 176 data['variation_id'] = (varid.length>0) ? varid.val() : 0; 177 // Earlier versions, no variation: 178 if (prodid.length == 0) { 179 prodid = jQuery(form).find('button[name="add-to-cart"]'); 180 if (prodid.length > 0) { 181 data['product_id'] = prodid.val(); 182 } else { 183 // Some weird themes are even more incompatible 184 prodid = jQuery(form).find('button[data-product_id]'); 185 data['product_id'] = prodid.length > 0 ? prodid.data('product_id') : 0; 186 } 187 } 188 } 189 // Finally, create a hook for even weirder themes. 190 data = wp.hooks.applyFilters('vippsBuySingleProductData', data, element, event); 191 data['action'] = 'vipps_buy_single_product'; 192 193 jQuery.ajax(VippsConfig['vippsajaxurl'], { 194 "method": "POST", 195 "data":data, 196 "cache":false, 197 "headers": {"Accept-Language": `${VippsConfig['vippslocale']}, *`}, 198 "dataType": "json", 199 "error": function (xhr, statustext, error) { 200 console.log("Error creating express checkout:" + statustext + " " + error); 201 addErrorMessage(error, element); 202 jQuery(element).prop('disabled',true); 203 jQuery(element).prop('inactive',true); 204 jQuery('body').removeClass('processing'); 205 }, 206 "success": function (result, statustext, xhr) { 207 if (result["ok"]) { 208 console.log("We created the order!"); 209 /* In case user presses the back button */ 210 setTimeout(function () { 211 jQuery(element).removeClass('disabled'); 212 jQuery(element).removeClass('loading'); 213 jQuery(element).removeAttr('disabled'); 214 jQuery(element).removeAttr('inactive'); 215 jQuery('body').removeClass('processing'); 216 } 217 , 1500); 218 window.location.assign(result["url"]); 219 } else { 220 console.log("Failure!"); 221 jQuery(element).removeClass('disabled'); 222 jQuery(element).removeClass('loading'); 223 jQuery(element).removeAttr('disabled'); 224 jQuery(element).removeAttr('inactive'); 225 addErrorMessage(result['msg'],element); 226 jQuery('body').removeClass('processing'); 227 } 228 }, 229 "timeout": 0 230 }); 231 232 } 233 234 235 236 // Remove old error messages 237 function removeErrorMessages () { 238 jQuery('.woocommerce-error.vipps-error').fadeOut(300, function () { jQuery(this).remove(); }); 239 jQuery(document).trigger('woo-vipps-remove-errors'); 240 if (typeof wp !== 'undefined' && typeof wp.hooks !== 'undefined') { 241 wp.hooks.doAction('vippsRemoveErrorMessages'); 242 } 243 } 244 245 // And add new ones 246 function addErrorMessage(msg,element) { 247 // Allow developers to customize error message by hiding vipps-default-error-message and hooking woo-vipps-error-message <messsage>,<element> 248 var msg = "<p><ul class='woocommerce-error vipps-error vipps-default-error-message vipps-buy-now-error'><li>
248"+msg+"!</li></ul></p>"; 249 if (typeof wp !== 'undefined' && typeof wp.hooks !== 'undefined') { 250 msg = wp.hooks.applyFilters('vippsErrorMessage',msg, element); 251 } 252 jQuery(document).trigger('woo-vipps-error-message',[msg, element]); 253 if (typeof wp !== 'undefined' && typeof wp.hooks !== 'undefined') { 254 wp.hooks.doAction('vippsAddErrorMessage', msg, element); 255 } 256 257 jQuery(msg).hide().insertAfter(element).fadeIn(300); 258 jQuery('.woocommerce-error.vipps-error').click(removeErrorMessages); 259 } 260 261 // Hooks for the button itself 262 function vippsInit() { 263 jQuery('.button.single-product.vipps-buy-now:not(.initialized)').click(buySingleProduct); 264 jQuery('.button.single-product.vipps-buy-now').addClass('initialized'); 265 if (typeof wp !== 'undefined' && typeof wp.hooks !== 'undefined') { 266 wp.hooks.doAction('vippsInit'); 267 } 268 } 269 270 // For modern wp/woo we want to subscribe to events for the cart especially. IOK 2026-02-24 271 if( window.wp?.data) { 272 // The interactivity based minicart is only loaded once; so if the cart changes wrt supporting Vipps Checkout we must handle that 273 // by subscribing to the cart data. IOK 2026-02-23 274 let prevCheckoutUrl = ""; 275 function handleCartChanges () { 276 const minicartbutton = document.querySelector('a.wp-block-woocommerce-mini-cart-checkout-button-block'); 277 if (!minicartbutton) return; 278 279 const cart = wp.data.select("wc/store/cart")?.getCartData?.(); 280 if (!cart) return; 281 const vippsdata = cart?.extensions?.['woo-vipps']; 282 if (!vippsdata) return; 283 if (vippsdata['checkout_url'] && prevCheckoutUrl != vippsdata['checkout_url']) { 284 prevCheckoutUrl = vippsdata['checkout_url']; 285 minicartbutton.href = vippsdata['checkout_url']; 286 } 287 } 288 wp.data.subscribe(handleCartChanges); 289 } 290 291 292 293 vippsInit(); 294}); 295
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.