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];
 | |
| };
 |