667 lines
19 KiB
JavaScript
Executable File
667 lines
19 KiB
JavaScript
Executable File
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
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;
|
|
}
|
|
}
|
|
};
|
|
|
|
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 = 'Please enter a date.';
|
|
} 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-%1).';
|
|
} 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) {
|
|
if (jQuery.mage.__) {
|
|
error = jQuery.mage.__(error);
|
|
}
|
|
|
|
if (!valueError) {
|
|
this.advice.innerHTML = error.replace('%1', 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-%1).',
|
|
errorTextModifier: function (text) {
|
|
return text.replace('%1', 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();
|
|
}]
|
|
]);
|
|
|
|
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();
|
|
}
|
|
});
|
|
|
|
/**
|
|
* 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) {
|
|
// dispatch event
|
|
var evt = document.createEvent('HTMLEvents');
|
|
|
|
evt.initEvent(event, true, true); // event type, bubbling, cancelable
|
|
return element.dispatchEvent(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;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Convert byte count to float KB/MB format
|
|
*
|
|
* @param int $bytes
|
|
* @return string
|
|
*/
|
|
var byteConvert = function (bytes) {
|
|
if (isNaN(bytes)) {
|
|
return '';
|
|
}
|
|
var symbols = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
var exp = Math.floor(Math.log(bytes) / Math.log(2));
|
|
|
|
if (exp < 1) {
|
|
exp = 0;
|
|
}
|
|
var i = Math.floor(exp / 10);
|
|
|
|
bytes /= Math.pow(2, 10 * i);
|
|
|
|
if (bytes.toString().length > bytes.toFixed(2).toString().length) {
|
|
bytes = bytes.toFixed(2);
|
|
}
|
|
|
|
return bytes + ' ' + symbols[i];
|
|
};
|