EnVisageOnline/Main/Source/EnVisage/Scripts/Plugins/ScenarioDependencyInformer.js

277 lines
8.5 KiB
JavaScript

/* ===========================================================
* ScenarioDependencyInformer.js v1.0.0
* ===========================================================
* Copyright 2017 Prevu
* ========================================================== */
(function ($) {
"use strict"; // jshint ;_;
/* ScenarioDependencyInformer CLASS DEFINITION */
var ScenarioDependencyInformer = function (element, options) {
this.init(element, options);
};
ScenarioDependencyInformer.prototype = {
constructor: ScenarioDependencyInformer,
init: function (element, options) {
var plugin = this;
this.options = options;
this.$container = $(element);
if (!this.options.projectId && !this.options.DependencyData) {
if (this.options.debug) {
console.log('ScenarioDependencyInformer: projectId not specified. Initialization finished');
}
return;
}
// Query data for widget
var promise = null;
if (typeof this.options.externalDataFunction === 'function') {
if (this.options.debug) {
console.log('ScenarioDependencyInformer: query data via external function');
}
promise = this.options.externalDataFunction(this.options.projectId);
}
else {
if (this.options.dataUrl) {
promise = this.queryDataFromUrl(this.options.dataUrl, this.options.projectId);
}
else {
if (this.options.debug) {
console.log('ScenarioDependencyInformer: No data source was specified, no data query was performed');
}
}
}
if (promise) {
promise.then(function (data) {
// data loaded
plugin.processIncomingData(data);
},
function (data, status, errMessage) {
// loading failed
var message = "Failed to load project dependencies info";
var html = '<div style="color: red;"><i>' + message + '</i></div>';
plugin.$container.html(html);
});
}
if (this.options.debug) {
console.log('ScenarioDependencyInformer: initialized');
}
if (this.options.initCallback && (typeof this.options.initCallback === 'function')) {
this.options.initCallback();
}
},
show: function () {
if (!this.$container)
return;
var duration = this.options.animation ? 400 : 0;
$(this.$container).show({ duration: duration });
},
hide: function () {
if (!this.$container)
return;
var duration = this.options.animation ? 400 : 0;
$(this.$container).hide({ duration: duration });
},
queryDataFromUrl: function(url, projectId) {
if (this.options.debug) {
console.log('ScenarioDependencyInformer: query data from server. Url: ' + url);
}
if (!url)
throw "ScenarioDependencyInformer: url for query data from server is empty";
if (!projectId)
throw "ScenarioDependencyInformer: project id to query data for, is empty";
var request = getAntiXSRFRequest(url);
request.method = 'GET';
request.data = {
id: projectId,
sessionKey: C_EMPTY_GUID,
};
var promise = $.ajax(request);
return promise;
},
processIncomingData: function (data) {
if (!data) {
if (this.options.debug) {
console.log('ScenarioDependencyInformer: incoming data is empty');
}
return;
}
if (!$.isArray(data)) {
if (this.options.debug) {
console.log('ScenarioDependencyInformer: incoming data has invalid format');
}
return;
}
// Indexing incoming data by datatype
var plugin = this;
var dataIndexed = [];
for (var index = 0; index < data.length; index++) {
var dataItem = data[index];
var dataType = dataItem && (dataItem.Type !== undefined) ? dataItem.Type : undefined;
if ($.isNumeric(dataType)) {
var dataTypeTyped = Number(dataType);
var indexedDataItem = {};
indexedDataItem.data = dataItem;
switch (dataTypeTyped) {
case 0:
indexedDataItem.message = this.options.finishConstraintMessageTemplate;
indexedDataItem.dateMs = dataItem.dtStartDate;
indexedDataItem.dateText = dataItem.StartDate;
indexedDataItem.scenarioDatePropName = "StartDate";
indexedDataItem.scenarioDatePrefix = "starts at";
indexedDataItem.tooltipHeader = "Dependency for:";
dataIndexed[String(dataTypeTyped)] = indexedDataItem;
break;
case 1:
indexedDataItem.message = this.options.startConstraintMessageTemplate;
indexedDataItem.dateMs = dataItem.dtEndDate;
indexedDataItem.dateText = dataItem.EndDate;
indexedDataItem.scenarioDatePropName = "EndDate";
indexedDataItem.scenarioDatePrefix = "ends at";
indexedDataItem.tooltipHeader = "Dependent on:";
dataIndexed[String(dataTypeTyped)] = indexedDataItem;
break;
}
}
}
var htmlRow;
var resultHtml = "";
for (var dataType = 1; dataType >= 0; dataType--) {
if (String(dataType) in dataIndexed) {
htmlRow = "";
var dataItem = dataIndexed[String(dataType)];
if (dataItem.message) {
var formattedMessage = dataItem.message.replace(/\{0\}/g, dataItem.dateText);
htmlRow = '<i>' + formattedMessage + '</i>';
}
if (this.options.displayIcons) {
if (htmlRow) {
htmlRow += '&nbsp;';
}
htmlRow += '<i class="fa fa-info-circle fa-fw"></i>';
if (this.options.tooltips) {
var tooltipContent = "";
if (dataItem.data.Items && $.isArray(dataItem.data.Items) && dataItem.data.Items.length) {
for (var pIndex = 0; pIndex < dataItem.data.Items.length; pIndex++) {
var projectInfo = dataItem.data.Items[pIndex];
var projectName = projectInfo.Level === 0 ? projectInfo.Name : '<i>' + projectInfo.Name + '</i>';
var projectTooltipContent = '<br>' + projectName;
if (projectInfo[dataItem.scenarioDatePropName]) {
var formattedProjectDate = DateTimeConverter.msFormatAsUtcString(projectInfo[dataItem.scenarioDatePropName]);
projectTooltipContent += projectInfo.Level === 0 ?
' (' + dataItem.scenarioDatePrefix + ' ' + formattedProjectDate + ')' :
' (<i>' + dataItem.scenarioDatePrefix + ' ' + formattedProjectDate + '</i>)';
}
tooltipContent += projectTooltipContent;
}
tooltipContent = dataItem.tooltipHeader + tooltipContent;
}
if (tooltipContent) {
htmlRow += ('<div class="tooltip-content">' + tooltipContent + '</div>');
}
}
}
resultHtml += ('<div' + (this.options.tooltips ? ' data-toggle="tooltip" data-placement="bottom">' : '>') + htmlRow + '</div>');
}
}
this.$container.html(resultHtml);
if (resultHtml && this.options.tooltips) {
var tooltipedDivs = this.$container.find('[data-toggle="tooltip"]');
$.each(tooltipedDivs, function (index, elem) {
$(elem).tooltip({
title: plugin.getTooltipContent,
html: true,
container: elem,
});
});
}
if (this.options.debug) {
console.log('ScenarioDependencyInformer: incoming data processed and published');
}
},
getTooltipContent: function (elem, data) {
var result = "No data available";
var tooltipContainter = $(this).find("div.tooltip-content");
if (tooltipContainter) {
var content = tooltipContainter.html();
if (content) {
result = content;
}
}
return result;
},
destroy: function () {
var e = $.Event('destroy');
this.$container.trigger(e);
if (e.isDefaultPrevented())
return;
if (this.options.debug) {
console.log('ScenarioDependencyInformer: destroyed');
}
},
};
/* ==================================================
* SCENARIO DEPENDENCY INFORMER PLUGIN DEFINITION
* ================================================== */
$.fn.scenarioDependencyInformer = function (option, args) {
return this.each(function () {
var $this = $(this),
data = $this.data('scenarioDependencyInformer'),
options = $.extend({}, $.fn.scenarioDependencyInformer.defaults, $this.data(), typeof option == 'object' && option);
if (!data) $this.data('scenarioDependencyInformer', (data = new ScenarioDependencyInformer(this, options)));
if (typeof option == 'string')
data[option].apply(data, [].concat(args));
});
};
$.fn.scenarioDependencyInformer.defaults = {
projectId: undefined,
dataUrl: undefined,
externalDataFunction: undefined,
startConstraintMessageTemplate: "Project must start after {0}",
finishConstraintMessageTemplate: "Project must end by {0}",
displayIcons: true,
tooltips: true,
animation: true,
initCallback: null,
debug: false
};
$.fn.scenarioDependencyInformer.Constructor = ScenarioDependencyInformer;
}(jQuery));