class HtmlTemplates {
constructor() {
}
/**
* Conditionally insert variable or html. Can be used in two ways.
* Either 1) pass html, and if so it will use the html if the field is true.
* Or, 2) if the field is a value (and truthy), and html is undefined/not provided, then return the field value.
* Instead of 2), you can also reference a variable directly, but risk outputting 'undefined' into the output html.
* @param field Either a data value evaluating as truthy, or a Boolean.
* @param html Optional html field to use if field is Boolean.
* @returns {string|*}
*/
outputif( field, html ) { // function to be called outputif, or printif
if ( field ) {
return html ? html : field;
} else {
return '';
}
}
/***
* Conditionally output options passed to the view controller constructor. Wrapper for outputif to handle multiple options.
* @param options
* @returns {string}
*/
outputOptions( options ) {
let output = [];
for ( var i = 0; i < options.length; i++ ) {
let result = this.outputif( options[i].option, options[i].html );
if ( result ) {
output.push( result );
}
}
return output.length > 0 ? '{ ' + output.join( ', ' ) + ' }' : '';
}
/**
* PascalCase to snake_case
*/
convertPascalCase2SnakeCase( string ) {
// all lowercase separated by _
return string.split( /(?=[A-Z][a-z])/ ).join( '_' ).toLowerCase(); // Fix: [A-Z][a-z] is needed to not split on all caps like ROEView. But this wont handle single caps at the end though.
}
/**
* PascalCase to kebab-case
*/
convertPascalCase2KebabCase( string ) {
// all lowercase separated by -
return string.split( /(?=[A-Z][a-z])/ ).join( '-' ).toLowerCase(); // Fix: [A-Z][a-z] is needed to not split on all caps like ROEView. But this wont handle single caps at the end though.
}
getTemplateTypeFromFilename( filename ) {
var type;
switch ( true ) { // known as 'overloaded switch'
// The following views will use the new templating logic. Order of these statements is important, first rule to match is used.
case this.checkViewClassForInlineHtmlbyFilename( filename ) !== false: // If success, it will return a String with the html.
// If a view class contains a static html_template value, then use this as an override instead of any specific type template matched by filename.
type = TemplateType.INLINE_HTML;
break;
case filename.indexOf( 'Sub' ) === 0: // Checks 'Sub' at start of filename. Must come before ReportView, otherwise it will conflict for SubSavedReportView.html
type = TemplateType.SUB_VIEW;
break;
case filename.indexOf( 'EditView.html' ) !== -1: // Must come before List Views, otherwise it will match for those due to both ending in View.html
type = TemplateType.EDIT_VIEW;
break;
case filename.indexOf( 'ReportView.html' ) !== -1 && filename.includes( 'Saved' ) === false: // Must come before List Views, and after 'Sub' otherwise reports will be loaded as list views. However make sure SavedReport is loaded as a list view.
type = TemplateType.REPORT_VIEW;
break;
case filename.indexOf( 'View.html' ) !== -1: // Must come more or less last, otherwise it will conflict with other files containing View.html, like EditView.html and ReportView.html
type = TemplateType.LIST_VIEW;
break;
default:
// If no template types are matched, treat as legacy html.
type = TemplateType.LEGACY_HTML; // This results in the relevant html file being loaded via the network. The new tab parsing logic may still run!
}
return type;
}
//Certain views do not fall under the rules of 'getTemplateTypeFromFilename()' and require special handling.
//This can be removed once we switch how views are loaded and can apply these rules directly on the view itself.
getTemplateOptionsFromViewId( view_id ) {
let options = {
view_id: view_id,
// Remember, sub_view_mode is not included here as not yet available here; view controller has not yet been loaded. Sub View Mode will be determined by template_type using the file name data. Will be applied as an option in HtmlTemplates.getGenericListViewHtml
};
//The following tax reports require an additional tab.
let reports_require_form_setup = ['RemittanceSummaryReport', 'T4SummaryReport', 'T4ASummaryReport', 'Form941Report', 'Form940Report', 'Form1099NecReport', 'FormW2Report', 'AffordableCareReport', 'USStateUnemploymentReport'];
if ( reports_require_form_setup.includes( view_id ) ) {
options.report_form_setup = true;
}
let sub_view_require_warning_message = [`UserDateTotal`];
if ( sub_view_require_warning_message.includes( view_id ) ) {
options.sub_view_warning_message = true;
}
//Issue #3158 - If these controllers are cached then side effects can occur.
//Such as permission denied alerts after opening login view on Invoice -> Client view.
let view_do_not_cache_controller = [`LoginUserWizard`, 'LoginUser', 'FindAvailableWizard', 'FindAvailable'];
if ( view_do_not_cache_controller.includes( view_id ) ) {
options.do_not_cache_controller = true;
}
//Audit log is both a TemplateType.INLINE_HTML and a TemplateType.SUB_VIEW under the current HTML2JS system.
//Once we switch to loading ViewControllers before HTML this special case can be removed.
if( view_id === 'Log' ) {
options.is_sub_view = true;
}
//Views extending BaseTreeViewController have slightly different requirments such as not show total number div.
//Once we switch to loading ViewControllers before the HTML this can be conditional by checking if the controller has tree_mode set to true.
let base_tree_views = ['JobGroup', 'JobItemGroup', 'PunchTagGroup', 'UserGroup', 'DocumentGroup', 'KPIGroup', 'ClientGroup', 'ProductGroup'];
if ( base_tree_views.includes( view_id ) ) {
options.base_tree_view = true;
}
return options;
}
checkViewClassForInlineHtmlbyFilename( filename ) {
// Lets see if this view class contains a html_template override, which should precede any type definitions.
let check_class = window[ filename.replace(/\.html$/,'') + 'Controller' ];
if( check_class !== undefined && typeof check_class.html_template === 'string' ) {
return check_class.html_template;
} else {
return false;
}
}
/**
*
* @param {TemplateType} type
* @param {Object} options
* @param {Function} [onResult]
*/
getTemplate( type, options = {}, onResult ) {
var html_template;
switch ( type ) {
case TemplateType.LIST_VIEW:
html_template = this.getGenericListViewHtml( options );
break;
case TemplateType.SUB_VIEW:
options.is_sub_view = true; // Force this to be true, as it's a sub_view after all. (This switch data is based off html filename request)
html_template = this.getGenericListViewHtml( options );
break;
case TemplateType.EDIT_VIEW:
// code block
html_template = HtmlTemplatesGlobal.genericEditView( options );
break;
case TemplateType.REPORT_VIEW:
// code block
html_template = HtmlTemplatesGlobal.genericReportEditView( options );
break;
case TemplateType.INLINE_HTML:
html_template = this.getViewScriptTagHtml( options ) + this.checkViewClassForInlineHtmlbyFilename( options.filename );
break;
default:
Debug.Error( 'HTML2JS: Error occured getting template. No matches for ' + options.view_id, 'HtmlTemplates.js', 'HtmlTemplates.js', 'getTemplate', 1 );
return -1;
}
// If callback onResult exists, call the function, else return html.
if ( onResult ) {
onResult( html_template ); // should we put this outside the switch? Depends how similar the other switch statements are.
} else {
return html_template;
}
}
/**
* This also handles subview script tags, if options.is_sub_view is true.
* @param options
* @returns {string}
*/
getGenericListViewHtml( options = {} ) {
Debug.Text( 'HTML2JS: Template retrieved for ' + options.view_id, 'HtmlTemplates.js', 'HtmlTemplates.js', 'getGenericListViewHtml', 10 );
// Prepend the `;
// Prepend the