/** * Magento * * NOTICE OF LICENSE * * This source file is subject to the Academic Free License (AFL 3.0) * that is bundled with this package in the file LICENSE_AFL.txt. * It is also available through the world-wide-web at this URL: * http://opensource.org/licenses/afl-3.0.php * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@magento.com so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade Magento to newer * versions in the future. If you wish to customize Magento for your * needs please refer to http://www.magento.com for more information. * * @category Varien * @package js * @copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com) * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) */ function popWin(url,win,para) { var win = window.open(url,win,para); win.focus(); } function setLocation(url){ window.location.href = url; } function setPLocation(url, setFocus){ if( setFocus ) { window.opener.focus(); } window.opener.location.href = url; } function setLanguageCode(code, fromCode){ //TODO: javascript cookies have different domain and path than php cookies var href = window.location.href; var after = '', dash; if (dash = href.match(/\#(.*)$/)) { href = href.replace(/\#(.*)$/, ''); after = dash[0]; } if (href.match(/[?]/)) { var re = /([?&]store=)[a-z0-9_]*/; if (href.match(re)) { href = href.replace(re, '$1'+code); } else { href += '&store='+code; } var re = /([?&]from_store=)[a-z0-9_]*/; if (href.match(re)) { href = href.replace(re, ''); } } else { href += '?store='+code; } if (typeof(fromCode) != 'undefined') { href += '&from_store='+fromCode; } href += after; setLocation(href); } /** * Add classes to specified elements. * Supported classes are: 'odd', 'even', 'first', 'last' * * @param elements - array of elements to be decorated * [@param decorateParams] - array of classes to be set. If omitted, all available will be used */ function decorateGeneric(elements, decorateParams) { var allSupportedParams = ['odd', 'even', 'first', 'last']; var _decorateParams = {}; var total = elements.length; if (total) { // determine params called if (typeof(decorateParams) == 'undefined') { decorateParams = allSupportedParams; } if (!decorateParams.length) { return; } for (var k in allSupportedParams) { _decorateParams[allSupportedParams[k]] = false; } for (var k in decorateParams) { _decorateParams[decorateParams[k]] = true; } // decorate elements // elements[0].addClassName('first'); // will cause bug in IE (#5587) if (_decorateParams.first) { Element.addClassName(elements[0], 'first'); } if (_decorateParams.last) { Element.addClassName(elements[total-1], 'last'); } for (var i = 0; i < total; i++) { if ((i + 1) % 2 == 0) { if (_decorateParams.even) { Element.addClassName(elements[i], 'even'); } } else { if (_decorateParams.odd) { Element.addClassName(elements[i], 'odd'); } } } } } /** * Decorate table rows and cells, tbody etc * @see decorateGeneric() */ function decorateTable(table, options) { var table = $(table); if (table) { // set default options var _options = { 'tbody' : false, 'tbody tr' : ['odd', 'even', 'first', 'last'], 'thead tr' : ['first', 'last'], 'tfoot tr' : ['first', 'last'], 'tr td' : ['last'] }; // overload options if (typeof(options) != 'undefined') { for (var k in options) { _options[k] = options[k]; } } // decorate if (_options['tbody']) { decorateGeneric(table.select('tbody'), _options['tbody']); } if (_options['tbody tr']) { decorateGeneric(table.select('tbody tr'), _options['tbody tr']); } if (_options['thead tr']) { decorateGeneric(table.select('thead tr'), _options['thead tr']); } if (_options['tfoot tr']) { decorateGeneric(table.select('tfoot tr'), _options['tfoot tr']); } if (_options['tr td']) { var allRows = table.select('tr'); if (allRows.length) { for (var i = 0; i < allRows.length; i++) { decorateGeneric(allRows[i].getElementsByTagName('TD'), _options['tr td']); } } } } } /** * Set "odd", "even" and "last" CSS classes for list items * @see decorateGeneric() */ function decorateList(list, nonRecursive) { if ($(list)) { if (typeof(nonRecursive) == 'undefined') { var items = $(list).select('li') } else { var items = $(list).childElements(); } decorateGeneric(items, ['odd', 'even', 'last']); } } /** * Set "odd", "even" and "last" CSS classes for list items * @see decorateGeneric() */ function decorateDataList(list) { list = $(list); if (list) { decorateGeneric(list.select('dt'), ['odd', 'even', 'last']); decorateGeneric(list.select('dd'), ['odd', 'even', 'last']); } } /** * Parse SID and produces the correct URL */ function parseSidUrl(baseUrl, urlExt) { var sidPos = baseUrl.indexOf('/?SID='); var sid = ''; urlExt = (urlExt != undefined) ? urlExt : ''; if(sidPos > -1) { sid = '?' + baseUrl.substring(sidPos + 2); baseUrl = baseUrl.substring(0, sidPos + 1); } return baseUrl+urlExt+sid; } /** * Formats currency using patern * format - JSON (pattern, decimal, decimalsDelimeter, groupsDelimeter) * showPlus - true (always show '+'or '-'), * false (never show '-' even if number is negative) * null (show '-' if number is negative) */ function formatCurrency(price, format, showPlus){ var precision = isNaN(format.precision = Math.abs(format.precision)) ? 2 : format.precision; var requiredPrecision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision; //precision = (precision > requiredPrecision) ? precision : requiredPrecision; //for now we don't need this difference so precision is requiredPrecision precision = requiredPrecision; var integerRequired = isNaN(format.integerRequired = Math.abs(format.integerRequired)) ? 1 : format.integerRequired; var decimalSymbol = format.decimalSymbol == undefined ? "," : format.decimalSymbol; var groupSymbol = format.groupSymbol == undefined ? "." : format.groupSymbol; var groupLength = format.groupLength == undefined ? 3 : format.groupLength; var s = ''; if (showPlus == undefined || showPlus == true) { s = price < 0 ? "-" : ( showPlus ? "+" : ""); } else if (showPlus == false) { s = ''; } var i = parseInt(price = Math.abs(+price || 0).toFixed(precision)) + ""; var pad = (i.length < integerRequired) ? (integerRequired - i.length) : 0; while (pad) { i = '0' + i; pad--; } j = (j = i.length) > groupLength ? j % groupLength : 0; re = new RegExp("(\\d{" + groupLength + "})(?=\\d)", "g"); /** * replace(/-/, 0) is only for fixing Safari bug which appears * when Math.abs(0).toFixed() executed on "0" number. * Result is "0.-0" :( */ 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) : "") var pattern = ''; if (format.pattern.indexOf('{sign}') == -1) { pattern = s + format.pattern; } else { pattern = format.pattern.replace('{sign}', s); } return pattern.replace('%s', r).replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; function expandDetails(el, childClass) { if (Element.hasClassName(el,'show-details')) { $$(childClass).each(function(item){item.hide()}); Element.removeClassName(el,'show-details'); } else { $$(childClass).each(function(item){item.show()}); Element.addClassName(el,'show-details'); } } // Version 1.0 var isIE = navigator.appVersion.match(/MSIE/) == "MSIE"; if (!window.Varien) var Varien = new Object(); Varien.showLoading = function(){ var loader = $('loading-process'); loader && loader.show(); } Varien.hideLoading = function(){ var loader = $('loading-process'); loader && loader.hide(); } Varien.GlobalHandlers = { onCreate: function() { Varien.showLoading(); }, onComplete: function() { if(Ajax.activeRequestCount == 0) { Varien.hideLoading(); } } }; Ajax.Responders.register(Varien.GlobalHandlers); /** * Quick Search form client model */ Varien.searchForm = Class.create(); Varien.searchForm.prototype = { initialize : function(form, field, emptyText){ this.form = $(form); this.field = $(field); this.emptyText = emptyText; Event.observe(this.form, 'submit', this.submit.bind(this)); Event.observe(this.field, 'focus', this.focus.bind(this)); Event.observe(this.field, 'blur', this.blur.bind(this)); this.blur(); }, submit : function(event){ if (this.field.value == this.emptyText || this.field.value == ''){ Event.stop(event); return false; } return true; }, focus : function(event){ if(this.field.value==this.emptyText){ this.field.value=''; } }, blur : function(event){ if(this.field.value==''){ this.field.value=this.emptyText; } }, initAutocomplete : function(url, destinationElement){ new Ajax.Autocompleter( this.field, destinationElement, url, { paramName: this.field.name, method: 'get', minChars: 2, updateElement: this._selectAutocompleteItem.bind(this), onShow : function(element, update) { if(!update.style.position || update.style.position=='absolute') { update.style.position = 'absolute'; Position.clone(element, update, { setHeight: false, offsetTop: element.offsetHeight }); } Effect.Appear(update,{duration:0}); } } ); }, _selectAutocompleteItem : function(element){ if(element.title){ this.field.value = element.title; } this.form.submit(); } } Varien.Tabs = Class.create(); Varien.Tabs.prototype = { initialize: function(selector) { var self=this; $$(selector+' a').each(this.initTab.bind(this)); }, initTab: function(el) { el.href = 'javascript:void(0)'; if ($(el.parentNode).hasClassName('active')) { this.showContent(el); } el.observe('click', this.showContent.bind(this, el)); }, showContent: function(a) { var li = $(a.parentNode), ul = $(li.parentNode); ul.getElementsBySelector('li', 'ol').each(function(el){ var contents = $(el.id+'_contents'); if (el==li) { el.addClassName('active'); contents.show(); } else { el.removeClassName('active'); contents.hide(); } }); } } Varien.DateElement = Class.create(); Varien.DateElement.prototype = { initialize: function(type, content, required, format) { if (type == 'id') { // id prefix this.day = $(content + 'day'); this.month = $(content + 'month'); this.year = $(content + 'year'); this.full = $(content + 'full'); this.advice = $(content + 'date-advice'); } else if (type == 'container') { // content must be container with data this.day = content.day; this.month = content.month; this.year = content.year; this.full = content.full; this.advice = content.advice; } else { return; } this.required = required; this.format = format; this.day.addClassName('validate-custom'); this.day.validate = this.validate.bind(this); this.month.addClassName('validate-custom'); this.month.validate = this.validate.bind(this); this.year.addClassName('validate-custom'); this.year.validate = this.validate.bind(this); this.setDateRange(false, false); this.year.setAttribute('autocomplete','off'); this.advice.hide(); }, validate: function() { var error = false, day = parseInt(this.day.value, 10) || 0, month = parseInt(this.month.value, 10) || 0, year = parseInt(this.year.value, 10) || 0; if (this.day.value.strip().empty() && this.month.value.strip().empty() && this.year.value.strip().empty() ) { if (this.required) { error = 'This date is a required value.'; } else { this.full.value = ''; } } else if (!day || !month || !year) { error = 'Please enter a valid full date.'; } else { var date = new Date, countDaysInMonth = 0, errorType = null; date.setYear(year);date.setMonth(month-1);date.setDate(32); countDaysInMonth = 32 - date.getDate(); if(!countDaysInMonth || countDaysInMonth>31) countDaysInMonth = 31; if (day<1 || day>countDaysInMonth) { errorType = 'day'; error = 'Please enter a valid day (1-%d).'; } else if (month<1 || month>12) { errorType = 'month'; error = 'Please enter a valid month (1-12).'; } else { if(day % 10 == day) this.day.value = '0'+day; if(month % 10 == month) this.month.value = '0'+month; this.full.value = this.format.replace(/%[mb]/i, this.month.value).replace(/%[de]/i, this.day.value).replace(/%y/i, this.year.value); var testFull = this.month.value + '/' + this.day.value + '/'+ this.year.value; var test = new Date(testFull); if (isNaN(test)) { error = 'Please enter a valid date.'; } else { this.setFullDate(test); } } var valueError = false; if (!error && !this.validateData()){//(year<1900 || year>curyear) { errorType = this.validateDataErrorType;//'year'; valueError = this.validateDataErrorText;//'Please enter a valid year (1900-%d).'; error = valueError; } } if (error !== false) { try { error = Translator.translate(error); } catch (e) {} if (!valueError) { this.advice.innerHTML = error.replace('%d', countDaysInMonth); } else { this.advice.innerHTML = this.errorTextModifier(error); } this.advice.show(); return false; } // fixing elements class this.day.removeClassName('validation-failed'); this.month.removeClassName('validation-failed'); this.year.removeClassName('validation-failed'); this.advice.hide(); return true; }, validateData: function() { var year = this.fullDate.getFullYear(); var date = new Date; this.curyear = date.getFullYear(); return (year>=1900 && year<=this.curyear); }, validateDataErrorType: 'year', validateDataErrorText: 'Please enter a valid year (1900-%d).', errorTextModifier: function(text) { return text.replace('%d', this.curyear); }, setDateRange: function(minDate, maxDate) { this.minDate = minDate; this.maxDate = maxDate; }, setFullDate: function(date) { this.fullDate = date; } }; Varien.DOB = Class.create(); Varien.DOB.prototype = { initialize: function(selector, required, format) { var el = $$(selector)[0]; var container = {}; container.day = Element.select(el, '.dob-day input')[0]; container.month = Element.select(el, '.dob-month input')[0]; container.year = Element.select(el, '.dob-year input')[0]; container.full = Element.select(el, '.dob-full input')[0]; container.advice = Element.select(el, '.validation-advice')[0]; new Varien.DateElement('container', container, required, format); } }; Varien.dateRangeDate = Class.create(); Varien.dateRangeDate.prototype = Object.extend(new Varien.DateElement(), { validateData: function() { var validate = true; if (this.minDate || this.maxValue) { if (this.minDate) { this.minDate = new Date(this.minDate); this.minDate.setHours(0); if (isNaN(this.minDate)) { this.minDate = new Date('1/1/1900'); } validate = validate && (this.fullDate >= this.minDate) } if (this.maxDate) { this.maxDate = new Date(this.maxDate) this.minDate.setHours(0); if (isNaN(this.maxDate)) { this.maxDate = new Date(); } validate = validate && (this.fullDate <= this.maxDate) } if (this.maxDate && this.minDate) { this.validateDataErrorText = 'Please enter a valid date between %s and %s'; } else if (this.maxDate) { this.validateDataErrorText = 'Please enter a valid date less than or equal to %s'; } else if (this.minDate) { this.validateDataErrorText = 'Please enter a valid date equal to or greater than %s'; } else { this.validateDataErrorText = ''; } } return validate; }, validateDataErrorText: 'Date should be between %s and %s', errorTextModifier: function(text) { if (this.minDate) { text = text.sub('%s', this.dateFormat(this.minDate)); } if (this.maxDate) { text = text.sub('%s', this.dateFormat(this.maxDate)); } return text; }, dateFormat: function(date) { return (date.getMonth() + 1) + '/' + date.getDate() + '/' + date.getFullYear(); } }); Varien.FileElement = Class.create(); Varien.FileElement.prototype = { initialize: function (id) { this.fileElement = $(id); this.hiddenElement = $(id + '_value'); this.fileElement.observe('change', this.selectFile.bind(this)); }, selectFile: function(event) { this.hiddenElement.value = this.fileElement.getValue(); } }; Validation.addAllThese([ ['validate-custom', ' ', function(v,elm) { return elm.validate(); }] ]); function truncateOptions() { $$('.truncated').each(function(element){ Event.observe(element, 'mouseover', function(){ if (element.down('div.truncated_full_value')) { element.down('div.truncated_full_value').addClassName('show') } }); Event.observe(element, 'mouseout', function(){ if (element.down('div.truncated_full_value')) { element.down('div.truncated_full_value').removeClassName('show') } }); }); } Event.observe(window, 'load', function(){ truncateOptions(); }); Element.addMethods({ getInnerText: function(element) { element = $(element); if(element.innerText && !Prototype.Browser.Opera) { return element.innerText } return element.innerHTML.stripScripts().unescapeHTML().replace(/[\n\r\s]+/g, ' ').strip(); } }); /* if (!("console" in window) || !("firebug" in console)) { var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; window.console = {}; for (var i = 0; i < names.length; ++i) window.console[names[i]] = function() {} } */ /** * Executes event handler on the element. Works with event handlers attached by Prototype, * in a browser-agnostic fashion. * @param element The element object * @param event Event name, like 'change' * * @example fireEvent($('my-input', 'click')); */ function fireEvent(element, event) { if (document.createEvent) { // dispatch for all browsers except IE before version 9 var evt = document.createEvent("HTMLEvents"); evt.initEvent(event, true, true ); // event type, bubbling, cancelable return element.dispatchEvent(evt); } else { // dispatch for IE before version 9 var evt = document.createEventObject(); return element.fireEvent('on' + event, evt) } } /** * Returns more accurate results of floating-point modulo division * E.g.: * 0.6 % 0.2 = 0.19999999999999996 * modulo(0.6, 0.2) = 0 * * @param dividend * @param divisor */ function modulo(dividend, divisor) { var epsilon = divisor / 10000; var remainder = dividend % divisor; if (Math.abs(remainder - divisor) < epsilon || Math.abs(remainder) < epsilon) { remainder = 0; } return remainder; } /** * createContextualFragment is not supported in IE9. Adding its support. */ if ((typeof Range != "undefined") && !Range.prototype.createContextualFragment) { Range.prototype.createContextualFragment = function(html) { var frag = document.createDocumentFragment(), div = document.createElement("div"); frag.appendChild(div); div.outerHTML = html; return frag; }; }