Files
zszq-trs/YLErpWeb/wwwroot/Scripts/base/main.js
T
hjhan 52c11e7540 fix(diag): 简化 otcDebug 调试开关命名并支持 localStorage 持久化
- __otcDiag 双源对象拆为 __diag(版本元数据, 仅供 banner 展示) + __debug(调试开关布尔值, 唯一真相来源), 消除 __私有对象 与 otcDebug.API 大小写混搭。
- __debug 解析顺序: URL ?otcdebug=1(命中即写回 localStorage) -> localStorage -> 兜底 __diag.debug。同源父子 frame 共享 localStorage, 使 _InfoLayout iframe 弹窗(新增互换交易)自动继承父页面开过的调试开关, 修复弹窗内无调试日志。
2026-07-30 14:42:10 +08:00

852 lines
28 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//依赖类库:lodash.js + jquery + jquery.validate + bootstrap.emodal.js
// 统一调试日志工具:仅在 otcdebug 开启时输出,默认静默(生产零噪音)。
// 开启:URL 加 ?otcdebug=1(会自动写入 localStorage,同源 iframe/弹窗自动继承);
// 或控制台 localStorage.setItem('otcdebug','1')。关闭:localStorage.removeItem('otcdebug')。
// 业务脚本用 otcDebug.banner / otcDebug.log 替代裸 console.log(见 swapTradeEdit.js / fastVue.base.js)。
//
// 命名约定(避免 __私有对象 + otcDebug.API 大小写混搭):
// __diag —— 版本元数据对象(仅 _MainLayout 灌入 ylotc.__diag 时存在,仅供 banner 展示,不参与开关判定)
// __debug —— 调试开关布尔值(唯一真相来源:localStorage 优先 → URL 参数 → 兜底 __diag.debug
var __diag = (window.ylotc && window.ylotc.__diag) || {};
var __debug = (function () {
try {
// 1) URL 参数优先(排查最直观);命中即写入 localStorage,供同源 iframe/弹窗继承
if (/[?&]otcdebug=1/.test(location.search)) { localStorage.setItem('otcdebug', '1'); return true; }
// 2) 已持久化的开关(父页面开过一次,_InfoLayout 弹窗自动生效)
if (localStorage.getItem('otcdebug') === '1') return true;
} catch (e) { /* localStorage 不可用时忽略,继续走兜底 */ }
// 3) 兜底:layout 灌入的 ylotc.__diag.debug(仅 _MainLayout 有)
return !!__diag.debug;
})();
window.otcDebug = {
// 模块加载横幅:F12 一眼看到模块名+版本,用于排查"是不是加载了旧代码/旧缓存"
banner: function (name, ver) {
if (!__debug || !window.console) return;
var git = (__diag.git || '').slice(0, 7);
console.log('%c[' + name + '] v' + ver + ' (bundle=' + __diag.jsVersion + ', git=' + git + ', built=' + __diag.built + ')',
'color:#06c;font-weight:bold');
},
// 普通调试日志:透传参数,仅 debug 开启时输出
log: function () {
if (!__debug || !window.console) return;
console.log.apply(console, arguments);
}
};
var main = window.main || { version: "1.0" };
main.extend = $.extend;
//数字格式化
/**
* 构建数字格式化函数(依赖lodash.js)
* @see Intl.NumberFormat
* @param {any} precision - 小数位精度,默认2,如果是对象类,则当做带precision属性的options处理
* @param {object} options - 格式化选项
* @param {boolean} options.rounded - 是否四舍五入,明确传入false时禁止四舍五入
* @param {boolean} options.grouping - 是否使用千位分隔符,默认false
* @param {boolean} options.percent - 是否百分比格式,默认false
* @param {boolean} options.trimTailZeros - 是否去除小数点后的尾部的0,默认false
* @param {any} options.prefmt
* - 预先格式化,支持多种形式处理
* - 如果传入数组类型的参数值,则循环执行数组中的函数,如果执行结果为string或number类型,则prefmt值取此结果并跳出循环
* - 如果传入函数类型的参数值,prefmt值取函数执行结果
* - 如果prefmt值为数字类型,则格式化prefmt值
* - 如果prefmt值不为undefined|null|false,则返回prefmt值,否则忽略prefmt
* @param {string} options.nanfmt - 输入值解析成数字为NAN时的格式化处理,类型为字符串,默认返回0的格式化数值
* @return {function} - 返回带fromat函数的格式化对象
*/
main.numberFormat = function (precision, options) {
if (typeof precision === 'object') {
options = precision;
precision = options.precision;
}
else if (!options || typeof options !== 'object') {
options = {};
}
//解析小数位精度
precision = parseInt(precision);
if (isNaN(precision)) {
precision = 2;
} else if (precision < 0) {
precision = 0;
} else if (precision > 10) {
precision = 10;
}
//构建Intl.NumberFormat
const fmt = new Intl.NumberFormat('en', {
useGrouping: !!options.grouping,
minimumFractionDigits: precision,
maximumFractionDigits: precision,
style: options.percent ? 'percent' : 'decimal'
});
//百分比格式特殊精度位处理
if (options.percent) precision += 2;
//预格式化处理
function preformat(prefmt, fmtArgs) {
//如果是数组类型,则以管道形式执行函数
if (Array.isArray(prefmt)) {
var result = false;
_.each(prefmt, x => {
let match = typeof x === 'function';
while (match) {
x = x.apply(this, fmtArgs);
switch (typeof x) {
case 'function':
continue;
case 'number':
case 'string':
result = x;
return false;
default: return true;
}
}
});
return result;
}
//执行函数处理
while (typeof prefmt === 'function') {
prefmt = prefmt.apply(this, fmtArgs);
}
return prefmt;
}
function _format(val) {
//预格式化处理
let prefmt = preformat(options.prefmt, arguments);
let type = typeof prefmt;
if (type === 'number') {
val = prefmt;
}
else if (type !== 'undefined' && prefmt !== null && prefmt !== false) {
return prefmt;
}
if (precision <= 4) {
val = _.round(val, precision + 4);
}
//数值格式化
if (options.rounded !== false) {
let negative = val < 0;
val = _.round(negative ? -val : val, precision);
negative && (val = -val);
} else {
val = _.floor(val, precision);
}
if (isNaN(val)) {
return typeof options.nanfmt === 'string' ? options.nanfmt : fmt.format(0);
}
return fmt.format(Math.abs(val) < 1e-6 ? 0 : val);
}
function format(val) {
let str = _format(val);
return options.trimTailZeros && str.endsWith("0") && precision > 0 ? str.replace(/\.?0+$/, '') : str;
}
format.precision = precision;
return format;
};
/**
* 格式化数字(依赖lodash.js)
* @param {object} number - 数字数值
* @param {any} precision - 小数位精度,默认2,如果是对象类,则当做带precision属性的options处理
* @param {object} options - 格式化选项
* @param {boolean} options.rounded - 是否四舍五入,类型为布尔值,默认true
* @param {boolean} options.grouping - 是否使用千位分隔符,类型为布尔值,默认false
* @param {boolean} options.percent - 是否百分比格式,类型为布尔值,默认false
* @param {string} options.nanfmt - 输入值解析成数字为NAN时的格式化处理,类型为字符串,默认返回0的格式化数值
* @param {any} options.prefmt - 参考main.numberFormat
* @return {function} - 返回带fromat函数的格式化对象
*/
main.formatNumber = function (number, precision, options) {
return new main.numberFormat(precision, options)(number);
};
//各种常用处理
const __alert = function (message) {
window.alert(message);
return false;
};
/**
* 显示页面加载组件,等待操作执行完成
* @param {string} method -- 'show'||'hide'
* @returns {jQuery} -- jQuery对象
*/
$.fn.waitMe = function (method) {
return this.each(function () {
if (this.showCount === undefined || this.showCount === null) {
this.showCount = 0;
}
var isBody = $(this).is('body');
var $waitme = $(this).children(".yl-waitme");
if (method === "show") {
if (!$waitme.length) {
!isBody && $(this).css("position") === "static" && $(this).css("position", "relative");
$waitme = $('<div class="yl-waitme"></div>');
$waitme.appendTo($(this));
}
$waitme.show();
this.showCount++;
} else if (this.showCount > 0) {
(this.showCount -= 1) === 0 && $waitme.remove();
}
});
};
main.logError = function (data) {
if (!data) return;
if (console && typeof console.error === "function") {
console.error(data);
} else if ($.isPlainObject(data) || data.length) {
alert(JSON.stringify(data));
} else {
alert(data);
}
};
const _systemmsg = [];
/**
* 显示通知消息
* @param {any} message -- 消息文本
* @param {any} time -- 显示时间
* @returns {boolean} -- false
*/
main.message = function (message, time) {
main.toast(message, time);
try {
if (_systemmsg.length >= 3) {
_systemmsg.splice(0, 1);
}
_systemmsg.push(message);
$("#systemspanmsg").html(_systemmsg.join(";"));
} catch (e) {
console.log("[ERROR:main.message]" + e);
}
return false;
};
main.toast = function (message, delay) {
if (!$('#toast-container').length) {
$('<div id="toast-container" class="toast-container">').appendTo('body');
}
var $t = $(`
<div class="toast toast-main">
<div class="toast-header pb-0 pt-3">
<span class="mr-auto">提示</span>
<button type="button" class="close" data-dismiss="toast"><strong>&times;</strong></button>
</div>
<div class="toast-body">${message}</div>
</div>`);
$t.appendTo('#toast-container').toast({ autohide: true, delay: delay || 3000 }).toast('show')
.on('hidden.bs.toast', function () { $t.remove(); }).on('click', function () {
$(this).toast('hide');
});
return false;
};
/**
* 显示警告信息
* @param {any} message -- 消息文本
* @returns {boolean} -- false
*/
main.warn = function (message) {
return main.message(message, 60 * 60 * 1000);
};
/**
* 显示警告弹窗
* @param {any} message -- 消息文本
* @returns {boolean} -- false
*/
main.alert = function (message, okCall) {
$.alert({
title: '提示',
content: (message || '').replace('\n', '<br>'),
buttons: {
ok: { text: '确定', action: okCall }
},
boxWidth: '450px',
useBootstrap: false,
animateFromElement: false
});
return false;
};
/**
* 显示确认弹窗
* @param {any} message -- 确认消息
* @param {any} okCallback -- 确认执行回调
* @param {any} cancelCallback -- 取消后回调
* @param {any} title -- 弹窗标题
*/
main.confirm = function (message, okCallback, cancelCallback, title) {
$.confirm({
title: title || '确认?',
content: message,
type: 'red',
buttons: {
ok: {
text: "确认",
btnClass: 'btn-primary',
keys: ['enter'],
action() {
if (okCallback) {
var tempCall = okCallback;
//确保只执行一次
okCallback = null;
tempCall();
}
}
},
cancel: {
text: "取消",
action() {
cancelCallback && cancelCallback();
}
}
},
useBootstrap: false,
boxWidth: '450px',
animateFromElement: false
});
};
//使用$.Deferred对象处理
main.confirmV2 = function (message, title) {
var deferred = $.Deferred();
$.confirm({
title: title || '确认?',
content: message,
type: 'red',
buttons: {
ok: {
text: "确认",
btnClass: 'btn-primary',
keys: ['enter'],
action: deferred.resolve
},
cancel: {
text: "取消",
action: deferred.reject
}
},
useBootstrap: false,
boxWidth: '450px',
animateFromElement: false
});
return deferred.promise();
};
main.waitMe = function (opt) {
if (typeof opt === 'boolean') {
opt = opt ? 'show' : 'hide';
} else {
opt = opt || "show";
}
$(document.body).waitMe(opt);
};
function __getWaitMeFunc(options) {
var waitMeFunc = main.waitMe;
if (typeof options !== 'undefined') {
var m = options.waitMe;
if (typeof m === 'undefined') {
m = options;
}
if (!m) {
waitMeFunc = function () { };
} else if (typeof m === 'function') {
waitMeFunc = m;
}
}
return waitMeFunc;
}
/**
* ⚠️【全局陷阱 / 接手必读】__post 的成败路由:
* - 成功(resp.success 为真 且 非 errcode) -> deferred.resolve(resp) .done 触发)
* - 业务错误(resp.success===false / errcode) -> deferred.reject(resp) .fail 触发,.done 不触发!)
* - 网络异常(ajax error) -> deferred.reject(resp) .fail 触发)
* 即:业务错误走的是 reject,不是 resolve。调用方若只在 .done(...) 里写「业务失败/算不出来」的处理,
* 业务失败时那段代码根本不会执行 —— 这是 bug 静默失效的高发地。
* 典型实例:swapTradeEdit.js 的 calcBondForItem「约定2补充(计算器算不出→清另两字段+清标识)」曾因
* applyBondCalcFailure 只写在 .done 内、长期不生效;后改到 .fail 才修复(见该文件注释)。
* 凡要区分「成功 / 业务失败 / 网络异常」的逻辑,务必在 .done 之外再挂 .fail。
*/
function __post(url, data, deferred, options) {
if (!url) throw "post url 不能为空";
var waitMeFunc = __getWaitMeFunc(options);
var ajaxOptions = {
type: "POST",
data: data,
dataType: "json",
cache: false,
success(resp) {
if (options && options.dataType && options.dataType !== "json") {
deferred.resolve(resp);
return;
}
if (resp.success === false || resp.errcode) {
let alert = options && options.alertFn ? options.alertFn : main.alert;
let errmsg = (resp.msg || resp.errmsg || "错误").replace(/\n/g, '<p></p>');
alert(errmsg);
deferred.reject(resp);
} else {
resp.msg && main.message(resp.msg);
deferred.resolve(resp);
}
},
beforeSend(jqXHR) {
waitMeFunc(true);
},
complete(jqXHR, textStatus) {
waitMeFunc(false);
},
error(jqXHR, textStatus, errorThrown) {
options && options.suppressError || main.alert('请求失败');
console.error("请求失败,url:" + url + ",status:" + textStatus + ",error:" + errorThrown);
}
};
if (data instanceof FormData) {
ajaxOptions.processData = false;
ajaxOptions.contentType = false;
}
ajaxOptions = $.extend(ajaxOptions, options);
$.ajax(url, ajaxOptions).fail(deferred.reject);
}
/**
* 封装$.ajax方法
* @param {any} options
* -- boolean:是否显示加载等待
* -- function:自定义加载等待调用
* -- object:{waitMe,suppressError}
* @param {boolean} options.waitMe -- 是否显示加载等待
* @param {boolean} options.suppressError -- 禁止出错时提示
* @returns {jQuery} -- jquery延迟对象Deferred
*/
main.ajax = function (options) {
var deferred = $.Deferred();
var waitMeFunc = __getWaitMeFunc(options);
var ajaxOptions = {
type: "POST",
dataType: "json",
success(resp) {
if (resp.success === false) {
main.alert(resp.msg || "错误");
deferred.reject(resp);
} else {
main.message(resp.msg || "成功");
deferred.resolve(resp);
}
},
beforeSend: function () {
waitMeFunc(true);
},
complete: function () {
waitMeFunc(false);
},
error(jqXHR, textStatus, errorThrown) {
let error = "请求失败,url:" + url + ",status:" + textStatus + ",error:" + errorThrown;
(options.suppressError ? console.error : main.alert)(error);
}
};
ajaxOptions = $.extend(ajaxOptions, options);
$.ajax(ajaxOptions).fail(deferred.reject);
return deferred.promise();
};
/**
* 封装$.Post
* @param {any} url -- post url
* @param {any} data -- post data
* @param {any} options
* -- boolean:是否显示加载等待
* -- function:自定义加载等待调用
* -- object:{waitMe,suppressError}
* @param {boolean} options.waitMe -- 是否显示加载等待
* @param {boolean} options.suppressError -- 禁止出错时提示
* @returns {jQuery} -- jquery延迟对象Deferred
*/
// ⚠️ 见上方 __post 说明:本方法业务错误/网络异常走 reject,调用方需 .fail 才能捕获(只 .done 会漏掉失败分支)。
main.post = function (url, data, options) {
var d = $.Deferred();
__post(url, data, d, options);
return d.promise();
};
/**
* main.postSafe — 安全版 main.post,返回标准 Promise 而非 jQuery Deferred。
* ============================================================================
* 解决 main.post 的「业务错误走 reject、.done 不触发」陷阱(见 __post 注释)。
*
* 用法:
* main.postSafe('/api/calc', { price: 100 })
* .then(function(resp) { /* 成功(含 resp.success !== false*\/ })
* .catch(function(resp) { /* 业务错误 / 网络异常 *\/ });
*
* 或者 async/await
* try {
* var resp = await main.postSafe('/api/calc', { price: 100 });
* // 成功
* } catch (resp) {
* // 业务错误 / 网络异常(resp 可能是 { success:false, msg:'...' } 或 Error
* }
*
* 与 main.post 的区别:
* - main.post 返回 jQuery Deferred.done = 成功, .fail = 失败
* - main.postSafe 返回 Promise .then = 成功, .catch = 失败
* - 行为一致,但 Promise 更符合标准,async/await 更自然
*
* @param {string} url -- post url
* @param {any} data -- post data
* @param {any} options -- 同 main.post
* @returns {Promise} -- 成功 resolve(resp),失败 reject(resp)
* ============================================================================
*/
main.postSafe = function (url, data, options) {
return new Promise(function (resolve, reject) {
main.post(url, data, options)
.done(function (resp) { resolve(resp); })
.fail(function (resp) { reject(resp); });
});
};
//确认提交
main.confirmPost = function (confirmText, url, data, options) {
var d = $.Deferred();
var okCallback = function () {
__post(url, data, d, options);
};
var cancelCallback = function () {
d.reject({ cancel: true });
};
main.confirm(confirmText, okCallback, cancelCallback, "提示");
return d.promise();
};
//以提交表单的方式打开新页面
main.formOpenNewPage = function (url, postData) {
var $f = $('<form target="_blank" method="post" action="' + url + '">')
_.each(postData, (val, key) => {
if ($.isArray(val)) {
_.each(val, (v, i) => {
$f.append('<input type="hidden" name="' + key + '[' + i + ']" value="' + v + '" />');
})
} else {
$f.append('<input type="hidden" name="' + key + '" value="' + val + '" />');
}
});
$f.appendTo("body").submit();
$f.remove();
};
//转换为string
main.toString = function (val) {
if (typeof val === 'undefined' || val === null) {
return "";
}
return val.toString();
}
/**
* 封装表单操作(表单验证+表单提交)
* @param {any} options -- 选项,可以直接传入form对象
* @param {any} options.el -- form元素或者jquery对象或者jquery选择器
* @param {any} options.submit -- 默认true,内部自动生成ajax post提交处理,如果为false则不自动提交
* 自定义提交选项:
* {
* url: string,提交地址,默认选用form元素的action属性或window.location.href,
* before: function,提交前的回调,返回false则中止提交
* after: function,提交成功后的回调
* postData: function,获取提交数据,如果未赋值则使用默认的表单序列化函数
* }
* @param {any} options.validate -- 默认true,内部自动附加验证器,false则不验证或者传入function对象使用自定义验证
* @returns {any} --
*/
main.form = function (options) {
if (!options) {
return __alert('[错误][main.form]缺少选项');
}
!$.isPlainObject(options) && (options = { el: options });
var $form, _hasSaved = 0;
function __init() {
//jquery form
$form = options.el instanceof jQuery ? options.el : $(options.el);
if (!$form.is("form")) {
$form = $form.find("form:first");
if (!$form.length) {
return __alert("[错误][main.form]没有找到form元素");
}
}
let submit = options.submit;
let validate = options.validate;
let sumbitHandler = __submitHandle;
if (submit === false) {
sumbitHandler = function () { return true; };
}
else {
!$.isPlainObject(submit) && (submit = {});
!$.trim(submit.url) && (submit.url = $.trim($form.attr('action')) || window.location.href);
options.submit = submit;
}
//设置表单验证
if ($form.attr('novalidate') !== undefined || validate === false) {
return;
}
//自定义表单验证
if (typeof validate === "function") {
$form.attr("novalidate", true);
$form.on("submit.validate", function () {
try {
validate($form) && sumbitHandler();
} finally {
return false;
}
});
return;
}
//jquery.validate表单验证
if (typeof validate === "object") {
validate = $.extend({ submitHandler: sumbitHandler }, validate);
} else {
validate = { submitHandler: sumbitHandler };
}
main.formValidate($form, validate);
}
//表单提交处理
function __submitHandle(form) {
var submit = options.submit;
try {
if (typeof submit.before === "function" && submit.before(form) === false) {
return false;
}
if (!submit.url) {
return __alert("[错误][main.form]submit.url未配置");
}
let data = typeof submit.postData === 'function' ? submit.postData() : $form.serialize();
main.post(submit.url, data).done(function (resp) {
_hasSaved += 1;
submit.after && submit.after(resp, _hasSaved);
});
} catch (e) {
console.log(e);
} finally {
return false;
}
}
$(__init);
return {
submit() { $form.submit(); }
};
};
/**
* 表单验证
* @param {any} form -- 表单元素或者jquery对象或者jquery元素选择器
* @param {any} options --jquery validate选项或者submitHandler函数
* @returns {any} --
*/
main.formValidate = function (form, options) {
if (typeof options === "function") {
options = { submitHandler: options };
}
if (!form) {
return __alert("[main.formValidate]参数错误:form");
}
if (!(form instanceof jQuery)) {
form = $(form);
}
//添加自定义验证规则,格式:$method:$param[message]$message[+]$method:$param[message]$message...
function __addCustomRule($el) {
var rulestr = $.trim($el.data("validate"));
if (!rulestr) return;
var ruleArr = rulestr.split("[+]");
ruleArr.forEach(function (rulePart) {
rulePart = rulePart.trim();
if (!rulePart) return;
if (!/^[a-zA-Z]/.test(rulePart)) {
console.error("不是正确的验证表达式:" + rulePart);
return;
}
let message, param, method;
let index1 = rulePart.indexOf(':');
method = rulePart.substring(0, index2).trim();
if (!method) {
console.error("不是有效的验证表达式(缺少method):" + rulePart);
return;
}
let index2 = rulePart.indexOf('[message]');
if (index2 > 0) {
message = rulePart.substring(index2 + 9).trim();
}
if (index1 > 0) {
param = rulePart.substring(index1, index2).trim();
}
let rule = {};
rule[method] = param || true;
if (message) {
rule.messages = {};
rule.messages[method] = decodeURIComponent(message);
}
$el.rules("add", rule);
});
}
var validator = form.validate(options);
form.find('input').each(function () {
var type = $(this).attr("type");
if (type === "text" || type === "password") {
__addCustomRule($(this));
}
});
return validator;
};
/**
* 解码HTML
* @param {any} inputStr
* @returns
*/
main.decodeHtmlEntity = function (inputStr) {
if (typeof inputStr !== 'string') return inputStr;
if (!inputStr) return '';
var textarea = document.createElement("textarea");
textarea.innerHTML = inputStr;
return textarea.value;
};
//jquery.validator
(function (factory) {
if (typeof define === "function" && define.amd) {
define(["jquery", "jquery.validate"], factory);
} else if (typeof module === "object" && module.exports) {
module.exports = factory(require("jquery"));
} else {
factory(jQuery);
}
}(function ($) {
if (!$.validator) {
return $;
}
$.validator.setDefaults({
errorElement: "span",
submitHandler: function () {
return true;
},
errorPlacement: function (error, element) {
error.appendTo(element.parent());
}
});
$.validator.addMethod("pattern", function (val, element, param) {
if (this.optional(element) || !param) {
return true;
}
val = val.replace(/(^\s*)|(\s*$)/g, "");
return new RegExp("^" + param + "$").test(val);
}, "输入不符合要求");
$.extend($.validator.messages, {
required: "必填",
remote: "请修正此字段",
email: "请输入有效的电子邮件地址",
url: "请输入有效的网址",
date: "请输入有效的日期",
dateISO: "请输入有效的日期 (YYYY-MM-DD)",
number: "请输入有效的数字",
digits: "只能输入数字",
creditcard: "请输入有效的信用卡号码",
equalTo: "你的输入不相同",
extension: "请输入有效的后缀",
maxlength: $.validator.format("最多可以输入 {0} 个字符"),
minlength: $.validator.format("最少要输入 {0} 个字符"),
rangelength: $.validator.format("请输入长度在 {0} 到 {1} 之间的字符串"),
range: $.validator.format("请输入范围在 {0} 到 {1} 之间的数值"),
step: $.validator.format("请输入 {0} 的整数倍值"),
max: $.validator.format("请输入不大于 {0} 的数值"),
min: $.validator.format("请输入不小于 {0} 的数值")
});
return $;
}));
//例:$('#form1').serializeObject
jQuery.prototype.serializeObject = function () {
var obj = new Object();
$.each(this.serializeArray(),
function (index, param) {
if (param.name in obj) {
obj[param.name] = [].concat(obj[param.name], param.value);
} else {
obj[param.name] = param.value;
}
});
return obj;
};
if (!String.prototype.replaceAll) {
String.prototype.replaceAll = function (oldString, newString) {
oldString = _.escapeRegExp(oldString);
return this.replace(new RegExp(oldString, "gm"), newString)
}
}