1(function (window, document, $, miniShop2Config) { 2 var miniShop2 = miniShop2 || {}; 3 miniShop2Config.callbacksObjectTemplate = function () { 4 return { 5 // return false to prevent send data 6 before: [], 7 response: { 8 success: [], 9 error: [] 10 }, 11 ajax: { 12 done: [], 13 fail: [], 14 always: [] 15 } 16 } 17 }; 18 miniShop2.Callbacks = miniShop2Config.Callbacks = { 19 Cart: { 20 add: miniShop2Config.callbacksObjectTemplate(), 21 remove: miniShop2Config.callbacksObjectTemplate(), 22 change: miniShop2Config.callbacksObjectTemplate(), 23 clean: miniShop2Config.callbacksObjectTemplate() 24 }, 25 Order: { 26 add: miniShop2Config.callbacksObjectTemplate(), 27 getcost: miniShop2Config.callbacksObjectTemplate(), 28 clean: miniShop2Config.callbacksObjectTemplate(), 29 submit: miniShop2Config.callbacksObjectTemplate(), 30 getrequired: miniShop2Config.callbacksObjectTemplate() 31 }, 32 }; 33 miniShop2.Callbacks.add = function (path, name, func) { 34 if (typeof func != 'function') { 35 return false; 36 } 37 path = path.split('.'); 38 var obj = miniShop2.Callbacks; 39 for (var i = 0; i < path.length; i++) { 40 if (obj[path[i]] == undefined) { 41 return false; 42 } 43 obj = obj[path[i]]; 44 } 45 if (typeof obj != 'object') { 46 obj = [obj]; 47 } 48 if (name != undefined) { 49 obj[name] = func; 50 } else { 51 obj.push(func); 52 } 53 return true; 54 }; 55 miniShop2.Callbacks.remove = function (path, name) { 56 path = path.split('.'); 57 var obj = miniShop2.Callbacks; 58 for (var i = 0; i < path.length; i++) { 59 if (obj[path[i]] == undefined) { 60 return false; 61 } 62 obj = obj[path[i]]; 63 } 64 if (obj[name] != undefined) { 65 delete obj[name]; 66 return true; 67 } 68 return false; 69 }; 70 miniShop2.ajaxProgress = false; 71 miniShop2.setup = function () { 72 // selectors & $objects 73 this.actionName = 'ms2_action'; 74 this.action = ':submit[name=' + this.actionName + ']'; 75 this.form = '.ms2_form'; 76 this.$doc = $(document); 77 78 this.sendData = { 79 $form: null, 80 action: null, 81 formData: null 82 }; 83 84 this.timeout = 300; 85 }; 86 miniShop2.initialize = function () { 87 miniShop2.setup(); 88 // Indicator of active ajax request 89 90 //noinspection JSUnresolvedFunction 91 miniShop2.$doc 92 .ajaxStart(function () { 93 miniShop2.ajaxProgress = true; 94 }) 95 .ajaxStop(function () { 96 miniShop2.ajaxProgress = false; 97 }) 98 .on('submit', miniShop2.form, function (e) { 99 e.preventDefault(); 100 var $form = $(this); 101 var action = $form.find(miniShop2.action).val(); 102 103 if (action) { 104 var formData = $form.serializeArray(); 105 formData.push({ 106 name: miniShop2.actionName, 107 value: action 108 }); 109 miniShop2.sendData = { 110 $form: $form, 111 action: action, 112 formData: formData 113 }; 114 miniShop2.controller(); 115 } 116 }); 117 miniShop2.Cart.initialize(); 118 miniShop2.Message.initialize(); 119 miniShop2.Order.initialize(); 120 miniShop2.Gallery.initialize(); 121 }; 122 miniShop2.controller = function () { 123 var self = this; 124 switch (self.sendData.action) { 125 case 'cart/add': 126 miniShop2.Cart.add(); 127 break; 128 case 'cart/remove': 129 miniShop2.Cart.remove(); 130 break; 131 case 'cart/change': 132 miniShop2.Cart.change(); 133 break; 134 case 'cart/clean': 135 miniShop2.Cart.clean(); 136 break; 137 case 'order/submit': 138 miniShop2.Order.submit(); 139 break; 140 case 'order/clean': 141 miniShop2.Order.clean(); 142 break; 143 default: 144 return; 145 } 146 }; 147 miniShop2.send = function (data, callbacks, userCallbacks) { 148 var runCallback = function (callback, bind) { 149 if (typeof callback == 'function') { 150 return callback.apply(bind, Array.prototype.slice.call(arguments, 2)); 151 } else if (typeof callback == 'object') { 152 for (var i in callback) { 153 if (callback.hasOwnProperty(i)) { 154 var response = callback[i].apply(bind, Array.prototype.slice.call(arguments, 2)); 155 if (response === false) { 156 return false;
157 } 158 } 159 } 160 } 161 return true; 162 }; 163 // set context 164 if ($.isArray(data)) { 165 data.push({ 166 name: 'ctx', 167 value: miniShop2Config.ctx 168 }); 169 } else if ($.isPlainObject(data)) { 170 data.ctx = miniShop2Config.ctx; 171 } else if (typeof data == 'string') { 172 data += '&ctx=' + miniShop2Config.ctx; 173 } 174 175 // set action url 176 var formActionUrl = (miniShop2.sendData.$form) 177 ? miniShop2.sendData.$form.attr('action') 178 : false; 179 var url = (formActionUrl) 180 ? formActionUrl 181 : (miniShop2Config.actionUrl) 182 ? miniShop2Config.actionUrl 183 : document.location.href; 184 // set request method 185 var formMethod = (miniShop2.sendData.$form) 186 ? miniShop2.sendData.$form.attr('method') 187 : false; 188 var method = (formMethod) 189 ? formMethod 190 : 'post'; 191 192 // callback before 193 if (runCallback(callbacks.before) === false || runCallback(userCallbacks.before) === false) { 194 return; 195 } 196 // send 197 var xhr = function (callbacks, userCallbacks) { 198 return $[method](url, data, function (response) { 199 if (response.success) { 200 if (response.message) { 201 miniShop2.Message.success(response.message); 202 } 203 runCallback(callbacks.response.success, miniShop2, response); 204 runCallback(userCallbacks.response.success, miniShop2, response); 205 } else { 206 miniShop2.Message.error(response.message); 207 runCallback(callbacks.response.error, miniShop2, response); 208 runCallback(userCallbacks.response.error, miniShop2, response); 209 } 210 }, 'json').done(function () { 211 runCallback(callbacks.ajax.done, miniShop2, xhr); 212 runCallback(userCallbacks.ajax.done, miniShop2, xhr); 213 }).fail(function () { 214 runCallback(callbacks.ajax.fail, miniShop2, xhr); 215 runCallback(userCallbacks.ajax.fail, miniShop2, xhr); 216 }).always(function () { 217 runCallback(callbacks.ajax.always, miniShop2, xhr); 218 runCallback(userCallbacks.ajax.always, miniShop2, xhr); 219 }); 220 }(callbacks, userCallbacks); 221 }; 222 223 miniShop2.Cart = { 224 callbacks: { 225 add: miniShop2Config.callbacksObjectTemplate(), 226 remove: miniShop2Config.callbacksObjectTemplate(), 227 change: miniShop2Config.callbacksObjectTemplate(), 228 clean: miniShop2Config.callbacksObjectTemplate() 229 }, 230 setup: function () { 231 miniShop2.Cart.cart = '#msCart'; 232 miniShop2.Cart.miniCart = '#msMiniCart'; 233 miniShop2.Cart.miniCartClass = '.msMiniCart'; 234 miniShop2.Cart.miniCartNotEmptyClass = 'full'; 235 miniShop2.Cart.countInput = 'input[name=count]'; 236 miniShop2.Cart.totalWeight = '.ms2_total_weight'; 237 miniShop2.Cart.totalCount = '.ms2_total_count'; 238 miniShop2.Cart.totalCost = '.ms2_total_cost'; 239 miniShop2.Cart.totalDiscount = '.ms2_total_discount'; 240 miniShop2.Cart.cost = '.ms2_cost'; 241 }, 242 initialize: function () { 243 miniShop2.Cart.setup(); 244 if (!$(miniShop2.Cart.cart).length) { 245 return; 246 } 247 miniShop2.$doc.on('change', miniShop2.Cart.cart + ' ' + miniShop2.Cart.countInput, function () { 248 if (!!$(this).val()) { 249 $(this).closest(miniShop2.form).submit(); 250 } 251 }); 252 }, 253 add: function () { 254 var callbacks = miniShop2.Cart.callbacks; 255 callbacks.add.response.success = function (response) { 256 this.Cart.status(response.data); 257 }; 258 miniShop2.send(miniShop2.sendData.formData, miniShop2.Cart.callbacks.add, miniShop2.Callbacks.Cart.add); 259 }, 260 remove: function () { 261 var callbacks = miniShop2.Cart.callbacks; 262 callbacks.remove.response.success = function (response) { 263 this.Cart.remove_position(miniShop2.Utils.getValueFromSerializedArray('key')); 264 this.Cart.status(response.data); 265 }; 266 miniShop2.send(miniShop2.sendData.formData, miniShop2.Cart.callbacks.remove, miniShop2.Callbacks.Cart.remove); 267 }, 268 change: function () { 269 var callbacks = miniShop2.Cart.callbacks; 270 callbacks.change.response.success = function (response) { 271 if (typeof (response.data.key) == 'undefined') { 272 this.Cart.remove_position(miniShop2.Utils.getValueFromSerializedArray('key')); 273 } else { 274 $('#' + miniShop2.Utils.getValueFromSerializedArray('key')).find(''); 275 } 276 this.Cart.status(response.data); 277 }; 278 miniShop2.send(miniShop2.sendData.formData, miniShop2.Cart.callbacks.change, miniShop2.Callbacks.Cart.change); 279 }, 280 status: function (status) { 281 if (status['total_count'] < 1) { 282 location.reload(); 283 } else { 284 //var $cart = $(miniShop2.Cart.cart); 285 var $miniCarts = $(miniShop2.Cart.miniCart).add(miniShop2.Cart.miniCartClass); 286 if (status['total_count'] > 0 && $miniCarts.length > 0) { 287 $miniCarts.each(function (index, cart) { 288 if (!$(cart).hasClass(miniShop2.Cart.miniCartNotEmptyClass)) { 289 $(cart).addClass(miniShop2.Cart.miniCartNotEmptyClass); 290 } 291 }); 292 } 293 $(miniShop2.Cart.totalWeight).text(miniShop2.Utils.formatWeight(status['total_weight'])); 294 $(miniShop2.Cart.totalCount).text(status['total_count']); 295 $(miniShop2.Cart.totalCost).text(miniShop2.Utils.formatPrice(status['total_cost'])); 296 $(miniShop2.Cart.totalDiscount).text(miniShop2.Utils.formatPrice(status['total_discount'])); 297 if (typeof(status['cost']) === 'number') { 298 $(miniShop2.Cart.cost, '#' + status['key']).text(miniShop2.Utils.formatPrice(status['cost'])); 299 } 300 if ($(miniShop2.Order.orderCost, miniShop2.Order.order).length) { 301 miniShop2.Order.getcost(); 302 } 303 } 304 }, 305 clean: function () { 306 var callbacks = miniShop2.Cart.callbacks; 307 callbacks.clean.response.success = function (response) { 308 this.Cart.status(response.data); 309 }; 310 311 miniShop2.send(miniShop2.sendData.formData, miniShop2.Cart.callbacks.clean, miniShop2.Callbacks.Cart.clean); 312 }, 313 remove_position: function (key) { 314 $('#' + key).remove(); 315 } 316 }; 317 318 miniShop2.Gallery = { 319 setup: function () { 320 miniShop2.Gallery.gallery = $('#msGallery'); 321 miniShop2.Gallery.files = miniShop2.Gallery.gallery.find('.fotorama'); 322 }, 323 initialize: function () { 324 miniShop2.Gallery.setup(); 325 if (miniShop2.Gallery.files.length) { 326 $('<link/>', { 327 rel: 'stylesheet', 328 type: 'text/css', 329 href: miniShop2Config.cssUrl + 'lib/fotorama.min.css', 330 }).appendTo('head'); 331 $('<script/>', { 332 type: 'text/javascript', 333 src: miniShop2Config.jsUrl + 'lib/fotorama.min.js', 334 }).appendTo('head'); 335 } 336 337 // fix size gallery 338 miniShop2.$doc.on('fotorama:ready', miniShop2.Gallery.files, function (e, Fotorama, extra) { 339 if ((src = Fotorama.activeFrame.src)) { 340 measure = $.Fotorama.measures[src]; 341 if (measure === undefined) { 342 for (i in $.Fotorama.measures) { 343 measure = $.Fotorama.measures[i]; 344 break; 345 } 346 Fotorama.resize(measure); 347 } 348 } 349 }); 350 351 } 352 }; 353 354 miniShop2.Order = { 355 callbacks: { 356 add: miniShop2Config.callbacksObjectTemplate(), 357 getcost: miniShop2Config.callbacksObjectTemplate(), 358 clean: miniShop2Config.callbacksObjectTemplate(), 359 submit: miniShop2Config.callbacksObjectTemplate(), 360 getrequired: miniShop2Config.callbacksObjectTemplate() 361 }, 362 setup: function () { 363 miniShop2.Order.order = '#msOrder'; 364 miniShop2.Order.deliveries = '#deliveries'; 365 miniShop2.Order.payments = '#payments'; 366 miniShop2.Order.deliveryInput = 'input[name="delivery"]'; 367 miniShop2.Order.inputParent = '.input-parent'; 368 miniShop2.Order.paymentInput = 'input[name="payment"]'; 369 miniShop2.Order.paymentInputUniquePrefix = 'input#payment_'; 370 miniShop2.Order.deliveryInputUniquePrefix = 'input#delivery_'; 371 miniShop2.Order.orderCost = '#ms2_order_cost'; 372 miniShop2.Order.cartCost = '#ms2_order_cart_cost'; 373 miniShop2.Order.deliveryCost = '#ms2_order_delivery_cost'; 374 }, 375 initialize: function () { 376 miniShop2.Order.setup(); 377 if ($(miniShop2.Order.order).length) { 378 miniShop2.$doc 379 .on('click', miniShop2.Order.order + ' [name="' + miniShop2.actionName + '"][value="order/clean"]', function (e) { 380 miniShop2.Order.clean(); 381 e.preventDefault(); 382 }) 383 .on('change', miniShop2.Order.order + ' input,' + miniShop2.Order.order + ' textarea', function () { 384 var $this = $(this); 385 var key = $this.attr('name'); 386 var value = $this.val(); 387 miniShop2.Order.add(key, value); 388 }); 389 var $deliveryInputChecked = $(miniShop2.Order.deliveryInput + ':checked', miniShop2.Order.order); 390 $deliveryInputChecked.trigger('change'); 391 } 392 }, 393 updatePayments: function (payments) { 394 var $paymentInputs = $(miniShop2.Order.paymentInput, miniShop2.Order.order); 395 $paymentInputs.attr('disabled', true).prop('disabled', true).closest(miniShop2.Order.inputParent).hide(); 396 if (payments.length > 0) { 397 for (var i in payments) { 398 if (payments.hasOwnProperty(i)) { 399 $paymentInputs.filter(miniShop2.Order.paymentInputUniquePrefix + payments[i]).attr('disabled', false).prop('disabled', false).closest(miniShop2.Order.inputParent).show(); 400 } 401 } 402 } 403 if ($paymentInputs.filter(':visible:checked').length == 0) { 404 $paymentInputs.filter(':visible:first').trigger('click'); 405 } 406 }, 407 add: function (key, value) { 408 var callbacks = miniShop2.Order.callbacks; 409 var old_value = value; 410 callbacks.add.response.success = function (response) { 411 (function (key, value, old_value) { 412 var $field = $('[name="' + key + '"]', miniShop2.Order.order); 413 switch (key) { 414 case 'delivery': 415 $field = $(miniShop2.Order.deliveryInputUniquePrefix + response.data[key]); 416 if (response.data[key] != old_value) { 417 $field.trigger('click'); 418 } else { 419 miniShop2.Order.getrequired(value); 420 miniShop2.Order.updatePayments($field.data('payments')); 421 miniShop2.Order.getcost(); 422 } 423 break; 424 case 'payment': 425 $field = $(miniShop2.Order.paymentInputUniquePrefix + response.data[key]); 426 if (response.data[key] != old_value) { 427 $field.trigger('click'); 428 } else { 429 miniShop2.Order.getcost(); 430 } 431 break; 432 //default: 433 } 434 $field.val(response.data[key]).removeClass('error').closest(miniShop2.Order.inputParent).removeClass('error'); 435 })(key, value, old_value); 436 }; 437 callbacks.add.response.error = function () { 438 (function (key) { 439 var $field = $('[name="' + key + '"]', miniShop2.Order.order); 440 if ($field.attr('type') == 'checkbox' || $field.attr('type') == 'radio') { 441 $field.closest(miniShop2.Order.inputParent).addClass('error'); 442 } else { 443 $field.addClass('error'); 444 } 445 })(key); 446 }; 447 448 var data = { 449 key: key, 450 value: value 451 }; 452 data[miniShop2.actionName] = 'order/add'; 453 miniShop2.send(data, miniShop2.Order.callbacks.add, miniShop2.Callbacks.Order.add); 454 }, 455 getcost: function () { 456 var callbacks = miniShop2.Order.callbacks; 457 callbacks.getcost.response.success = function (response) { 458 $(miniShop2.Order.orderCost, miniShop2.Order.order).text(miniShop2.Utils.formatPrice(response.data['cost'])); 459 $(miniShop2.Order.cartCost, miniShop2.Order.order).text(miniShop2.Utils.formatPrice(response.data['cart_cost'])); 460 $(miniShop2.Order.deliveryCost, miniShop2.Order.order).text(miniShop2.Utils.formatPrice(response.data['delivery_cost'])); 461 }; 462 var data = {}; 463 data[miniShop2.actionName] = 'order/getcost'; 464 miniShop2.send(data, miniShop2.Order.callbacks.getcost, miniShop2.Callbacks.Order.getcost); 465 }, 466 clean: function () { 467 var callbacks = miniShop2.Order.callbacks; 468 callbacks.clean.response.success = function () { 469 location.reload(); 470 }; 471 472 var data = {}; 473 data[miniShop2.actionName] = 'order/clean'; 474 miniShop2.send(data, miniShop2.Order.callbacks.clean, miniShop2.Callbacks.Order.clean); 475 }, 476 submit: function () { 477 miniShop2.Message.close(); 478 479 // Checking for active ajax request 480 if (miniShop2.ajaxProgress) { 481 //noinspection JSUnresolvedFunction 482 miniShop2.$doc.ajaxComplete(function () { 483 miniShop2.ajaxProgress = false;
484 miniShop2.$doc.unbind('ajaxComplete'); 485 miniShop2.Order.submit(); 486 }); 487 return false; 488 } 489 490 var callbacks = miniShop2.Order.callbacks; 491 callbacks.submit.before = function () { 492 $(':button, a', miniShop2.Order.order).attr('disabled', true).prop('disabled', true); 493 }; 494 callbacks.submit.response.success = function (response) { 495 if (response.data['redirect']) { 496 document.location.href = response.data['redirect']; 497 } else if (response.data['msorder']) { 498 document.location.href = document.location.origin + document.location.pathname 499 + (document.location.search ? document.location.search + '&' : '?') 500 + 'msorder=' + response.data['msorder']; 501 } else { 502 location.reload(); 503 } 504 }; 505 callbacks.submit.response.error = function (response) { 506 setTimeout((function () { 507 $(':button, a', miniShop2.Order.order).attr('disabled', false).prop('disabled', false); 508 }.bind(this)), 3 * miniShop2.timeout); 509 $('[name]', miniShop2.Order.order).removeClass('error').closest(miniShop2.Order.inputParent).removeClass('error'); 510 for (var i in response.data) { 511 if (response.data.hasOwnProperty(i)) { 512 var key = response.data[i]; 513 //var $field = $('[name="' + response.data[i] + '"]', miniShop2.Order.order); 514 //$field.addClass('error').closest(miniShop2.Order.inputParent).addClass('error'); 515 var $field = $('[name="' + key + '"]', miniShop2.Order.order); 516 if ($field.attr('type') == 'checkbox' || $field.attr('type') == 'radio') { 517 $field.closest(miniShop2.Order.inputParent).addClass('error'); 518 } else { 519 $field.addClass('error'); 520 } 521 } 522 } 523 }; 524 return miniShop2.send(miniShop2.sendData.formData, miniShop2.Order.callbacks.submit, miniShop2.Callbacks.Order.submit); 525 }, 526 getrequired: function (value) { 527 var callbacks = miniShop2.Order.callbacks; 528 callbacks.getrequired.response.success = function (response) { 529 $('[name]', miniShop2.Order.order).removeClass('required').closest(miniShop2.Order.inputParent).removeClass('required'); 530 var requires = response.data['requires']; 531 for (var i = 0, length = requires.length; i < length; i++) { 532 $('[name=' + requires[i] + ']', miniShop2.Order.order).addClass('required').closest(miniShop2.Order.inputParent).addClass('required'); 533 } 534 }; 535 callbacks.getrequired.response.error = function () { 536 $('[name]', miniShop2.Order.order).removeClass('required').closest(miniShop2.Order.inputParent).removeClass('required'); 537 }; 538 539 var data = { 540 id: value 541 }; 542 data[miniShop2.actionName] = 'order/getrequired'; 543 miniShop2.send(data, miniShop2.Order.callbacks.getrequired, miniShop2.Callbacks.Order.getrequired); 544 } 545 }; 546 547 miniShop2.Message = { 548 initialize: function () { 549 }, 550 close: function () { 551 }, 552 show: function (message) { 553 if (message != '') { 554 alert(message); 555 } 556 }, 557 success: function (message) { 558 }, 559 error: function (message) { 560 }, 561 info: function (message) { 562 } 563 }; 564 565 miniShop2.Utils = { 566 empty: function (val) { 567 return (typeof (val) == 'undefined' || val == 0 || val === null || val === false || (typeof (val) == 'string' && val.replace(/\s+/g, '') == '') || (typeof (val) == 'object' && val.length == 0)); 568 }, 569 formatPrice: function (price) { 570 var pf = miniShop2Config.price_format; 571 price = this.number_format(price, pf[0], pf[1], pf[2]); 572 573 if (miniShop2Config.price_format_no_zeros && pf[0] > 0) { 574 price = price.replace(/(0+)$/, ''); 575 price = price.replace(/[^0-9]$/, ''); 576 } 577 578 return price; 579 }, 580 formatWeight: function (weight) { 581 var wf = miniShop2Config.weight_format; 582 weight = this.number_format(weight, wf[0], wf[1], wf[2]); 583 584 if (miniShop2Config.weight_format_no_zeros && wf[0] > 0) { 585 weight = weight.replace(/(0+)$/, ''); 586 weight = weight.replace(/[^0-9]$/, ''); 587 } 588 589 return weight; 590 }, 591 // Format a number with grouped thousands, 592 number_format: function (number, decimals, dec_point, thousands_sep) { 593 // original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) 594 // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 595 // bugfix by: Michael White (http://crestidg.com) 596 var i, j, kw, kd, km; 597 598 // input sanitation & defaults 599 if (isNaN(decimals = Math.abs(decimals))) { 600 decimals = 2; 601 } 602 if (dec_point == undefined) { 603 dec_point = ','; 604 } 605 if (thousands_sep == undefined) { 606 thousands_sep = '.'; 607 } 608 609 i = parseInt(number = (+number || 0).toFixed(decimals)) + ''; 610 611 if ((j = i.length) > 3) { 612 j = j % 3; 613 } else { 614 j = 0; 615 } 616 617 km = j 618 ? i.substr(0, j) + thousands_sep 619 : ''; 620 kw = i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands_sep); 621 kd = (decimals 622 ? dec_point + Math.abs(number - i).toFixed(decimals).replace(/-/, '0').slice(2) 623 : ''); 624 625 return km + kw + kd; 626 }, 627 getValueFromSerializedArray: function (name, arr) { 628 if (!$.isArray(arr)) { 629 arr = miniShop2.sendData.formData; 630 } 631 for (var i = 0, length = arr.length; i < length; i++) { 632 if (arr[i].name == name) { 633 return arr[i].value; 634 } 635 } 636 return null; 637 } 638 }; 639 640 $(document).ready(function ($) { 641 miniShop2.initialize(); 642 var html = $('html'); 643 html.removeClass('no-js'); 644 if (!html.hasClass('js')) { 645 html.addClass('js'); 646 } 647 }); 648 649 window.miniShop2 = miniShop2; 650})(window, document, jQuery, miniShop2Config);
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.