var echart;
var noDataDom;
$(function()
{
var chart = DataStorage.clone('chart');
if(!chart.settings || !(chart.settings instanceof Array)) chart.settings = [{type: chart.type ? chart.type : 'pie'}];
if(!chart.settings.length) chart.settings = [{type: chart.type ? chart.type : 'pie'}];
if(!chart.filters || !(chart.filters instanceof Array)) chart.filters = [];
DataStorage.chart = chart;
switchStep(DataStorage.step);
$('#type').picker({'maxDropHeight': pickerHeight});
$('body').resize(() => {calcDesignGrowFilter(true);});
});
/**
* Tab click callback.
*
* @param object evt
* @param int nextStep
* @access public
* @return void
*/
function tabClick(evt, nextStep)
{
var step = DataStorage.step;
if($(evt).hasClass('disabled') || step == nextStep) return;
if(nextStep < step)
{
DataStorage.step = nextStep;
switchStep(nextStep);
return;
}
finishStep(step, nextStep, function(nextStep)
{
DataStorage.step = nextStep;
switchStep(nextStep);
});
}
/**
* Next step click callback.
*
* @access public
* @return void
*/
function nextStep()
{
var step = DataStorage.step;
finishStep(step, step + 1, function(nextStep)
{
DataStorage.step = nextStep;
switchStep(nextStep);
});
}
/**
* Submit publish.
*
* @access public
* @return void
*/
function publish(stage = 'published')
{
var chart = DataStorage.clone('chart');
var isPublished = chart.stage == 'published';
if(stage == 'published' && !validate()) return;
if(stage == 'draft')
{
var chart = DataStorage.clone('chart');
var newSql = $('#sql').val().replace(';', "").trim();
var hasSettings = checkSettings();
var sqlChange = chart.sql.length > 0 && newSql !== chart.sql;
if(sqlChange && hasSettings)
{
bootbox.confirm(clearSettingsLang, function(res)
{
if(res)
{
/* Init chart design settings */
chart.settings = [{type: 'pie'}];
/* Init filter settings */
chart.filters = [];
loadConfigForm('pie', true);
buildSettingForm(true);
if(chart.used)
{
bootbox.confirm({message:confirmDraft,callback:save.bind(null, stage)});
}
else
{
if(isPublished) bootbox.confirm({message:chartLang.draftSave,callback:save.bind(null, stage)});
if(!isPublished) save(stage);
}
DataStorage.chart = chart;
}
});
}
else
{
if(chart.used)
{
bootbox.confirm({message:confirmDraft,callback:save.bind(null, stage)});
}
else
{
if(isPublished) bootbox.confirm({message:chartLang.draftSave,callback:save.bind(null, stage)});
if(!isPublished) save(stage);
}
}
return;
}
if(chart.used) bootbox.confirm({message:confirmPublish,callback:save.bind(null, stage)});
if(!chart.used) save(stage)
}
function save(stage, status = true)
{
if(!status || DataStorage.saving) return;
DataStorage.saving = true;
var chart = DataStorage.clone('chart');
var fields = DataStorage.fields;
var fieldSettings = DataStorage.fieldSettings;
var langs = DataStorage.langs;
var sqlbuilder = DataStorage.sqlbuilder;
if(sqlbuilder && sqlbuilder.sql !== undefined) sqlbuilder.sql = window.latin1ToBase64(sqlbuilder.sql);
chart.sql = window.latin1ToBase64($('#sql').val().replace(';', "").trim());
chart.step = DataStorage.step;
chart.mode = DataStorage.mode;
chart.fields = Object.keys(fields);
chart.fieldSettings = fieldSettings;
chart.langs = langs;
chart.stage = stage;
chart.type = chart.settings[0].type;
chart.acl = $('input[name="acl"]:checked').val();
chart.whitelist = $('select[name="whitelist[]"]').val();
chart.sqlbuilder = JSON.stringify(sqlbuilder);
DataStorage.chart = chart;
$.post(createLink('chart', 'design', 'chartID=' + chart.id), chart, function(response)
{
response = JSON.parse(response);
if(response.result == 'success')
{
success(response.message);
setTimeout(function()
{
window.location.href = createLink('chart', 'browse')
DataStorage.saving = false;
}, 2000);
}
else
{
DataStorage.saving = false;
/* The result.message is just a string. */
if($.type(response.message) == 'string')
{
if($('#responser').length == 0) return alert(response.message);
return $('#responser').html(response.message).addClass('text-error').show().delay(3000).fadeOut(100);
}
/* The result.message is just a object. */
if($.type(response.message) == 'object')
{
var triggered = new Array();
$.each(response.message, function(key, value)
{
/* Define the id of the error objecjt and it's label. */
var errorOBJ = '#legendBasicInfo #' + key;
var errorLabel = key + 'Label';
var i = triggered.push(false);
/* Create the error message. */
var errorMSG = '
';
errorMSG += $.type(value) == 'string' ? value : value.join(';');
errorMSG += '
';
/* Append error message, set style and set the focus events. */
$('#' + errorLabel).remove();
var isInputGroup = $(errorOBJ).closest('.input-group').size();
var $showOBJ = isInputGroup ? $(errorOBJ).closest('.input-group').parent() : $(errorOBJ).parent();
$showOBJ.append(errorMSG);
$(errorOBJ).css('margin-bottom', 0);
$(errorOBJ).css('border-color','#D2322D');
if($(errorOBJ + '_chosen').size() > 0)
{
$(errorOBJ + '_chosen .chosen-single').css('border-color','#D2322D');
$(errorOBJ + '_chosen').bind('keydown mousedown', function()
{
if(!triggered[i])
{
$(this).removeAttr('style');
$('#' + errorLabel).remove();
triggered[i] = true;
}
});
}
$(errorOBJ).bind('keydown mousedown', function()
{
if(!triggered[i])
{
$(this).removeAttr('style');
$('#' + errorLabel).remove();
triggered[i] = true;
}
});
if(i == 1)$(errorOBJ).focus();
})
}
}
});
}
/**
* Finish current step and check.
*
* @param int step
* @access public
* @return void
*/
function finishStep(step, nextStep, callback)
{
if(step == 1)
{
var check = checkStep1();
if(!check) return false;
/* Update sql query values */
getFieldSettings();
var newSql = $('#sql').val().replace(';', "").trim();
var hasSettings = checkSettings();
var chart = DataStorage.clone('chart');
/* Fix bug #32348. */
chart.sqlChange = chart.sql.length > 0 && newSql !== chart.sql;
if(chart.sqlChange && hasSettings)
{
bootbox.confirm(resetSettingsLang, function(res)
{
if(res)
{
/* Remove step active. */
$('#step1').nextAll('.step-tab').removeClass('active');
/* Set chart refreshTab for function getFinish. */
chart.refreshTab = true;
chart.stage = 'draft';
/* Init chart design settings */
chart.settings = [{type: 'pie'}];
/* Init filter settings */
chart.filters = [];
loadConfigForm('pie', true);
buildSettingForm(true);
chart.sql = newSql;
chart.fields = Object.keys(fields);
chart.fieldSettings = fieldSettings;
DataStorage.chart = chart;
if(callback instanceof Function) callback(2);
}
});
return false;
}
chart.sql = newSql;
chart.fields = Object.keys(fields);
chart.fieldSettings = fieldSettings;
DataStorage.chart = chart;
}
if(step == 2)
{
var check = checkStep2();
if(!check) return false;
}
if(callback instanceof Function) callback(nextStep);
}
/**
* Load chart config form.
*
* @param string type
* @access public
* @return void
*/
function loadConfigForm(type, update = false)
{
if(echart) echart.clear();
var chart = DataStorage.clone('chart');
chart.type = type;
chart.settings = [{type: type}];
DataStorage.chart = chart;
if(update) $('select#type').data('zui.picker').setValue(type);
/* Show current html form. */
buildSettingForm(true, function()
{
if(validate()) ajaxGetChart();
});
}
/**
* Listen pie config form change.
*
* @param string value
* @param string field
* @param bool required
* @access public
* @return void
*/
function pieChange(value, field, required = false, multi = 0)
{
if(multi)
{
refreshMulti(this);
}
else
{
var chart = DataStorage.clone('chart');
/* Pie have group and metirc, others have xaxis. */
var isEmpty = value == '';
if(field == 'group' || field == 'xaxis')
{
var fieldName = isEmpty ? '' : DataStorage.fieldSettings[value].name;
var fieldType = isEmpty ? '' : DataStorage.fieldSettings[value].type;
var dateClass = fieldType == 'date' ? '' : 'hidden';
$('#dateGroup').removeClass();
$('#dateGroup').addClass(dateClass);
clearRadioChecked();
chart.settings[0][field] = [{field: value, name: fieldName, group: ''}];
}
else if(field == 'metric')
{
var agg = $('#valOrAgg').val();
var fieldName = isEmpty ? '' : DataStorage.fieldSettings[value].name;
chart.settings[0][field] = [{field: value, name: fieldName, valOrAgg: agg}];
}
else if(field == 'dateGroup')
{
var type = chart.settings[0].type;
var field = type == 'pie' ? 'group' : 'xaxis';
chart.settings[0][field][0].group = value;
}
else if(field == 'valOrAgg')
{
var field = $('#metric').val();
var fieldName = DataStorage.fieldSettings[field].name;
chart.settings[0]['metric'] = [{field: field, name: fieldName, valOrAgg: value}];
}
else if(field == 'rotateX' || field == 'rotateY')
{
var isChecked = $('input#' + field + '0')[0].checked;
chart.settings[0][field] = isChecked ? 'use' : 'notuse';
}
DataStorage.chart = chart;
}
refreshChart();
}
/**
* Build setting form.
*
* @access public
* @return void
*/
function buildSettingForm(dropOld = false, callback = '')
{
var chart = DataStorage.chart;
var fieldSettings = DataStorage.fieldSettings;
var langs = DataStorage.langs;
var type = chart.settings[0].type;
var $form = $('#chartForm');
if(dropOld)
{
$form.empty();
var fieldNames = {};
Object.keys(fieldSettings).forEach(function(key){fieldNames[key] = fieldSettings[key].name});
$.post(createLink('chart', 'ajaxGetTypeForm', 'id=' + chart.id + '&type=' + type),
{
fields: fieldNames,
values: chart.settings[0],
fieldSettings: fieldSettings,
langs: langs,
sql: window.latin1ToBase64(chart.sql)
}, function(data)
{
$form.html($(data));
initPicker($form);
var type = chart.settings[0].type;
if(type == 'waterpolo') $('.denominator-tip').popover();
if(['line', 'cluBarX', 'cluBarY', 'stackedBar', 'stackedBarY'].includes(type)) $('.rotate-tip').popover();
if(callback instanceof Function) callback();
});
}
}
/**
* Add row.
*
* @param obj $obj
* @param field $field
* @access public
* @return void
*/
function addRow(obj, field)
{
var chart = DataStorage.chart;
var type = chart.settings[0].type;
var tplName = '#' + type + 'Column';
var row = $(tplName).html();
$('' + row + '
').insertAfter($(obj).closest('tr'));
var butClass = '.del-' + field;
var delCount = $(obj).parents('tbody').find('.del-' + field).length;
if(delCount == 2) $(obj).parents('tbody').find('.del-' + field).eq(0).removeClass('hidden');
var $row = $(obj).closest('tr').next();
initPicker($row, 'hidden-picker-select');
}
/**
* Delete row.
*
* @param obj $obj
* @param field $field
* @access public
* @return void
*/
function deleteRow(obj, field)
{
var chart = DataStorage.chart;
var type = chart.settings[0].type;
var buttons = $('#chartForm .table-form .del-' + field);
var delCount = buttons.length;
var th = buttons.eq(0).parents('tr').find('th').text();
$(obj).closest('tr').remove();
if(delCount === 2) $('#chartForm .del-' + field).eq(0).addClass('hidden');
$('#chartForm .del-' + field).eq(0).parents('tr').find('th').text(th);
var isReady = validate();
refreshMulti();
refreshChart();
}
/**
* Refresh multi form values.
*
* @access public
* @return void
*/
function refreshMulti()
{
var chart = DataStorage.clone('chart');
var fieldSettings = DataStorage.fieldSettings;
var type = chart.settings[0].type;
var chartSetting = chartSettings[type];
var multiColumn = multiColumns[type];
var multiSettings = chartSetting[multiColumn];
var fields = multiSettings.map(function(item){return item.field});
var settingInfo = {};
fields.forEach(function(field)
{
settingInfo[field] = [];
$('#chartForm .table-form').find('.multi-' + field).each(function()
{
settingInfo[field].push($(this).val());
});
});
/* Set chart.settings[0]['yaxis']. */
var yaxisSetting = [];
for(var index = 0; index < settingInfo.yaxis.length; index ++)
{
var yaxis = settingInfo.yaxis[index];
if(yaxis.length == 0) continue;
var fieldName = fieldSettings[yaxis].name;
var valOrAgg = settingInfo.valOrAgg[index];
yaxisSetting.push({field: yaxis, name: fieldName, valOrAgg: valOrAgg});
}
chart.settings[0]['yaxis'] = yaxisSetting;
DataStorage.chart = chart;
}
/**
* Refresh chart draw.
*
* @access public
* @return void
*/
function refreshChart()
{
var isReady = validate();
if(isReady)
{
ajaxGetChart();
}
else
{
echart.clear();
}
}
/**
* Get current finish step stage.
*
* @access public
* @return int
*/
function getFinish()
{
var chart = DataStorage.clone('chart');
if('refreshTab' in chart)
{
delete chart.refreshTab;
DataStorage.chart = chart;
return 1;
}
if(chart.stage == 'published' || chart.stage == 4) return 4;
if(checkStep2(false)) return 2;
if(checkStep1(false)) return 1;
return 0;
}
function checkSettings()
{
var chart = DataStorage.chart;
var type = chart.settings[0].type;
var chartSetting = chartSettings[type];
for(var key in chartSetting)
{
var exist = chartSetting[key].find(function(field)
{
return field.required && chart.settings[0][field.field];
});
if(exist) return true;
}
return false;
}
/**
* Check step 1 is finished.
*
* @param bool page
* @access public
* @return bool
*/
function checkStep1(page = true)
{
var chart = DataStorage.chart;
if(!page)
{
var sql = chart.sql;
var fields = DataStorage.fields;
var fieldSettings = DataStorage.fieldSettings;
return sql && fieldSettings && fields && sql.length > 0 && Object.keys(fieldSettings).length > 0 && Object.keys(fields). length > 0;
}
$.ajaxSettings.async = false;
query();
$.ajaxSettings.async = true;
return $('#dataform .error').length == $('#dataform .error.hidden').length;
}
/**
* Check step 2 is finished.
*
* @param bool page
* @access public
* @return bool
*/
function checkStep2(page = true)
{
if(!page)
{
var settings = DataStorage.chart.settings;
return settings instanceof Array && settings.length > 0 && validate();
}
return validate(true);
}
function switchStep(step)
{
setStepActive(step);
setStepEnable(step);
buildSettingForm(true, initStep(step));
}
function initStep(step)
{
if(step == 1) return;
if(echart) echart.dispose();
var echartDom = $('#step' + step + 'Content').find('#draw').get(0);
echart = echarts.init(echartDom);
noDataDom = $('#step' + step + 'Content').find('#draw-no-data');
if(validate()) ajaxGetChart();
if(step == 2 || step == 3 || step == 4) renderFilters(step);
}
/**
* Set step tab label active.
*
* @param int step
* @access public
* @return void
*/
function setStepActive(step)
{
/* Remove old class and Add new active class. */
//$('.step-tab').removeClass('active current');
$('.step-tab').removeClass('current');
$('#step' + step).addClass('active current');
$('#step' + step).prevAll('.step-tab').addClass('active');
$('.step-content').hide();
$('#step' + step + 'Content').show();
}
/**
* Set step tab label enable.
*
* @access public
* @return void
*/
function setStepEnable(step)
{
var stus = [];
var finish = getFinish();
if(finish == 0) stus = [1, 1, 0, 0];
if(finish == 1 && step == 1) stus = [1, 1, 0, 0];
if(finish == 1 && step == 2) stus = [1, 1, 1, 0];
if(finish == 2 || finish == 4) stus = [1, 1, 1, 1];
$('.step-tab').removeClass('disabled');
$('.step-tab').removeClass('clickable');
stus.forEach(function(value, step)
{
var disable = value == 1 ? '' : 'disabled';
$('#step' + (step + 1)).addClass(disable);
/* If step haven't active and disabled, means it hasn't be clicked to set active, but it's clickable now. */
if(!$('#step' + (step + 1)).hasClass('active') && !$('#step' + (step + 1)).hasClass('disabled')) $('#step' + (step + 1)).addClass('clickable')
});
}
function clearRadioChecked()
{
$("#dateGroupday").prop('checked', false);
$("#dateGroupdweek").prop('checked', false);
$("#dateGroupmonth").prop('checked', false);
$("#dateGroupyear").prop('checked', false);
}
function toggleRadioSelection(obj, value)
{
var radio1 = $("#dateGroupday");
var radio2 = $("#dateGroupweek");
var radio3 = $("#dateGroupmonth");
var radio4 = $("#dateGroupyear");
var clickedRadio = $('#' + $(obj).attr('id'));
if(clickedRadio.hasClass('checked'))
{
clickedRadio.prop('checked', false);
clickedRadio.removeClass('checked');
}
else
{
clearRadioChecked();
radio1.removeClass('checked');
radio2.removeClass('checked');
radio3.removeClass('checked');
radio4.removeClass('checked');
clickedRadio.prop('checked', true);
clickedRadio.addClass('checked');
}
var sendValue = clickedRadio.hasClass('checked') ? value : '';
pieChange(sendValue, 'dateGroup');
}