1/** 2 * OpenMage 3 * 4 * NOTICE OF LICENSE 5 * 6 * This source file is subject to the Academic Free License (AFL 3.0) 7 * that is bundled with this package in the file LICENSE_AFL.txt. 8 * It is also available through the world-wide-web at this URL: 9 * https://opensource.org/licenses/afl-3.0.php 10 * If you did not receive a copy of the license and are unable to 11 * obtain it through the world-wide-web, please send an email 12 * to [email protected] so we can send you a copy immediately. 13 * 14 * @category Varien 15 * @package js 16 * @copyright Copyright (c) 2006-2020 Magento, Inc. (https://www.magento.com) 17 * @copyright Copyright (c) 2020-2022 The OpenMage Contributors (https://www.openmage.org) 18 * @license https://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) 19 */ 20function popWin(url,win,para) { 21 var win = window.open(url,win,para); 22 win.focus(); 23} 24 25function setLocation(url){ 26 window.location.href = encodeURI(url); 27} 28 29function setPLocation(url, setFocus){ 30 if( setFocus ) { 31 window.opener.focus(); 32 } 33 window.opener.location.href = encodeURI(url); 34} 35 36/** 37 * Add classes to specified elements. 38 * Supported classes are: 'odd', 'even', 'first', 'last' 39 * 40 * @param elements - array of elements to be decorated 41 * [@param decorateParams] - array of classes to be set. If omitted, all available will be used 42 */ 43function decorateGeneric(elements, decorateParams) 44{ 45 var allSupportedParams = ['odd', 'even', 'first', 'last']; 46 var _decorateParams = {}; 47 var total = elements.length; 48 49 if (total) { 50 // determine params called 51 if (typeof(decorateParams) == 'undefined') { 52 decorateParams = allSupportedParams; 53 } 54 if (!decorateParams.length) { 55 return; 56 } 57 for (var k in allSupportedParams) { 58 _decorateParams[allSupportedParams[k]] = false; 59 } 60 for (var k in decorateParams) { 61 _decorateParams[decorateParams[k]] = true; 62 } 63 64 // decorate elements 65 // elements[0].addClassName('first'); // will cause bug in IE (#5587) 66 if (_decorateParams.first) { 67 Element.addClassName(elements[0], 'first'); 68 } 69 if (_decorateParams.last) { 70 Element.addClassName(elements[total-1], 'last'); 71 } 72 for (var i = 0; i < total; i++) { 73 if ((i + 1) % 2 == 0) { 74 if (_decorateParams.even) { 75 Element.addClassName(elements[i], 'even'); 76 } 77 } 78 else { 79 if (_decorateParams.odd) { 80 Element.addClassName(elements[i], 'odd'); 81 } 82 } 83 } 84 } 85} 86 87/** 88 * Decorate table rows and cells, tbody etc 89 * @see decorateGeneric() 90 */ 91function decorateTable(table, options) { 92 var table = $(table); 93 if (table) { 94 // set default options 95 var _options = { 96 'tbody' : false, 97 'tbody tr' : ['odd', 'even', 'first', 'last'], 98 'thead tr' : ['first', 'last'], 99 'tfoot tr' : ['first', 'last'], 100 'tr td' : ['last'] 101 }; 102 // overload options 103 if (typeof(options) != 'undefined') { 104 for (var k in options) { 105 _options[k] = options[k]; 106 } 107 } 108 // decorate 109 if (_options['tbody']) { 110 decorateGeneric(table.select('tbody'), _options['tbody']); 111 } 112 if (_options['tbody tr']) { 113 decorateGeneric(table.select('tbody tr'), _options['tbody tr']); 114 } 115 if (_options['thead tr']) { 116 decorateGeneric(table.select('thead tr'), _options['thead tr']); 117 } 118 if (_options['tfoot tr']) { 119 decorateGeneric(table.select('tfoot tr'), _options['tfoot tr']); 120 } 121 if (_options['tr td']) { 122 var allRows = table.select('tr'); 123 if (allRows.length) { 124 for (var i = 0; i < allRows.length; i++) { 125 decorateGeneric(allRows[i].getElementsByTagName('TD'), _options['tr td']); 126 } 127 } 128 } 129 } 130} 131 132/** 133 * Set "odd", "even" and "last" CSS classes for list items 134 * @see decorateGeneric() 135 */ 136function decorateList(list, nonRecursive) { 137 if ($(list)) { 138 if (typeof(nonRecursive) == 'undefined') { 139 var items = $(list).select('li'); 140 } 141 else { 142 var items = $(list).childElements(); 143 } 144 decorateGeneric(items, ['odd', 'even', 'last']); 145 } 146} 147 148/** 149 * Set "odd", "even" and "last" CSS classes for list items 150 * @see decorateGeneric() 151 */ 152function decorateDataList(list) { 153 list = $(list); 154 if (list) { 155 decorateGeneric(list.select('dt'), ['odd', 'even', 'last']); 156 decorateGeneric(list.select('dd'), ['odd', 'even', 'last']); 157 } 158} 159 160/** 161 * Parse SID and produces the correct URL 162 */ 163function parseSidUrl(baseUrl, urlExt) { 164 var sidPos = baseUrl.indexOf('/?SID='); 165 var sid = ''; 166 urlExt = (urlExt != undefined) ? urlExt : ''; 167 168 if(sidPos > -1) { 169 sid = '?' + baseUrl.substring(sidPos + 2); 170 baseUrl = baseUrl.substring(0, sidPos + 1); 171 } 172 173 return baseUrl+urlExt+sid; 174} 175 176/** 177 * Formats currency using patern 178 * format - JSON (pattern, decimal, decimalsDelimeter, groupsDelimeter) 179 * showPlus - true (always show '+'or '-'), 180 * false (never show '-' even if number is negative) 181 * null (show '-' if number is negative) 182 */ 183 184function formatCurrency(price, format, showPlus){ 185 var precision = isNaN(format.precision = Math.abs(format.precision)) ? 2 : format.precision; 186 var requiredPrecision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision; 187 188 //precision = (precision > requiredPrecision) ? precision : requiredPrecision; 189 //for now we don't need this difference so precision is requiredPrecision 190 precision = requiredPrecision; 191 192 var integerRequired = isNaN(format.integerRequired = Math.abs(format.integerRequired)) ? 1 : format.integerRequired; 193 194 var decimalSymbol = format.decimalSymbol == undefined ? "," : format.decimalSymbol; 195 var groupSymbol = format.groupSymbol == undefined ? "." : format.groupSymbol; 196 var groupLength = format.groupLength == undefined ? 3 : format.groupLength; 197 198 var s = ''; 199 200 if (showPlus == undefined || showPlus == true) { 201 s = price < 0 ? "-" : ( showPlus ? "+" : ""); 202 } else if (showPlus == false) { 203 s = ''; 204 } 205 206 var i = parseInt(price = Math.abs(+price || 0).toFixed(precision)) + ""; 207 var pad = (i.length < integerRequired) ? (integerRequired - i.length) : 0; 208 while (pad) { i = '0' + i; pad--; } 209 j = (j = i.length) > groupLength ? j % groupLength : 0; 210 re = new RegExp("(\\d{" + groupLength + "})(?=\\d)", "g"); 211 212 /** 213 * replace(/-/, 0) is only for fixing Safari bug which appears 214 * when Math.abs(0).toFixed() executed on "0" number. 215 * Result is "0.-0" :( 216 */ 217 var r = (j ? i.substr(0, j) + groupSymbol : "") + i.substr(j).replace(re, "$1" + groupSymbol) + (precision ? decimalSymbol + Math.abs(price - i).toFixed(precision).replace(/-/, 0).slice(2) : ""); 218 var pattern = ''; 219 if (format.pattern.indexOf('{sign}') == -1) { 220 pattern = s + format.pattern; 221 } else { 222 pattern = format.pattern.replace('{sign}', s); 223 } 224 225 return pattern.replace('%s', r).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); 226}; 227 228function expandDetails(el, childClass) {
229 if (Element.hasClassName(el,'show-details')) { 230 $$(childClass).each(function(item){ 231 item.hide(); 232 }); 233 Element.removeClassName(el,'show-details'); 234 } 235 else { 236 $$(childClass).each(function(item){ 237 item.show(); 238 }); 239 Element.addClassName(el,'show-details'); 240 } 241} 242 243// Version 1.0 244var isIE = navigator.appVersion.match(/MSIE/) == "MSIE"; 245 246if (!window.Varien) 247 var Varien = new Object(); 248 249Varien.showLoading = function(){ 250 var loader = $('loading-process'); 251 loader && loader.show(); 252}; 253Varien.hideLoading = function(){ 254 var loader = $('loading-process'); 255 loader && loader.hide(); 256}; 257Varien.GlobalHandlers = { 258 onCreate: function() { 259 Varien.showLoading(); 260 }, 261 262 onComplete: function() { 263 if(Ajax.activeRequestCount == 0) { 264 Varien.hideLoading(); 265 } 266 } 267}; 268 269Ajax.Responders.register(Varien.GlobalHandlers); 270 271/** 272 * Quick Search form client model 273 */ 274Varien.searchForm = Class.create(); 275Varien.searchForm.prototype = { 276 initialize : function(form, field, emptyText){ 277 this.form = $(form); 278 this.field = $(field); 279 this.emptyText = emptyText; 280 281 Event.observe(this.form, 'submit', this.submit.bind(this)); 282 Event.observe(this.field, 'focus', this.focus.bind(this)); 283 Event.observe(this.field, 'blur', this.blur.bind(this)); 284 this.blur(); 285 }, 286 287 submit : function(event){ 288 if (this.field.value == this.emptyText || this.field.value == ''){ 289 Event.stop(event); 290 return false; 291 } 292 return true; 293 }, 294 295 focus : function(event){ 296 if(this.field.value==this.emptyText){ 297 this.field.value=''; 298 } 299 300 }, 301 302 blur : function(event){ 303 if(this.field.value==''){ 304 this.field.value=this.emptyText; 305 } 306 }, 307 308 initAutocomplete : function(url, destinationElement){ 309 new Ajax.Autocompleter( 310 this.field, 311 destinationElement, 312 url, 313 { 314 paramName: this.field.name, 315 method: 'get', 316 minChars: 2, 317 updateElement: this._selectAutocompleteItem.bind(this), 318 onShow : function(element, update) { 319 if(!update.style.position || update.style.position=='absolute') { 320 update.style.position = 'absolute'; 321 Position.clone(element, update, { 322 setHeight: false, 323 offsetTop: element.offsetHeight 324 }); 325 }
326 Effect.Appear(update,{duration:0}); 327 } 328 329 } 330 ); 331 }, 332 333 _selectAutocompleteItem : function(element){ 334 if(element.title){ 335 this.field.value = element.title; 336 } 337 this.form.submit(); 338 } 339}; 340 341Varien.Tabs = Class.create(); 342Varien.Tabs.prototype = { 343 initialize: function(selector) { 344 var self=this; 345 $$(selector+' a').each(this.initTab.bind(this)); 346 }, 347 348 initTab: function(el) { 349 el.href = 'javascript:void(0)'; 350 if ($(el.parentNode).hasClassName('active')) { 351 this.showContent(el); 352 } 353 el.observe('click', this.showContent.bind(this, el)); 354 }, 355 356 showContent: function(a) { 357 var li = $(a.parentNode), ul = $(li.parentNode); 358 ul.getElementsBySelector('li', 'ol').each(function(el){ 359 var contents = $(el.id+'_contents'); 360 if (el==li) { 361 el.addClassName('active'); 362 contents.show(); 363 } else { 364 el.removeClassName('active'); 365 contents.hide(); 366 } 367 }); 368 } 369}; 370 371Varien.DateElement = Class.create(); 372Varien.DateElement.prototype = { 373 initialize: function(type, content, required, format) { 374 if (type == 'id') { 375 // id prefix 376 this.day = $(content + 'day'); 377 this.month = $(content + 'month'); 378 this.year = $(content + 'year'); 379 this.full = $(content + 'full'); 380 this.advice = $(content + 'date-advice'); 381 } else if (type == 'container') { 382 // content must be container with data 383 this.day = content.day; 384 this.month = content.month; 385 this.year = content.year; 386 this.full = content.full; 387 this.advice = content.advice; 388 } else { 389 return; 390 } 391 392 this.required = required; 393 this.format = format; 394 395 this.day.addClassName('validate-custom'); 396 this.day.validate = this.validate.bind(this); 397 this.month.addClassName('validate-custom'); 398 this.month.validate = this.validate.bind(this); 399 this.year.addClassName('validate-custom'); 400 this.year.validate = this.validate.bind(this); 401 402 this.setDateRange(false, false); 403 this.year.setAttribute('autocomplete','off'); 404 405 this.advice.hide(); 406 407 var date = new Date; 408 this.curyear = date.getFullYear(); 409 }, 410 validate: function() { 411 var error = false, 412 day = parseInt(this.day.value, 10) || 0, 413 month = parseInt(this.month.value, 10) || 0, 414 year = parseInt(this.year.value, 10) || 0; 415 if (this.day.value.strip().empty() 416 && this.month.value.strip().empty() 417 && this.year.value.strip().empty() 418 ) { 419 if (this.required) { 420 error = 'This date is a required value.'; 421 } else { 422 this.full.value = ''; 423 } 424 } else if (!day || !month || !year) { 425 error = 'Please enter a valid full date'; 426 } else { 427 var date = new Date, countDaysInMonth = 0, errorType = null; 428 date.setYear(year);date.setMonth(month-1);date.setDate(32); 429 countDaysInMonth = 32 - date.getDate(); 430 if(!countDaysInMonth || countDaysInMonth>31) countDaysInMonth = 31; 431 if(year < 1900) error = this.errorTextModifier(this.validateDataErrorText); 432 433 if (day<1 || day>countDaysInMonth) { 434 errorType = 'day'; 435 error = 'Please enter a valid day (1-%d).'; 436 } else if (month<1 || month>12) { 437 errorType = 'month'; 438 error = 'Please enter a valid month (1-12).'; 439 } else { 440 if(day % 10 == day) this.day.value = '0'+day; 441 if(month % 10 == month) this.month.value = '0'+month; 442 this.full.value = this.format.replace(/%[mb]/i, this.month.value).replace(/%[de]/i, this.day.value).replace(/%y/i, this.year.value); 443 var testFull = this.month.value + '/' + this.day.value + '/'+ this.year.value; 444 var test = new Date(testFull); 445 if (isNaN(test)) { 446 error = 'Please enter a valid date.'; 447 } else { 448 this.setFullDate(test); 449 } 450 } 451 var valueError = false;
452 if (!error && !this.validateData()){//(year<1900 || year>curyear) { 453 errorType = this.validateDataErrorType;//'year'; 454 valueError = this.validateDataErrorText;//'Please enter a valid year (1900-%d).'; 455 error = valueError; 456 } 457 } 458 459 if (error !== false) { 460 try { 461 error = Translator.translate(error); 462 } 463 catch (e) {} 464 if (!valueError) { 465 this.advice.innerHTML = error.replace('%d', countDaysInMonth); 466 } else { 467 this.advice.innerHTML = this.errorTextModifier(error); 468 } 469 this.advice.show(); 470 return false; 471 } 472 473 // fixing elements class 474 this.day.removeClassName('validation-failed'); 475 this.month.removeClassName('validation-failed'); 476 this.year.removeClassName('validation-failed'); 477 478 this.advice.hide(); 479 return true; 480 }, 481 validateData: function() { 482 var year = this.fullDate.getFullYear(); 483 return (year>=1900 && year<=this.curyear); 484 }, 485 validateDataErrorType: 'year', 486 validateDataErrorText: 'Please enter a valid year (1900-%d).', 487 errorTextModifier: function(text) { 488 text = Translator.translate(text); 489 return text.replace('%d', this.curyear); 490 }, 491 setDateRange: function(minDate, maxDate) { 492 this.minDate = minDate; 493 this.maxDate = maxDate; 494 }, 495 setFullDate: function(date) { 496 this.fullDate = date; 497 } 498}; 499 500Varien.DOB = Class.create(); 501Varien.DOB.prototype = { 502 initialize: function(selector, required, format) { 503 var el = $$(selector)[0]; 504 var container = {}; 505 container.day = Element.select(el, '.dob-day input')[0]; 506 container.month = Element.select(el, '.dob-month input')[0]; 507 container.year = Element.select(el, '.dob-year input')[0]; 508 container.full = Element.select(el, '.dob-full input')[0]; 509 container.advice = Element.select(el, '.validation-advice')[0]; 510 511 new Varien.DateElement('container', container, required, format); 512 } 513}; 514 515Varien.dateRangeDate = Class.create(); 516Varien.dateRangeDate.prototype = Object.extend(new Varien.DateElement(), { 517 validateData: function() { 518 var validate = true; 519 if (this.minDate || this.maxValue) { 520 if (this.minDate) { 521 this.minDate = new Date(this.minDate); 522 this.minDate.setHours(0); 523 if (isNaN(this.minDate)) { 524 this.minDate = new Date('1/1/1900'); 525 } 526 validate = validate && (this.fullDate >= this.minDate); 527 } 528 if (this.maxDate) { 529 this.maxDate = new Date(this.maxDate); 530 this.minDate.setHours(0); 531 if (isNaN(this.maxDate)) { 532 this.maxDate = new Date(); 533 } 534 validate = validate && (this.fullDate <= this.maxDate); 535 } 536 if (this.maxDate && this.minDate) { 537 this.validateDataErrorText = 'Please enter a valid date between %s and %s'; 538 } else if (this.maxDate) { 539 this.validateDataErrorText = 'Please enter a valid date less than or equal to %s'; 540 } else if (this.minDate) { 541 this.validateDataErrorText = 'Please enter a valid date equal to or greater than %s'; 542 } else { 543 this.validateDataErrorText = ''; 544 } 545 } 546 return validate; 547 }, 548 validateDataErrorText: 'Date should be between %s and %s', 549 errorTextModifier: function(text) { 550 if (this.minDate) { 551 text = text.sub('%s', this.dateFormat(this.minDate)); 552 } 553 if (this.maxDate) { 554 text = text.sub('%s', this.dateFormat(this.maxDate)); 555 } 556 return text; 557 }, 558 dateFormat: function(date) { 559 return (date.getMonth() + 1) + '/' + date.getDate() + '/' + date.getFullYear(); 560 } 561}); 562 563Varien.FileElement = Class.create(); 564Varien.FileElement.prototype = { 565 initialize: function (id) { 566 this.fileElement = $(id); 567 this.hiddenElement = $(id + '_value'); 568 569 this.fileElement.observe('change', this.selectFile.bind(this)); 570 }, 571 selectFile: function(event) { 572 this.hiddenElement.value = this.fileElement.getValue(); 573 } 574}; 575 576Validation.addAllThese([ 577 ['validate-custom', ' ', function(v,elm) { 578 return elm.validate(); 579 }] 580]); 581 582function truncateOptions() { 583 $$('.truncated').each(function(element){ 584 Event.observe(element, 'mouseover', function(){ 585 if (element.down('div.truncated_full_value')) { 586 element.down('div.truncated_full_value').addClassName('show'); 587 } 588 }); 589 Event.observe(element, 'mouseout', function(){ 590 if (element.down('div.truncated_full_value')) { 591 element.down('div.truncated_full_value').removeClassName('show'); 592 } 593 }); 594 595 }); 596} 597Event.observe(window, 'load', function(){ 598 truncateOptions(); 599}); 600 601Element.addMethods({ 602 getInnerText: function(element) 603 { 604 element = $(element); 605 if(element.innerText && !Prototype.Browser.Opera) { 606 return element.innerText; 607 } 608 return element.innerHTML.stripScripts().unescapeHTML().replace(/[\n\r\s]+/g, ' ').strip(); 609 } 610}); 611 612/** 613 * Executes event handler on the element. Works with event handlers attached by Prototype, 614 * in a browser-agnostic fashion. 615 * @param element The element object 616 * @param event Event name, like 'change' 617 * 618 * @example fireEvent($('my-input', 'click')); 619 */ 620function fireEvent(element, event) { 621 if (document.createEvent) { 622 // dispatch for all browsers except IE before version 9 623 var evt = document.createEvent("HTMLEvents"); 624 evt.initEvent(event, true, true ); // event type, bubbling, cancelable 625 return element.dispatchEvent(evt); 626 } else { 627 // dispatch for IE before version 9 628 var evt = document.createEventObject(); 629 return element.fireEvent('on' + event, evt); 630 } 631} 632 633/** 634 * Returns more accurate results of floating-point modulo division 635 * E.g.: 636 * 0.6 % 0.2 = 0.19999999999999996 637 * modulo(0.6, 0.2) = 0 638 * 639 * @param dividend 640 * @param divisor 641 */ 642function modulo(dividend, divisor) 643{ 644 var epsilon = divisor / 10000; 645 var remainder = dividend % divisor; 646 647 if (Math.abs(remainder - divisor) < epsilon || Math.abs(remainder) < epsilon) { 648 remainder = 0; 649 } 650 651 return remainder; 652} 653 654/** 655 * createContextualFragment is not supported in IE9. Adding its support. 656 */ 657if ((typeof Range != "undefined") && !Range.prototype.createContextualFragment) 658{ 659 Range.prototype.createContextualFragment = function(html) 660 { 661 var frag = document.createDocumentFragment(), 662 div = document.createElement("div"); 663 frag.appendChild(div); 664 div.outerHTML = html; 665 return frag; 666 }; 667} 668 669/** 670 * Create form element. Set parameters into it and send 671 * 672 * @param url 673 * @param parametersArray 674 * @param method 675 */ 676Varien.formCreator = Class.create(); 677Varien.formCreator.prototype = { 678 initialize : function(url, parametersArray, method) { 679 this.url = url; 680 this.parametersArray = JSON.parse(parametersArray); 681 this.method = method; 682 this.form = ''; 683 684 this.createForm(); 685 this.setFormData(); 686 }, 687 createForm : function() { 688 this.form = new Element('form', { 'method': this.method, action: this.url }); 689 }, 690 setFormData : function () { 691 for (var key in this.parametersArray) { 692 Element.insert( 693 this.form, 694 new Element('input', { name: key, value: this.parametersArray[key], type: 'hidden' }) 695 ); 696 } 697 } 698}; 699 700function customFormSubmit(url, parametersArray, method) { 701 var createdForm = new Varien.formCreator(url, parametersArray, method); 702 Element.insert($$('body')[0], createdForm.form); 703 createdForm.form.submit(); 704} 705 706function customFormSubmitToParent(url, parametersArray, method) { 707 new Ajax.Request(url, { 708 method: method, 709 parameters: JSON.parse(parametersArray), 710 onSuccess: function (response) { 711 var node = document.createElement('div'); 712 node.innerHTML = response.responseText; 713 var responseMessage = node.getElementsByClassName('messages')[0]; 714 var pageTitle = window.document.body.getElementsByClassName('page-title')[0]; 715 pageTitle.insertAdjacentHTML('afterend', responseMessage.outerHTML);
716 window.opener.focus(); 717 window.opener.location.href = response.transport.responseURL; 718 } 719 }); 720} 721 722function buttonDisabler() { 723 var buttons = document.querySelectorAll('button.save'); 724 buttons.forEach(function(button) { 725 button.disabled = true; 726 }); 727}
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.