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