/**
* amWiki Web端 - 简单 ajax 测试模块
* @author Tevin
*
* @notice 仅当页面存在“请求地址”、“请求类型”、“请求参数”三个h3标题时触发,且参数列表表格顺序不能打乱
*/
(function (win, $) {
'use strict';
/**
* 建接口测试
* @constructor
*/
var Testing = function () {
//缓存元素
this.$e = {
win: $(win),
//测试面板
testingBox: $('#testingBox'),
//md文档渲染处
view: $('#view'),
//上一篇下一篇切换
sibling: $('#mainSibling'),
//面板显示隐藏按钮
testingShow: null,
//参数列表的容器
testingParam: $('#testingParam')
};
//缓存数据
this._data = {
//全局参数列队
globalParams: [],
//全局参数是否生效
globalParamWorking: true,
//单条参数模板
paramTemplate: $('#template\\:formList').text()
};
//请求数据
this._request = {
//请求地址
url: '',
//请求类型
method: '',
//请求参数
params: [],
//全局参数
paramGlobal: []
};
this._useGlobalParam();
this._bindPanelCtrl();
this._bindAjaxSend();
};
/**
* 抓取请求内容,抓取成功才显示按钮
* @public
*/
Testing.prototype.crawlContent = function () {
var that = this;
var testingReqState = [false, false, false];
this.$e.testingShow.removeClass('show');
this.$e.view.find('h3').each(function () {
var $this = $(this);
var name = $.trim($this.text());
//抓取请求地址
if (name == '请求地址' && !testingReqState[0]) {
that._request.url = $.trim($this.next().text());
if (that._request.url.indexOf('http') < 0) {
if (that._request.url.indexOf('/') == 0) {
that._request.url = 'http://' + location.host + that._request.url;
} else {
that._request.url = 'http://' + location.host + '/' + that._request.url;
}
}
testingReqState[0] = true;
}
//抓取请求类型
else if (name == '请求类型' && !testingReqState[1]) {
that._request.method = $.trim($this.next().text()).toUpperCase();
var methodState = false;
['GET', 'POST', 'PUT', 'DELETE'].forEach(function (value, index) {
if (that._request.method == value) {
methodState = true;
}
});
if (!methodState) {
that._request.method = 'POST';
}
testingReqState[1] = true;
}
//抓取请求参数
else if (name == '请求参数' && !testingReqState[2]) {
//清空参数列表
that._request.params.length = 0;
//不存在table直接无参数,存在table时开始解析
if ($this.next('table').length > 0) {
$this.next('table').find('tbody').find('tr').each(function () {
var $tds = $(this).find('td');
//抓取内容
var param = {
keyName: $tds.eq(0).text().replace(/^\s+|\s+$/g, ''),
valueType: $tds.eq(1).text().replace(/^\s+|\s+$/g, ''),
required: $tds.eq(2).text().replace(/^\s+|\s+$/g, ''),
describe: $tds.eq(3).text().replace(/^\s+|\s+$/g, ''),
default: $tds.eq(4).text().replace(/^\s+|\s+$/g, ''),
reference: $tds.eq(5).text().replace(/^\s+|\s+$/g, '')
};
//修正请求参数,正确键名才添加参数
if (param.keyName != '无' && param.keyName != '-' && param.keyName != '') {
//“必填”转换
if (param.required == '是' || param.required == '必填' || param.required == 'yes' || param.required == 'true') {
param.required = 'required';
} else {
param.required = '';
}
//“默认值”转换
if (param.default == '-' || param.default == '无' || param.default == 'Null' || param.default == 'null') {
if (param.reference && param.reference != '-' && param.reference != '无' && param.reference != 'Null' && param.reference != 'null') {
param.default = param.reference;
} else {
param.default = '';
}
}
that._request.params.push(param);
}
});
}
testingReqState[2] = true;
}
});
if (testingReqState[0] && testingReqState[1] && testingReqState[2]) {
this._initPanel();
} else {
this._offPanel();
}
testingReqState = [false, false, false];
};
/**
* 关闭测试面板
* @private
*/
Testing.prototype._offPanel = function () {
this.$e.testingShow.removeClass('show');
if (this.$e.testingShow.hasClass('on')) {
this.displayBox('off');
}
//清除抓取参数
this._request.url = '';
this._request.method = '';
this._request.params = [];
//清空请求地址
$('#testingSendUrl').val('');
//还原请求类型
$('#testingSendType').find('option[value="POST"]').prop('selected', true);
//清空参数列表
this.$e.testingParam.html('');
//重置iframe
$('#testingResponse')[0].contentWindow.location.reload();
};
/**
* 测试面板填充数据
* @private
*/
Testing.prototype._initPanel = function () {
this.$e.testingShow.addClass('show');
//填充请求地址
$('#testingSendUrl').val(this._request.url);
//填充请求类型
$('#testingSendType').find('option[value="' + this._request.method + '"]').prop('selected', true);
//清空现有参数列表
this.$e.testingParam.html('');
//填充参数列表
if (this._request.params.length > 0) {
var paramsHTML = '';
for (var i = 0; i < this._request.params.length; i++) {
paramsHTML += this._data.paramTemplate
.replace('{{describe}}', this._request.params[i].describe)
.replace('{{keyName}}', this._request.params[i].keyName)
.replace('{{default}}', this._request.params[i].default)
.replace('{{valueType}}', this._request.params[i].valueType)
.replace('{{required}}', this._request.params[i].required);
}
this.$e.testingParam.append(paramsHTML);
} else {
this.$e.testingParam.append('
无');
}
};
/**
* 切换测试面板显示隐藏状态
* @param {String} type - on / off
* @public
*/
Testing.prototype.displayBox = function (type) {
var that = this;
if (type == 'off') {
this.$e.testingShow.removeClass('on').find('span').text('测试接口');
this.$e.testingBox.css({
'position': 'absolute'
});
this.$e.view.show().addClass('scroller-content');
this.$e.sibling.addClass('scroller-content').addClass('on');
this.$e.testingBox.removeClass('scroller-content').stop().animate({
'width': '30%',
'opacity': 0
}, 200, 'swing', function () {
that.$e.testingBox.removeAttr('style');
});
} else if (type == 'on') {
this.$e.testingShow.addClass('on').find('span').text('关闭测试');
this.$e.testingBox
.css({
'display': 'block',
'width': '0',
'opacity': 0
})
.stop()
.animate({
'width': '100%',
'opacity': 1
}, 300, 'swing', function () {
that.$e.view.hide().removeClass('scroller-content');
that.$e.sibling.removeClass('scroller-content').removeClass('on');
that.$e.testingBox.addClass('scroller-content').css({
'position': 'relative'
});
});
}
};
/**
* 测试面板普通操作
* @private
*/
Testing.prototype._bindPanelCtrl = function () {
var that = this;
//显示隐藏控制按钮
this.$e.testingShow = $('[测试接口]
');
if (location.protocol == 'file:') {
this.$e.testingShow
.attr('disabled', 'disabled')
.append('您当前为本地模式打开,file:// 协议下不开放接口测试模块,请使用 http(s):// 网址打开');
}
$('#main').append(this.$e.testingShow);
//显示隐藏测试面板
this.$e.testingShow.on('click', function () {
var $this = that.$e.testingShow;
if ($this.attr('disabled') == 'disabled') {
$this.toggleClass('on');
} else {
if (that.$e.testingShow.hasClass('on')) {
that.displayBox('off');
} else {
that.displayBox('on');
}
}
});
//填充请求地址
$('#testingSendUrl').on('change', function () {
that._request.url = $(this).val();
});
//填充请求类型
$('#testingSendType').on('change', function () {
that._request.method = $(this).find("option:selected").val();
});
//清空所有普通参数的值
$('#testingBtnReset').on('click', function () {
that.$e.testingParam.find('.testing-param-val').val('');
});
//新增一个参数
$('#testingBtnAdd').on('click', function () {
var pHTML = that._data.paramTemplate
.replace('{{describe}}', '新增参数')
.replace('{{keyName}}', '')
.replace('{{default}}', '')
.replace('({{valueType}})', '')
.replace('{{required}}', '');
that.$e.testingParam.append(pHTML);
});
};
/**
* 全局参数模块
* @private
*/
Testing.prototype._useGlobalParam = function () {
var that = this;
this._data.globalParams = JSON.parse(localStorage['amWikiGlobalParam'] || '[]'); //全局参数
var gParamTmpl = $('#template\\:globalParam').text(); //全局参数模板
var $testingGlobalParam = $('#testingGlobalParam'); //全局参数显示容器
var $testingGlobal = $('#testingGlobal'); //全局参数弹窗
this._data.globalParamWorking = (localStorage['amWikiGParamWorking'] || 'on') == 'on'; //全局参数是否工作
//显示弹窗
$('#testingBtnGParam').on('click', function () {
$testingGlobalParam.html('');
that._data.globalParams = JSON.parse(localStorage['amWikiGlobalParam'] || '[]');
if (that._data.globalParams.length == 0) {
$testingGlobalParam.append('无');
} else {
for (var p = 0; p < that._data.globalParams.length; p++) {
$testingGlobalParam.append(gParamTmpl.replace('{{describe}}', that._data.globalParams[p].describe)
.replace('{{keyName}}', that._data.globalParams[p].keyName)
.replace('{{value}}', that._data.globalParams[p].value));
}
}
$testingGlobal.show();
});
//基本操作
$testingGlobal.on('click', function (e) {
var $elm = $(e.target);
//关闭
if ($elm.hasClass('close') || $elm.hasClass('testing-global')) {
$testingGlobal.hide();
}
//新增
else if ($elm.hasClass('add')) {
$testingGlobalParam.find('[data-type="empty"]').remove();
$testingGlobalParam.append(gParamTmpl.replace('{{describe}}', '')
.replace('{{keyName}}', '')
.replace('{{value}}', ''));
}
//保存
else if ($elm.hasClass('save')) {
that._data.globalParams.length = 0;
$testingGlobalParam.find('li').each(function (i, elment) {
var $inputs = $(this).find('input');
if ($inputs.eq(1).val()) {
that._data.globalParams.push({
describe: $inputs.eq(0).val(),
keyName: $inputs.eq(1).val(),
value: $inputs.eq(2).val()
});
}
});
localStorage['amWikiGlobalParam'] = JSON.stringify(that._data.globalParams);
$testingGlobal.hide();
}
});
//删除参数
$testingGlobalParam.on('click', 'i', function () {
$(this).parent().remove();
if ($testingGlobalParam.find('li').length == 0) {
$testingGlobalParam.append('无');
}
});
$('#testingGlobalWorking').on('click', function () {
if (that._data.globalParamWorking) {
that._data.globalParamWorking = false;
localStorage['amWikiGParamWorking'] = 'off';
$(this).addClass('off');
} else {
that._data.globalParamWorking = true;
localStorage['amWikiGParamWorking'] = 'on';
$(this).removeClass('off');
}
}).addClass(this._data.globalParamWorking ? '' : 'off');
};
/**
* 发送请求操作
* @private
*/
Testing.prototype._bindAjaxSend = function () {
var that = this;
var frame = $('#testingResponse')[0];
var $duration = $('#testingDuration'); //耗时输出
var $loading = $('#testingLoading');
var $testingParam = $('#testingParam'); //参数列表
$('#testingBtnSend').on('click', function () {
$duration.text('');
var realParam = {}; //合并参数列表
//从面板获取最新(可能已修改)接口参数
if ($testingParam.find('input').length > 0) {
$testingParam.find('li').each(function () {
var $this = $(this);
realParam[$this.find('.testing-param-key').val()] = $this.find('.testing-param-val').val();
});
}
//全局参数
if (that._data.globalParams.length > 0 && that._data.globalParamWorking) {
for (var i = 0; i < that._data.globalParams.length; i++) {
realParam[that._data.globalParams[i].keyName] = that._data.globalParams[i].value;
}
}
frame.contentWindow.location.reload(); //刷新iframe以便重新输出内容
$loading.show();
var startTime = Date.now();
$.ajax({
type: that._request.method,
url: that._request.url,
data: realParam,
dataType: 'text',
success: function (data) {
$loading.hide();
$duration.text('耗时:' + parseFloat(Date.now() - startTime).toLocaleString() + ' ms');
var $frameBody = $(frame.contentWindow.document).find('body');
$frameBody.css('wordBreak', 'break-all');
if (/^\s*\{[\s\S]*\}\s*$/.test(data)) {
$frameBody[0].innerHTML = '';
//json格式化输出
$frameBody.find('pre').text(win.tools.formatJson(data));
} else {
$frameBody[0].innerHTML = data.replace(//, '');
}
setTimeout(function () {
$(frame).height($frameBody.height());
}, 100);
},
error: function (xhr, textStatus) {
$loading.hide();
$duration.text('耗时:' + parseFloat(Date.now() - startTime).toLocaleString() + ' ms');
var $frameBody = $(frame.contentWindow.document).find('body');
$frameBody.css('wordBreak', 'break-all');
var html = 'HTTP Status: ' +
xhr.status + ' ' + xhr.statusText + '
';
//根据readyState简单判断跨域
if (xhr.readyState == 0) {
html += '请求未发送!可能是因为:' +
'
' +
'- 请求了跨域地址
' +
'- 接口被302重定向到跨域地址
' +
'- 其他原因
' +
'
';
$frameBody[0].innerHTML = html;
}
//不跨域且为json
else if (/^\s*\{[\s\S]*\}\s*$/.test(xhr.responseText)) {
html += '';
$frameBody[0].innerHTML = html;
//json格式化输出
$frameBody.find('pre').text(win.tools.formatJson(xhr.responseText));
}
//其他不跨域
else {
html += xhr.responseText.replace(//, '');
$frameBody[0].innerHTML = html;
}
setTimeout(function () {
$(frame).height($frameBody.height());
}, 100);
}
});
});
};
/**
* 判断测试面板是否处于打开状态
* @returns {Boolean}
* @public
*/
Testing.prototype.isOpen = function () {
return this.$e.testingShow.hasClass('on');
};
return win.AWTesting = Testing;
})(window, jQuery);