{"version":3,"sources":["JFM/AJAXCommunications.js","JFM/Constants.js","JFM/Observable.js","JFM/Recaptcha,.js","JFM/Utility.js","JFM/Validations.js","JFM/WidgetForForms.js","JFMUI/Alert.js","JFMUI/Form.js","JFMUI/Icon.js","JFMUI/Loader.js","JFMUI/PopUp.js","JFMUI/UI_Constants.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACvPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACrDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACnOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACpIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACjiBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACvXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACvDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC3rBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AClHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC1LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC1QA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"JFM.js","sourcesContent":["/// \r\n/**\r\n * SpinLoader params\r\n * @typedef {Object} AJAX_OPTIONS\r\n * @property {string} method Http Request Method.\r\n * @property {string} url Target url.\r\n * @property {object} data Data to send.\r\n * @property {string} mode Fetch API mode {@link JFM_CONST.FETCHMODES}\r\n * @property {string} contentType Content Type {@link JFM_CONST.CONTENTTYPE}\r\n * @property {Function} FnSuccess Callback on successful communication.\r\n * @property {Function} FnError Callback on communication error.\r\n * @property {Function} FnBeforeSend Fn before establish communication.\r\n * @property {Function} FnComplete Callback on complete communication.\r\n */\r\n\r\n/**\r\n * Error response.\r\n * @typedef {Object} AJAX_ERROR\r\n * @property {String} message error message.\r\n * @property {String} stack stack trace.\r\n * @property {String} status status code.\r\n * @property {String} statusText statux text.\r\n */\r\n\r\n\r\n/**\r\n * Ajax response.\r\n * @typedef {Object} AJAX_RESPONSE\r\n * @property {String} data data response.\r\n * @property {String} isRedirected is redirected.\r\n * @property {String} contentType content type header.\r\n */\r\n\r\n/**\r\n * @class\r\n * AJAX communications.\r\n */\r\nclass AJAXCommunications_JS {\r\n /**\r\n * @param {AJAX_OPTIONS}\r\n */\r\n constructor(pOptions) {\r\n //default values\r\n this.Options = {\r\n method: \"get\",\r\n url: null,\r\n data: null,\r\n mode: JFM_CONST.FETCHMODES.SAMEORIGIN,\r\n contentType: null,\r\n FnSuccess: null,\r\n FnError: null,\r\n FnBeforeSend: null,\r\n FnComplete: null,\r\n };\r\n\r\n Object.assign(this.Options, pOptions);\r\n }\r\n /**\r\n * Send Data to a target url. The response is treated with Callbacks.\r\n */\r\n async AsyncFetch() {\r\n let objThis = this,\r\n isFinished = false,\r\n isRedirected = false,\r\n attempt = 0,\r\n contentType = '',\r\n fetchOptions = {\r\n method: this.Options.method,\r\n body: this.Options.data,\r\n redirect: \"follow\"\r\n };\r\n\r\n // Add the headers\r\n if (this.Options.contentType && this.Options.contentType.toLowerCase().indexOf(JFMUI.CONST.CONTENTTYPE.FILEFORM) == -1) {\r\n fetchOptions.headers = {\r\n \"Content-type\": this.Options.contentType,\r\n };\r\n }\r\n\r\n fetchOptions.headers = { ...fetchOptions.headers, \"X-Requested-With\": \"XMLHttpRequest\" };\r\n\r\n if (objThis.Options.mode == JFM_CONST.FETCHMODES.CORS) {\r\n fetchOptions.credentials = \"include\";\r\n }\r\n\r\n if (this.Options.FnBeforeSend) {\r\n this.Options.FnBeforeSend();\r\n }\r\n\r\n do {\r\n await fetch(this.Options.url, fetchOptions)\r\n .then((res) => {\r\n if (res.ok) {\r\n contentType = res.headers.get(\"Content-Type\");\r\n if (res.redirected) {\r\n isRedirected = true;\r\n return res.text();\r\n } else if (contentType.indexOf(JFM_CONST.CONTENTTYPE.JSON) !== -1) {\r\n return res.json();\r\n } else if (contentType.indexOf(JFM_CONST.CONTENTTYPE.TEXT) !== -1) {\r\n return res.text();\r\n } else if (contentType.indexOf(JFM_CONST.CONTENTTYPE.ZIP) !== -1) {\r\n return res.blob();\r\n } else if (contentType.indexOf(JFM_CONST.CONTENTTYPE.XEXCEL) !== -1) {\r\n return res.blob();\r\n } else {\r\n return res.text();\r\n }\r\n } else {\r\n return Promise.reject(res);\r\n }\r\n })\r\n .then((dataR) => {\r\n isFinished = true;\r\n if (this.Options.FnSuccess) {\r\n this.Options.FnSuccess(dataR, isRedirected,contentType);\r\n }\r\n })\r\n .catch((res) => {\r\n attempt++;\r\n if (attempt == JFM_CONST.ATTEMPTS.AJAX) {\r\n isFinished = true;\r\n res = !res ? {} : res;\r\n if (this.Options.FnError) {\r\n this.Options.FnError(res.statusText, res.status, res.message, res.stack);\r\n }\r\n }\r\n })\r\n .finally(() => {\r\n if (isFinished) {\r\n if (this.Options.FnComplete) {\r\n this.Options.FnComplete();\r\n }\r\n }\r\n });\r\n } while (!isFinished);\r\n }\r\n /**\r\n * Send Data to a target url in JSON format.\r\n * @param {String} pUrl Target url.\r\n * @param {String} pData Data to Send.\r\n * @param {String} pMethod Request method.\r\n * @param {String} pFetchMode Fetch mode.\r\n * @returns {Promise} Response from fetch API.\r\n */\r\n static async AsyncFetchJSON(pUrl ,pData, pMethod, pFetchMode = JFM_CONST.FETCHMODES.SAMEORIGIN) {\r\n let isFinished = false,\r\n isRedirected = false,\r\n isSuccessful = false,\r\n attempt = 0,\r\n contentType = '',\r\n /**\r\n * @type {AJAX_RESPONSE}\r\n */\r\n objAjaxResponse = null,\r\n /**\r\n * @type {AJAX_ERROR}\r\n */\r\n objAjaxError = null, \r\n fetchOptions = {\r\n method: pMethod,\r\n body: !!pData ? JSON.stringify(pData) : null,\r\n headers: {\r\n \"Content-type\": JFM_CONST.CONTENTTYPE.JSON,\r\n \"X-Requested-With\": \"XMLHttpRequest\"\r\n },\r\n redirect: \"follow\",\r\n };\r\n\r\n if (pFetchMode == JFM_CONST.FETCHMODES.CORS) {\r\n fetchOptions.credentials = \"include\";\r\n }\r\n\r\n\r\n // Request to the server\r\n do {\r\n await fetch(pUrl, fetchOptions)\r\n .then((res) => {\r\n if (res.ok) {\r\n contentType = res.headers.get(\"Content-Type\");\r\n if (res.redirected) {\r\n isRedirected = true;\r\n return res.text();\r\n } else if (contentType.indexOf(JFM_CONST.CONTENTTYPE.JSON) !== -1) {\r\n return res.json();\r\n } else if (contentType.indexOf(JFM_CONST.CONTENTTYPE.TEXT) !== -1) {\r\n return res.text();\r\n } else if (contentType.indexOf(JFM_CONST.CONTENTTYPE.ZIP) !== -1) {\r\n return res.blob();\r\n } else if (contentType.indexOf(JFM_CONST.CONTENTTYPE.XEXCEL) !== -1) {\r\n return res.blob();\r\n } else {\r\n return res.text();\r\n }\r\n } else {\r\n return Promise.reject(res);\r\n }\r\n })\r\n .then((res) => {\r\n isFinished = true;\r\n isSuccessful = true;\r\n objAjaxResponse =\r\n {\r\n data: res,\r\n isRedirected: isRedirected,\r\n contentType: contentType\r\n };\r\n })\r\n .catch((res) => {\r\n attempt++;\r\n if (attempt == JFM_CONST.ATTEMPTS.AJAX) {\r\n isFinished = true;\r\n isSuccessful = false;\r\n res = !res ? {} : res;\r\n objAjaxError =\r\n {\r\n message: res.message,\r\n stack: res.stack,\r\n status: res.status,\r\n statusText: res.statusText\r\n };\r\n }\r\n });\r\n } while (!isFinished);\r\n\r\n return isSuccessful ? Promise.resolve(objAjaxResponse) : Promise.reject(objAjaxError);\r\n }\r\n /**\r\n * Fetch Json with Post Request method.\r\n * @param {String} pUrl Target url.\r\n * @param {String} pData Data to Send.\r\n * @param {String} pFetchMode pFetchMode Fetch mode.\r\n * @returns {Promise} Response from fetch API.\r\n */\r\n static async AsyncPostJSON(pUrl, pData, pFetchMode = JFM_CONST.FETCHMODES.SAMEORIGIN) {\r\n return AJAXCommunications_JS.AsyncFetchJSON(pUrl, pData, 'Post', pFetchMode);\r\n }\r\n /**\r\n * Fetch Json with Post Request method.\r\n * @param {String} pUrl Target url.\r\n * @param {String} pData Data to Send.\r\n * @param {String} pFetchMode pFetchMode Fetch mode.\r\n * @returns {Promise} Response from fetch API.\r\n */\r\n static async AsyncGetJSON(pUrl, pData, pFetchMode = JFM_CONST.FETCHMODES.SAMEORIGIN) {\r\n return AJAXCommunications_JS.AsyncFetchJSON(pUrl, pData, 'Get', pFetchMode);\r\n }\r\n}","/**\r\n * July 2022\r\n * @file Constant values for the custom library (JFM).\r\n * @author Jorge Flores Miguel \r\n * @version 1.1.1.001\r\n */\r\n\r\n/**\r\n * Header content type for interchange data between AJAX communications.\r\n * @typedef {Object} CONTENTTYPE \r\n * @property {string} FORMDATA Form data to upload files.\r\n * @property {string} JSON Json data.\r\n * @property {string} XML Xml data.\r\n * @property {string} TEXT Html/text data.\r\n * @property {string} ZIP Zip file.\r\n * @property {string} XEXCEL Excel xml.\r\n */\r\n\r\n/**\r\n * Fetch API mode.\r\n * @typedef {Object} FETCHMODES\r\n * @property {string} SAMEORIGIN Ajax Requests for the same origin (Host).\r\n * @property {string} CORS Ajax Requests for cross site.\r\n */\r\n\r\n/**\r\n * Replace result mode after submit a form.\r\n * @typedef {Object} REPLACEMODE\r\n * @property {string} REPLACE Replace the entire Form tag with the new content\r\n * @property {string} INSERTAFTER Insert content after the Form tag\r\n * @property {string} INSERTBEFORE Insert content before the Form tag\r\n */\r\n\r\n/**\r\n * @typedef {Object} ATTEMPTS #Number of attempts for different situations.\r\n * @property {Number} AJAX #Number of attempts for AJAX communications.\r\n */\r\n\r\n/**\r\n * @typedef {Array} CONTAINER_COLLECTION valid container collection.\r\n */\r\n\r\n/**\r\n * Constant values for general porpuse\r\n * @typedef {Object} CONSTANTS\r\n * @property {CONTENTTYPE} CONTENTTYPE Header content type for interchange data between AJAX communications.\r\n * @property {FETCHMODES} FETCHMODES Fetch API mode.\r\n * @property {ICONS} ICONS Icon type for alert messages.\r\n * @property {REPLACEMODE} REPLACEMODE Replace result mode after submit a form.\r\n * @property {ATTEMPTS} ATTEMPTS #Number of attempts for different situations.\r\n * @property {CONTAINER_COLLECTION} CONTAINER_COLLECTION valid container collection.\r\n */\r\n\r\n/**\r\n * Several constant values for general purpose.\r\n * @type {CONSTANTS}\r\n * @constant\r\n */\r\nconst JFM_CONST = {\r\n CONTENTTYPE: {\r\n FORMDATA: 'multipart/form-data',\r\n JSON: 'application/json',\r\n XML: 'text/xml',\r\n TEXT: 'text/html',\r\n ZIP: 'application/zip',\r\n XEXCEL: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'\r\n },\r\n FETCHMODES: {\r\n SAMEORIGIN: 'same-origin',\r\n CORS: 'cors'\r\n },\r\n REPLACEMODE: {\r\n REPLACE: 'REPLACE',\r\n INSERTAFTER: 'AFTER',\r\n INSERTBEFORE: 'BEFORE'\r\n },\r\n ATTEMPTS: {\r\n AJAX: 3\r\n },\r\n CONTAINER_COLLECTION: [\r\n 'DIV',\r\n 'FORM',\r\n 'SECTION',\r\n 'TABLE',\r\n 'FIELDSET',\r\n 'ASIDE',\r\n 'FOOTER',\r\n 'HEADER',\r\n 'NAV',\r\n 'ARTICLE'\r\n ]\r\n};","/**\r\n * Subscribe observers and listen the messages from the Observable.\r\n * @class\r\n * */\r\n class Observable {\r\n /**\r\n * @constructor\r\n * */\r\n constructor() {\r\n /** Saves the obsevers function according to a category.\r\n @type {Array} \r\n @private\r\n */\r\n this.observers = [];\r\n }\r\n /**\r\n * Register Observers.\r\n * @param {String} pCategory Message Category.\r\n * @param {Function} pFunc Action to execute.\r\n */\r\n subscribe(pCategory, pFunc) {\r\n this.observers.push({\r\n Category: pCategory,\r\n Func: pFunc\r\n });\r\n }\r\n /**\r\n * Unregister Observers.\r\n * @param {String} pCategory Message Category.\r\n * @param {Function} pFunc Action to execute.\r\n */\r\n unsubscribe(pCategory, pFunc) {\r\n this.observers = this.observers.filter(obs => !(obs.Category === pCategory && Func === pFunc));\r\n }\r\n /**\r\n * Unregister all Observers from a specific Category.\r\n * @param {String} pCategory Message Category.\r\n */\r\n unsubscribeAll(pCategory) {\r\n this.observers = this.observers.filter(obs => obs.Category !== pCategory);\r\n }\r\n /**\r\n * Raise events from a specific Category.\r\n * @param {String} pCategory Message Category..\r\n * @param {any} pArg Function arguments.\r\n */\r\n notify(pCategory, pArg) {\r\n this.observers.forEach(obs => {\r\n if (obs.Category == pCategory) {\r\n obs.Func(pArg);\r\n }\r\n });\r\n }\r\n}","/**\r\n * GrecaptchaV2_JS options.\r\n * @typedef {Object} GRECAPTCHA_OPTIONS\r\n * @property {String} selector HTML parent container.\r\n * @property {String} siteKey recaptcha render Id.\r\n * @property {String} theme Color Theme of thw widget: ('dark','light').\r\n * @property {String} size The size of the widget ('compact','normal','invisible').\r\n * @property {Number} tabindex The tabindex of the widget and challenge.\r\n * @property {Function} callback The name of your callback function, executed when the user submits a successful response. The g-recaptcha-response token is passed to your callback.\r\n * @property {Function} expiredCallback The name of your callback function, executed when the reCAPTCHA response expires and the user needs to re-verify.\r\n * @property {Function} errorCallback The name of your callback function, executed when reCAPTCHA encounters an error (usually network connectivity) and cannot continue until connectivity is restored. \r\n * @property {String} badge (Invisible only) position of the recaptcha. ('bottomright','bottomleft','inline').\r\n * @property {Boolean} isolated (Invisible only) If true, this reCAPTCHA instance will be part of a separate ID space.\r\n * @property {Boolean} isInvisible True for an invisible recaptcha.\r\n * @property {HTMLInputElement} inputForm Input HTML Element that receives token value after a successful response.\r\n */\r\n\r\n/**\r\n * Google recaptcha V2 object.\r\n */\r\nclass GrecaptchaV2_JS {\r\n /**\r\n * @param {Object} pGrecaptcha grecaptcha object.\r\n * @param {GRECAPTCHA_OPTIONS} pOptions\r\n * @constructor\r\n */\r\n constructor(pGrecaptcha, pOptions) {\r\n\r\n if (!pGrecaptcha) {\r\n throw new Error('Missing grecaptcha object.');\r\n }\r\n /**\r\n * @type {GRECAPTCHA_OPTIONS} \r\n */\r\n let objOptions = {\r\n selector: null,\r\n siteKey: null,\r\n theme: null,\r\n size: null,\r\n tabindex: null,\r\n callback: null,\r\n expiredCallback: null,\r\n errorCallback: null,\r\n badge: null,\r\n isolated: false,\r\n isInvisible: false,\r\n inputForm: null\r\n }\r\n\r\n Object.assign(objOptions, pOptions);\r\n\r\n if (!objOptions.selector || !objOptions.siteKey) {\r\n throw new Error('Missing params: selector or sitekey for Google grecaptcha');\r\n }\r\n\r\n /**\r\n * Flag for invisble recaptcha.\r\n * @type {Boolean}\r\n * @public\r\n */\r\n this.IsInvisible = objOptions.isInvisible;\r\n /**\r\n * Html input that stores recaptcha value.\r\n * @type {HTMLInputElement} \r\n * @public\r\n */\r\n this.InputForm = objOptions.inputForm;\r\n /**\r\n * grecaptcha object.\r\n * @type {Object} \r\n * @public\r\n */\r\n this.Grecaptcha = pGrecaptcha;\r\n /**\r\n * Widget Id.\r\n * @type {Number} \r\n * @public\r\n */\r\n this.widget_id = null;\r\n /**\r\n * Call back function on recaptcha response.\r\n * @type {Function} \r\n * @public\r\n */\r\n this.FnCallback = objOptions.callback;\r\n /**\r\n * Call back function on expired recaptcha.\r\n * @type {Function} \r\n * @public\r\n */\r\n this.FnexpiredCallback = objOptions.expiredCallback;\r\n /**\r\n * Recaptcha value.\r\n * @type {String} \r\n * @public\r\n */\r\n this.RecaptchaValue = '';\r\n\r\n // Initialize recaptcha.\r\n this.init(objOptions);\r\n }\r\n // #region PUBLIC PROPERTIES\r\n /**\r\n * setter Recaptcha value.\r\n * @type {string}\r\n * @public \r\n */\r\n set RecaptchaValue(pValue) {\r\n this._RecaptchaValue = pValue;\r\n // set input HTML value equal to RecaptchaValue\r\n if (this.InputForm) {\r\n this.InputForm.value = pValue;\r\n this.InputForm.classList.remove('is-invalid');\r\n this.InputForm.classList.add('is-valid');\r\n let errLabel = this.InputForm.parentElement.querySelector(`.invalid-feedback[data-valmsg-for=\"${this.InputForm.name}\"]`);\r\n !!errLabel && (errLabel.innerHTML = '');\r\n }\r\n }\r\n /**\r\n * getter current recaptcha value.\r\n * @type {string} \r\n * @public\r\n */\r\n get RecaptchaValue() {\r\n return this._RecaptchaValue;\r\n }\r\n // #endregion\r\n /**\r\n * Initialize method.\r\n * @param {GRECAPTCHA_OPTIONS} pObjOptions GrecaptchaV2_JS options.\r\n * @private\r\n */\r\n init(pObjOptions) {\r\n if (this.IsInvisible) {\r\n this.widget_id = this.Grecaptcha.render(pObjOptions.selector, {\r\n 'sitekey': pObjOptions.siteKey,\r\n 'badge': !!pObjOptions.badge ? pObjOptions.badge : 'bottomright',\r\n 'size': 'invisible',\r\n 'tabindex': !!pObjOptions.tabindex ? pObjOptions.tabindex : 0,\r\n 'callback': this.responseCallback.bind(this),\r\n 'expired-callback': this.expiredCallBack.bind(this),\r\n 'error-Recaptchacallback': !!pObjOptions.errorCallback ? pObjOptions.errorCallback : null,\r\n 'isolated': pObjOptions.isolated\r\n });\r\n } else {\r\n this.widget_id = this.Grecaptcha.render(pObjOptions.selector, {\r\n 'sitekey': pObjOptions.siteKey,\r\n 'theme': !!pObjOptions.theme ? pObjOptions.theme : 'light',\r\n 'size': !!pObjOptions.size ? pObjOptions.size : 'normal',\r\n 'tabindex': !!pObjOptions.tabindex ? pObjOptions.tabindex : 0,\r\n 'callback': this.responseCallback.bind(this),\r\n 'expired-callback': this.expiredCallBack.bind(this),\r\n 'error-callback': !!pObjOptions.errorCallback ? pObjOptions.errorCallback : null\r\n });\r\n }\r\n }\r\n // #region PUBLIC METHODS\r\n /**\r\n * Update RecaptchaValue and call FnCallback property.\r\n * @param {String} ptoken \r\n */\r\n responseCallback(ptoken) {\r\n this.RecaptchaValue = ptoken;\r\n if (!!this.FnCallback) {\r\n this.FnCallback(ptoken);\r\n }\r\n }\r\n /**\r\n * Reset Recaptcha value and call FnexpiredCallback property,\r\n */\r\n expiredCallBack() {\r\n this.reset();\r\n this.InputForm.value = '';\r\n this.InputForm.classList.remove('is-valid');\r\n this.InputForm.classList.add('is-invalid');\r\n if (!!this.FnexpiredCallback) {\r\n this.FnexpiredCallback();\r\n }\r\n }\r\n /**\r\n * Compute Recaptcha response value.\r\n * @returns {String} Recaptcha value\r\n */\r\n getResponse() {\r\n if (this.IsInvisible) {\r\n this.Grecaptcha.execute(this.widget_id);\r\n } else {\r\n this.RecaptchaValue = this.Grecaptcha.getResponse(this.widget_id);\r\n }\r\n return this.RecaptchaValue;\r\n }\r\n /**\r\n * Reset Recaptcha.\r\n */\r\n reset() {\r\n this.Grecaptcha.reset(this.widget_id);\r\n this.RecaptchaValue = '';\r\n }\r\n /**\r\n * Evaluate validity of recaptcha.\r\n * @returns {boolean} true for valid recaptcha.\r\n */\r\n isValid() {\r\n return this.RecaptchaValue.length > 0;\r\n }\r\n // #endregion\r\n //#region STATIC METHODS\r\n /**\r\n * @description Add Google Recaptcha library to the DOM.\r\n * @param {Function} pFnOnload - A callback that Google executes after Load all of the resources.\r\n * @param {Boolean} pIsAsync - True for script tag async attribute\r\n * @param {Boolean} pIsDefer - True for script tag defer attribute\r\n */\r\n static addRecaptchaLibrary(pFnOnload, pIsAsync = false, pIsDefer = false) {\r\n let objHTMLScript = document.createElement('SCRIPT');\r\n objHTMLScript.async = pIsAsync;\r\n objHTMLScript.defer = pIsDefer;\r\n\r\n if (!!pFnOnload && typeof pFnOnload == 'function') {\r\n objHTMLScript.src = `https://www.google.com/recaptcha/api.js?onload=${pFnOnload.name}&render=explicit`;\r\n } else {\r\n objHTMLScript.src = 'https://www.google.com/recaptcha/api.js';\r\n }\r\n\r\n document.getElementsByTagName('head')[0].appendChild(objHTMLScript);\r\n }\r\n}\r\n","/**\r\n * Utility DOM custom methods.\r\n */\r\nclass DOM_Utility {\r\n /**\r\n * Create Document Fragment with inner HTML template.\r\n * @param {String} pTemplate Text HTML Template.\r\n * @returns {HTMLAllCollection} \r\n */\r\n static createHTMLFromString(pTemplate) {\r\n let objHTMLDiv = document.createElement('DIV'),\r\n objHTML = null;\r\n objHTMLDiv.insertAdjacentHTML('afterbegin', pTemplate);\r\n if (!!objHTMLDiv.firstElementChild) {\r\n objHTML = objHTMLDiv.firstElementChild;\r\n }\r\n return objHTML;\r\n }\r\n /**\r\n * decode HTML special characters to string\r\n * @param {String} pStr Encoded HTML string\r\n * @returns {String} Decoded HTML string\r\n */\r\n static decodeHTMLEntities(pStr) {\r\n if (pStr && typeof pStr === 'string') {\r\n // strip script/html tags\r\n pStr = pStr.replace(/]*>([\\S\\s]*?)<\\/script>/gmi, '');\r\n pStr = pStr.replace(/<\\/?\\w(?:[^\"'>]|\"[^\"]*\"|'[^']*')*>/gmi, '');\r\n const HTMLDIV = document.createElement('DIV');\r\n HTMLDIV.innerHTML = pStr;\r\n pStr = HTMLDIV.textContent;\r\n HTMLDIV.remove();\r\n }\r\n return pStr;\r\n }\r\n /**\r\n * Encode invalid characters\r\n * @param {String} pStr Original string. \r\n * @returns {String} Sanitized string.\r\n */\r\n static encodeHTMLEntities(pStr) {\r\n return pStr\r\n .replace(/&/g, '&')\r\n .replace(//g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''')\r\n .replace(/\\//g, '/')\r\n .replace(/\\s/g, ' ')\r\n .trim();\r\n }\r\n}\r\n/**\r\n * several utilities\r\n */\r\nclass Utility {\r\n /**\r\n * It combines n functions. It’s a pipe flowing left-to-right, calling each function with the output of the last one.\r\n * @param {...Function} fns collection of functions\r\n * @returns {any} depends the last Fn\r\n */\r\n static pipe(...fns) {\r\n return (x) => fns.reduce((prevValue, currentFn) => currentFn(prevValue), x);\r\n }\r\n /**\r\n * It combines n functions. It’s a pipe flowing right-to-left, calling each function with the output of the last one.\r\n * @param {...Function} fns collection of functions\r\n * @returns {any} depends the last Fn\r\n */\r\n static compose(...fns) {\r\n return (x) => fns.reduceRight((prevValue, currentFn) => currentFn(prevValue), x);\r\n }\r\n /**\r\n * rigt inner join two objects\r\n * @param {Object} src source object\r\n * @param {Object} tgt target object\r\n * @returns {Object} tgt updated target\r\n */\r\n static assign(src, tgt) {\r\n const primitiveType = ['string', 'number', 'boolean'];\r\n\r\n //Assign non valid arrays or objects\r\n if (primitiveType.some(t => typeof src === t) || tgt === null || tgt === undefined || src === null || src === undefined || typeof src !== typeof tgt) {\r\n tgt = src;\r\n return tgt;\r\n }\r\n\r\n //handle arrays\r\n if (Array.isArray(src) && Array.isArray(tgt)) {\r\n src.forEach((ele, ix) => {\r\n if (primitiveType.some(t => typeof ele === t)) {\r\n tgt[ix] = ele\r\n } else {\r\n tgt[ix] = Utility.assign(ele, tgt[ix]);\r\n }\r\n });\r\n }\r\n\r\n //handle objects\r\n if (typeof src === 'object') {\r\n for (const key in src) {\r\n if (tgt.hasOwnProperty(key)) {\r\n //assign value\r\n if (primitiveType.some(t => typeof src[key] === t)) {\r\n tgt[key] = src[key];\r\n } else if (Array.isArray(tgt[key]) && Array.isArray(src[key])) {\r\n //decompose array\r\n src[key].forEach((ele, ix) => {\r\n if (primitiveType.some(t => typeof ele === t)) {\r\n tgt[key][ix] = ele\r\n } else {\r\n tgt[key][ix] = Utility.assign(ele, tgt[key][ix]);\r\n }\r\n });\r\n } else {\r\n //decompose object\r\n tgt[key] = Utility.assign(src[key], tgt[key]);\r\n }\r\n } else {\r\n tgt[key] = src[key];\r\n }\r\n }\r\n }\r\n return tgt;\r\n }\r\n}\r\n//TODO: create own sanitizer\r\n/**\r\n * Sanitizer utility\r\n */\r\nclass Sanitizer {\r\n\r\n}","/**\r\n * Response for ValidationMethods_JS.\r\n * @typedef {Object} VAL_METHOD_RESPONSE\r\n * @property {boolean} IsValid true for valid HTMLInputElement\r\n * @property {String} ErrorMessage Error Message.\r\n */\r\n\r\n/**\r\n * Response for ValidationMethods_JS.\r\n * @typedef {Object} VALIDATION_RESPONSE\r\n * @property {boolean} IsValid True for valid collection of fields.\r\n * @property {Map} Errors All Error Messages (key = HTMLInputElement, value = ErrorMessage).\r\n */\r\n\r\n/**\r\n * Custom Regular Expresion for a specific domain.\r\n */\r\nclass RegExp_JS {\r\n /**\r\n * Email Expression.\r\n * @type {RegExp}\r\n * @public\r\n */\r\n static get EMAIL() {\r\n return /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\r\n }\r\n /**\r\n * Name Expression.\r\n * @type {RegExp}\r\n * @public\r\n */\r\n static get NAME() {\r\n return /^([a-zA-ZàáâäãåąčćęèéêëėįìíîïłńòóôöõøùúûüųūÿýżźñçčšžÀÁÂÄÃÅĄĆČĖĘÈÉÊËÌÍÎÏĮŁŃÒÓÔÖÕØÙÚÛÜŲŪŸÝŻŹÑßÇŒÆČŠŽ∂ð'.-]+\\s*)+$/;\r\n }\r\n /**\r\n * Name Expression.\r\n * @type {RegExp}\r\n * @public\r\n */\r\n static get PASSWORD() {\r\n return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&#])[A-Za-z\\d@$!%*?&#]{8,}$/;\r\n }\r\n}\r\n/**\r\n * Several validation methods.\r\n * @class\r\n */\r\nclass ValidationMethods_JS {\r\n /**\r\n * Test for required field.\r\n * @param {HTMLInputElement} pHTMLInput a Form field\r\n * @returns {VAL_METHOD_RESPONSE} HTMLInputElement Validation Response.\r\n */\r\n static requiredFieldEval(pHTMLInput) {\r\n // dataset values:\r\n // data-val-required Error message\r\n let strErrorMessage = '',\r\n isValid = true;\r\n\r\n if (typeof pHTMLInput.dataset.valRequired !== 'undefined') {\r\n strErrorMessage = pHTMLInput.dataset.valRequired;\r\n\r\n switch (pHTMLInput.type.toLowerCase()) {\r\n case 'checkbox':\r\n !pHTMLInput.checked && (isValid = false);\r\n break;\r\n case 'radio':\r\n if (!pHTMLInput.name) {\r\n isValid = false;\r\n strErrorMessage = 'Missing name attribute on radio input.';\r\n } else {\r\n !document.querySelector(`[name=\"${pHTMLInput.name}\"]:checked`) && (isValid = false);\r\n }\r\n break;\r\n case \"select-one\":\r\n case \"select-multiple\":\r\n (pHTMLInput.options.length > 0) && (pHTMLInput.options[0].selected) && (isValid = false);\r\n break;\r\n case \"file\":\r\n (pHTMLInput.files.length == 0) && (isValid = false);\r\n break;\r\n default:\r\n (!pHTMLInput.value) && (isValid = false);\r\n break;\r\n }\r\n }\r\n /**\r\n * @type {VAL_METHOD_RESPONSE}\r\n */\r\n return {\r\n IsValid: isValid,\r\n ErrorMessage: isValid ? '' : (!!strErrorMessage ? strErrorMessage : 'Required Input Value.')\r\n };\r\n }\r\n // TODO: falta validar este método\r\n /**\r\n * Test a regular expression on HTMLInputElement Value.\r\n * @param {HTMLInputElement} pHTMLInput a Form field\r\n * @returns {VAL_METHOD_RESPONSE} HTMLInputElement Validation Response.\r\n */\r\n static regularExpressionEval(pHTMLInput) {\r\n // dataset values:\r\n // data-val-regex-pattern Regular Expression.\r\n // data-val-regex Error message\r\n let strErrorMessage = '',\r\n /**\r\n * @type {VAL_METHOD_RESPONSE}\r\n */\r\n objResponse = {\r\n IsValid: true,\r\n ErrorMessage: ''\r\n };\r\n if (typeof pHTMLInput.dataset.valRegexPattern !== 'undefined') {\r\n strErrorMessage = pHTMLInput.dataset.valRegex;\r\n !!pHTMLInput.dataset.valRegexPattern && !(new RegExp(pHTMLInput.dataset.valRegexPattern).test(pHTMLInput.value)) && (objResponse = {\r\n IsValid: false,\r\n ErrorMessage: !!strErrorMessage ? strErrorMessage : 'Invalid Input Value.'\r\n });\r\n }\r\n return objResponse;\r\n }\r\n // TODO: falta validar este método\r\n /**\r\n * Test for a \"n\" max length value.\r\n * @param {HTMLInputElement} pHTMLInput a Form field\r\n * @returns {VAL_METHOD_RESPONSE} HTMLInputElement Validation Response.\r\n */\r\n static lengthMaxEval(pHTMLInput) {\r\n // dataset values:\r\n // data-val-length-max Max number value.\r\n // data-val-length-max-err Error message\r\n let strValLengthMax = pHTMLInput.dataset.valLengthMax,\r\n strErrorMessage = pHTMLInput.dataset.valLengthMaxErr,\r\n /**\r\n * @type {VAL_METHOD_RESPONSE}\r\n */\r\n objResponse = {\r\n IsValid: true,\r\n ErrorMessage: ''\r\n };\r\n\r\n !!strValLengthMax && (pHTMLInput.value.length > parseInt(strValLengthMax)) && (objResponse = {\r\n IsValid: false,\r\n ErrorMessage: !!strErrorMessage ? strErrorMessage : 'Invalid Input Value.'\r\n });\r\n\r\n return objResponse;\r\n }\r\n // TODO: falta validar este método\r\n /**\r\n * Test for a \"n\" min length value.\r\n * @param {HTMLInputElement} pHTMLInput a Form field\r\n * @returns {VAL_METHOD_RESPONSE} HTMLInputElement Validation Response.\r\n */\r\n static lengthMinEval(pHTMLInput) {\r\n // dataset values:\r\n // data-val-length-min Min number value.\r\n // data-val-length-min-err Error message\r\n let strValLengthMin = pHTMLInput.dataset.valLengthMin,\r\n strErrorMessage = pHTMLInput.dataset.valLengthMinErr,\r\n /**\r\n * @type {VAL_METHOD_RESPONSE}\r\n */\r\n objResponse = {\r\n IsValid: true,\r\n ErrorMessage: ''\r\n };\r\n\r\n !!strValLengthMin && (pHTMLInput.value.length < parseInt(strValLengthMin)) && (objResponse = {\r\n IsValid: false,\r\n ErrorMessage: !!strErrorMessage ? strErrorMessage : 'Invalid Input Value.'\r\n });\r\n\r\n return objResponse;\r\n }\r\n /**\r\n * Test for a default class validation @see {@link RegExp_JS}.\r\n * @param {HTMLInputElement} pHTMLInput Form field.\r\n * @returns {VAL_METHOD_RESPONSE} HTMLInputElement Validation Response.\r\n */\r\n static expressionEval(pHTMLInput) {\r\n // dataset values:\r\n // data-val-expression-class Default class for regular expression.\r\n // data-val-expression Error message\r\n let strErrorMessage = pHTMLInput.dataset.valExpression,\r\n strProperty = pHTMLInput.dataset.valExpressionClass,\r\n\r\n /**\r\n * @type {VAL_METHOD_RESPONSE}\r\n */\r\n objResponse = {\r\n IsValid: true,\r\n ErrorMessage: ''\r\n };\r\n\r\n (!!strProperty) && (RegExp_JS.hasOwnProperty(strProperty.toLocaleUpperCase())) && !(RegExp_JS[strProperty.toLocaleUpperCase()].test(pHTMLInput.value)) && (objResponse = {\r\n IsValid: false,\r\n ErrorMessage: !!strErrorMessage ? strErrorMessage : 'Invalid Input Value.'\r\n });\r\n return objResponse;\r\n }\r\n /**\r\n * Test for a valid date\r\n * @param {HTMLInputElement} pHTMLInput Form field.\r\n * @returns {VAL_METHOD_RESPONSE} HTMLInputElement Validation Response.\r\n */\r\n static dateISO8601Eval(pHTMLInput) {\r\n // dataset values:\r\n // data-val-date Error message\r\n let strErrorMessage = '',\r\n objDaysByMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],\r\n strDateParts = '',\r\n intYear = 0,\r\n intMonth = 0,\r\n intDay = 0,\r\n isValidDate = true,\r\n\r\n /**\r\n * @type {VAL_METHOD_RESPONSE}\r\n */\r\n objResponse = {\r\n IsValid: true,\r\n ErrorMessage: ''\r\n };\r\n\r\n if (typeof pHTMLInput.dataset.valDate !== 'undefined') {\r\n strErrorMessage = pHTMLInput.dataset.valDate;\r\n\r\n if (!!pHTMLInput.value) {\r\n strDateParts = pHTMLInput.value.split('-');\r\n if (strDateParts.length > 2) {\r\n intYear = parseInt(strDateParts[0]);\r\n intMonth = parseInt(strDateParts[1]);\r\n intDay = parseInt(strDateParts[2]);\r\n\r\n if (isNaN(intYear) || isNaN(intMonth) || isNaN(intDay)) {\r\n isValidDate = false;\r\n } else if (intYear < 1 || intYear > 9999) {\r\n isValidDate = false;\r\n } else if (intMonth < 1 || intMonth > 12) {\r\n isValidDate = false;\r\n } else if (intMonth == 2 && (intYear % 4 == 0) && ((intYear % 100 != 0) || (intYear % 400 == 0))) { //leap year validation.\r\n isValidDate = !(intDay < 1 || intDay > 29);\r\n } else if (intDay < 1 || intDay > objDaysByMonth[intMonth - 1]) {\r\n isValidDate = false;\r\n }\r\n } else {\r\n isValidDate = false;\r\n }\r\n } else {\r\n isValidDate = false;\r\n }\r\n }\r\n\r\n return objResponse = {\r\n IsValid: isValidDate,\r\n ErrorMessage: isValidDate ? '' : (!!strErrorMessage ? strErrorMessage : 'Invalid Input Value.')\r\n };\r\n }\r\n /**\r\n * Compare two Inputs for equality.\r\n * @param {HTMLInputElement} pHTMLInput Form field.\r\n * @returns {VAL_METHOD_RESPONSE} HTMLInputElement Validation Response.\r\n */\r\n static equalToOtherfieldEval(pHTMLInput) {\r\n // dataset values:\r\n // data-val-Equalto Selector for the other field.\r\n // data-val-Equal Error message\r\n let strErrorMessage = '',\r\n objHtmlInputElement = null,\r\n /**\r\n * @type {VAL_METHOD_RESPONSE}\r\n */\r\n objResponse = {\r\n IsValid: true,\r\n ErrorMessage: ''\r\n };\r\n\r\n if (pHTMLInput.dataset.valEqualto !== undefined) {\r\n strErrorMessage = pHTMLInput.dataset.valEqual;\r\n objHtmlInputElement = document.body.querySelector(pHTMLInput.dataset.valEqualto);\r\n !!objHtmlInputElement && (objHtmlInputElement.value != pHTMLInput.value) && (objResponse = {\r\n IsValid: false,\r\n ErrorMessage: !!strErrorMessage ? strErrorMessage : `Input Value not equal to ${pHTMLInput.dataset.valEqualto}`\r\n });\r\n }\r\n return objResponse;\r\n }\r\n // TODO: falta validar este método\r\n /**\r\n * Test for type of file.\r\n * @param {HTMLInputElement} pHTMLInput Form field.\r\n * @returns {VAL_METHOD_RESPONSE} HTMLInputElement Validation Response.\r\n */\r\n static typeOfFileEval(pHTMLInput) {\r\n // dataset values:\r\n // data-val-type-of-file-mime Mime Type file.\r\n // data-val-type-of-file Error message\r\n\r\n let strErrorMessage = '',\r\n strValTypeOfFileMime = '',\r\n isValid = false,\r\n /**\r\n * @type {VAL_METHOD_RESPONSE}\r\n */\r\n objResponse = {\r\n IsValid: true,\r\n ErrorMessage: ''\r\n };\r\n\r\n if (pHTMLInput.dataset.valTypeOfFileMime !== undefined) {\r\n strErrorMessage = pHTMLInput.dataset.valTypeOfFile;\r\n strValTypeOfFileMime = pHTMLInput.dataset.valTypeOfFileMime;\r\n\r\n if (pHTMLInput.type == \"file\" && pHTMLInput.files.length > 0) {\r\n isValid = [].slice.call(pHTMLInput.files, 0).every(file => strValTypeOfFileMime.split(',').some(mime => mime.toLocaleUpperCase() == file.type.toLocaleUpperCase()));\r\n objResponse = {\r\n IsValid: isValid,\r\n ErrorMessage: isValid ? '' : (!!strErrorMessage ? strErrorMessage : `Invalid Input file(s) format`)\r\n }\r\n }\r\n }\r\n\r\n return objResponse;\r\n }\r\n // TODO: falta validar este método\r\n /**\r\n * Test for size of File.\r\n * @param {HTMLInputElement} pHTMLInput Form field.\r\n * @returns {VAL_METHOD_RESPONSE} HTMLInputElement Validation Response.\r\n */\r\n static sizeOfFileEval(pHTMLInput) {\r\n // dataset values:\r\n // data-val-size-of-file-bytes Size in bytes.\r\n // data-val-size-of-file Error message\r\n let strErrorMessage = '',\r\n totalOfBytes = 0,\r\n /**\r\n * @type {VAL_METHOD_RESPONSE}\r\n */\r\n objResponse = {\r\n IsValid: true,\r\n ErrorMessage: ''\r\n };\r\n\r\n if (typeof pHTMLInput.dataset.valSizeOfFileBytes !== 'undefined') {\r\n strErrorMessage = pHTMLInput.dataset.valSizeOfFile;\r\n if (pHTMLInput.type == \"file\" && pHTMLInput.files.length > 0) {\r\n //Total of bytes for whole files > valid size bytes\r\n totalOfBytes = [].slice.call(pHTMLInput.files, 0).reduce((pV, file) => (pV + file.size), 0);\r\n\r\n (totalOfBytes > Number(pHTMLInput.dataset.valSizeOfFileBytes)) && (objResponse = {\r\n IsValid: false,\r\n ErrorMessage: !!strErrorMessage ? strErrorMessage.replace('{0}', totalOfBytes) : `Invalid Input file(s) size of ${totalOfBytes}.`\r\n });\r\n }\r\n }\r\n return objResponse;\r\n }\r\n}\r\n/**\r\n * Validation Form Helper.\r\n * @class\r\n */\r\nclass ValidationForm_JS {\r\n /**\r\n * @param {object} pContainer Parent of HTML inputs.\r\n * @param {Array.} pFields form fields.\r\n * @param {string} pEvents A list of events separated by space that raise input validation.\r\n * @param {Function} pFnErrorField Callback Function when the field has an error.\r\n * @param {Function} pFnValidField CallBack Function where the field is valid.\r\n * @param {Array} pValidationMethods Array of validation functions.\r\n * @constructor\r\n */\r\n constructor(pContainer, pFields, pEvents, pFnErrorField, pFnValidField, pValidationMethods = []) {\r\n if (!!pContainer && JFM_CONST.CONTAINER_COLLECTION.some(c => c === pContainer.tagName)) {\r\n /**\r\n * Form fields.\r\n * @type {Array.}\r\n */\r\n this.Fields = pFields;\r\n if (!this.Fields) throw new Error(`Invalid container fields: zero inputs to validate.`);\r\n /**\r\n * Form container\r\n * @type {HTMLFormElement|HTMLDivElement}\r\n */\r\n this.Container = pContainer;\r\n /**\r\n * raise a function for each incorrect field.\r\n * @type {Function}\r\n */\r\n this.FnErrorField = (typeof pFnErrorField === 'function') ? pFnErrorField : null;\r\n /**\r\n * raise a function for each correct field.\r\n * @type {Function}\r\n */\r\n this.FnValidField = (typeof pFnValidField === 'function') ? pFnValidField : null;\r\n // pValidationMethods must be a collection of functions\r\n if (Array.isArray(pValidationMethods) && pValidationMethods.length > 0 && pValidationMethods.every(f => typeof f === 'function')) {\r\n /**\r\n * validation methos for each field.\r\n * @type {Array.}\r\n */\r\n this.ValidationMethods = pValidationMethods;\r\n } else {\r\n this.ValidationMethods = null;\r\n }\r\n /**\r\n * collection of events to raise separated by spaces.\r\n * @type {String}\r\n */\r\n this.Events = !!pEvents ? pEvents : 'change blur';\r\n\r\n this.init();\r\n } else {\r\n throw new Error(`Invalid Container: must be ${JFM_CONST.CONTAINER_COLLECTION.join(' or ')}.`)\r\n }\r\n }\r\n /**\r\n * Init helper.\r\n */\r\n init() {\r\n this.addEventListenerToFields();\r\n // If this.ValidationMethods is empty, then it initialized by ValidationMethods_JS\r\n if (!this.ValidationMethods || this.ValidationMethods.length == 0) {\r\n this.ValidationMethods = Object.getOwnPropertyNames(ValidationMethods_JS)\r\n .filter(f => (typeof ValidationMethods_JS[f] === 'function'))\r\n .map(m => ValidationMethods_JS[m]);\r\n }\r\n }\r\n /**\r\n * Attach event listeners to a field.\r\n */\r\n addEventListenerToFields() {\r\n this.Events.split(' ').forEach(e => {\r\n this.Fields.forEach(f => {\r\n f.addEventListener(e, this.evalField.bind(this), false);\r\n });\r\n });\r\n }\r\n /**\r\n * Evaluate a field.\r\n * @param {Object} event event from listener.\r\n * @returns {VAL_METHOD_RESPONSE} Field validation response.\r\n */\r\n evalField(event) {\r\n /*\r\n * validate individual field.\r\n */\r\n let objCurrentField = event.currentTarget, // current field\r\n objErrorMsgfor = this.Container.querySelector('.invalid-feedback[data-valmsg-for=\"' + objCurrentField.name + '\"]'),\r\n objValidMsgfor = this.Container.querySelector('.valid-feedback[data-valmsg-for=\"' + objCurrentField.name + '\"]'),\r\n /**\r\n * @type {VAL_METHOD_RESPONSE}\r\n */\r\n objResponse = null;\r\n\r\n // Loop for every validation method\r\n this.ValidationMethods.some(f => {\r\n objResponse = f(objCurrentField);\r\n return !objResponse.IsValid;\r\n });\r\n\r\n if (objResponse.IsValid) {\r\n !!objErrorMsgfor && (objErrorMsgfor.innerText = '');\r\n objCurrentField.classList.add('is-valid');\r\n objCurrentField.classList.remove('is-invalid');\r\n !!this.FnValidField && this.FnValidField(objCurrentField, objValidMsgfor, objErrorMsgfor, this.Container);\r\n } else {\r\n !!objErrorMsgfor && (objErrorMsgfor.innerText = objResponse.ErrorMessage);\r\n objCurrentField.classList.remove('is-valid');\r\n objCurrentField.classList.add('is-invalid');\r\n !!this.FnErrorField && this.FnErrorField(objCurrentField, objValidMsgfor, objErrorMsgfor, this.Container);\r\n }\r\n event.stopPropagation();\r\n return objResponse;\r\n }\r\n /**\r\n * Evaluate an entire of collection fields.\r\n * @returns {VALIDATION_RESPONSE} evaluated collection response.\r\n */\r\n evalForm() {\r\n let objMapErrors = new Map(), // Save all errors\r\n objEvent = {},\r\n IsValid = true,\r\n /**\r\n * @type {VAL_METHOD_RESPONSE}\r\n */\r\n objResponse = null;\r\n //check every field in the collection (this.Fields)\r\n this.Fields.forEach(f => {\r\n Object.assign(objEvent, {\r\n currentTarget: f,\r\n stopPropagation: () => {}\r\n });\r\n objResponse = this.evalField(objEvent);\r\n !objResponse.IsValid && (IsValid = false, objMapErrors.set(f, objResponse.ErrorMessage));\r\n });\r\n /**\r\n * @type {VALIDATION_RESPONSE}\r\n */\r\n return {\r\n IsValid: IsValid,\r\n Errors: objMapErrors\r\n }\r\n }\r\n /**\r\n * validate recaptcha input\r\n * @param {RecaptchaWidget} pWidgetRecaptcha \r\n * @param {VALIDATION_RESPONSE} pValidationResponse \r\n */\r\n evalCheckTypeRecaptcha(pWidgetRecaptcha, pValidationResponse) {\r\n let _token = pWidgetRecaptcha.getResponse(),\r\n _hiddenInput = null,\r\n _labelMessage = null,\r\n _errorMessage = '',\r\n _isvalid = false;\r\n\r\n if (_token) {\r\n _isvalid = true;\r\n } else {\r\n // add error to the response\r\n _isvalid = false;\r\n pValidationResponse.IsValid = false;\r\n pValidationResponse.Errors.set(pWidgetRecaptcha.RecaptchaCollection[0].inputForm, pWidgetRecaptcha.ErrorMessage);\r\n }\r\n // add error and classes for data representation.\r\n pWidgetRecaptcha.RecaptchaCollection.forEach(r => {\r\n _hiddenInput = r.inputForm;\r\n _labelMessage = this.Container.querySelector(`.invalid-feedback[data-valmsg-for=\"${_hiddenInput.name}\"]`);\r\n\r\n if (_isvalid) {\r\n _errorMessage = '';\r\n !!_hiddenInput && (_hiddenInput.classList.add('is-valid'), _hiddenInput.classList.remove('is-invalid'));\r\n } else {\r\n _errorMessage = pWidgetRecaptcha.ErrorMessage;\r\n !!_hiddenInput && (_hiddenInput.classList.add('is-invalid'), _hiddenInput.classList.remove('is-valid'));\r\n }\r\n\r\n !!_labelMessage && (_labelMessage.innerText = _errorMessage);\r\n });\r\n \r\n return pValidationResponse;\r\n }\r\n\r\n}","/**\r\n * Expression collection\r\n * @typedef {Object} class_Exp Class Expression.\r\n * @property {String} name Expression ID.\r\n * @property {String} expression Regular Expression.\r\n * @property {String} message Test message.\r\n * @property {HTMLUListElement} li list item.\r\n */\r\n\r\n/**\r\n * Set up for PasswordWidget\r\n * @typedef {Object} Widget_PWD_Params widget password params.\r\n * @property {Array.} classes testing expression collection.\r\n */\r\n\r\n\r\n\r\n/**\r\n * Point to valid subexpression test.\r\n */\r\nclass PasswordWidget {\r\n /**\r\n * @constructor\r\n * @param {HTMLInputElement} pInputControl HTML input element\r\n */\r\n constructor(pInputControl) {\r\n\r\n if (!pInputControl || !(pInputControl instanceof HTMLInputElement)) throw new Error(`Invalid input text ${pInputControl}`)\r\n\r\n // declare variables\r\n\r\n /**\r\n * @type {Widget_PWD_Params}\r\n */\r\n let objDataParams = JSON.parse(pInputControl.dataset.widgetParam);\r\n // validate input params\r\n if (!objDataParams || !Array.isArray(objDataParams.classes) || objDataParams.classes.length == 0 ||\r\n !objDataParams.classes.every(c => (!!c.expression && !!c.message && !!c.name))) {\r\n throw new Error(`Invalid widget Params : Missing classes option.`)\r\n }\r\n\r\n /**\r\n * @type {HTMLInputElement} HTML input element where widget is attached.\r\n */\r\n this.TextInput = pInputControl;\r\n /**\r\n * @type {Array.} Array of expression to test.\r\n */\r\n this.Classes = objDataParams.classes;\r\n /**\r\n * @type {Object} bootstrap.Dropdown\r\n */\r\n this.Dropdown = null;\r\n\r\n this.init();\r\n\r\n }\r\n /**\r\n * Initialize widget\r\n */\r\n init() {\r\n let parentDiv = this.TextInput.closest('div'), // Designer must code \"div\" as container for the password field.\r\n listOfDrowdown = document.createElement('UL'), // expression box\r\n listItem = document.createElement('LI'), // Each expression to test\r\n clonedListItem = null, // build each item\r\n innerText = null, // message to the user for each expression\r\n inputCheck = document.createElement('INPUT'), // check for valid input\r\n textLabel = !this.TextInput.name ? this.TextInput.id : this.TextInput.name,\r\n objThis = this;\r\n\r\n // Build parent elements\r\n parentDiv.classList.add('dropdown');\r\n listOfDrowdown.classList.add('dropdown-menu');\r\n listOfDrowdown.classList.add('dropdown-menu-end');\r\n listOfDrowdown.classList.add('p-1');\r\n parentDiv.appendChild(listOfDrowdown);\r\n\r\n !!textLabel && (listOfDrowdown.setAttribute('aria-labelledby', textLabel));\r\n\r\n //Build list item template\r\n listItem.classList.add('list-group-item');\r\n listItem.setAttribute('aria-disabled', 'true');\r\n inputCheck.type = 'checkbox';\r\n inputCheck.value = '';\r\n inputCheck.classList.add('form-check-input');\r\n inputCheck.classList.add('me-1');\r\n inputCheck.disabled = true;\r\n listItem.appendChild(inputCheck);\r\n\r\n // Build each list items\r\n this.Classes.forEach(c => {\r\n clonedListItem = listItem.cloneNode(true);\r\n clonedListItem.setAttribute('aria-label', c.message);\r\n clonedListItem.dataset.widgetClass = c.name;\r\n clonedListItem.dataset.widgetClassExp = c.expression\r\n innerText = document.createTextNode(c.message);\r\n clonedListItem.appendChild(innerText);\r\n c.li = listOfDrowdown.appendChild(clonedListItem);\r\n c.li.inputCheck = c.li.querySelector('input[type=\"checkbox\"]');\r\n });\r\n //Build dropdown\r\n this.Dropdown = new bootstrap.Dropdown(parentDiv);\r\n //Show widget\r\n this.TextInput.addEventListener('focus', () => {\r\n objThis.Dropdown.show();\r\n }, false);\r\n //Hide Widget\r\n this.TextInput.addEventListener('blur', () => {\r\n objThis.Dropdown.hide();\r\n }, false);\r\n // catch entry data for input text field\r\n this.TextInput.addEventListener('input', this.evalRegularExpressions.bind(this), false);\r\n }\r\n /**\r\n * Set input checked attribute to true if the current value is tested as true\r\n * @param {Object} event \r\n */\r\n evalRegularExpressions(evt) {\r\n let objRegExp = null,\r\n strValue = `${this.TextInput.value}`;\r\n this.Classes.forEach(c => {\r\n objRegExp = new RegExp(c.expression);\r\n if (objRegExp.test(strValue)) {\r\n c.li.inputCheck.checked = true;\r\n } else {\r\n c.li.inputCheck.checked = false;\r\n }\r\n });\r\n }\r\n}\r\n\r\n\r\n/**\r\n * Build hidden input text from date parts\r\n */\r\nclass DatePartWidget {\r\n constructor(pInputDatePart) {\r\n if (!pInputDatePart || !(pInputDatePart instanceof HTMLSelectElement || pInputDatePart instanceof HTMLInputElement)) throw new Error(`Invalid HTML Element ${pInputDatePart}`)\r\n\r\n let params = JSON.parse(pInputDatePart.dataset.widgetParam)\r\n\r\n /**\r\n * Hidden input selector\r\n * @type {String} \r\n */\r\n this.InputHiddenSelector = pInputDatePart.dataset.widgetTarget;\r\n /**\r\n * Date part\r\n * @type {String} \r\n */\r\n this.DatePartParam = params.part;\r\n /**\r\n * Default Value\r\n * @type {String} \r\n */\r\n this.DefaultValueParam = !!params.value ? params.value : 'null';\r\n /**\r\n * Aria for assisted technologies.\r\n * @type {String} \r\n */\r\n this.AriaDescribedBYParam = !!params.describedby ? params.describedby : '';\r\n /**\r\n * Message Error for {@link ValidationMethods_JS.dateISO8601Eval}\r\n * @type {String} \r\n */\r\n this.ValMessageParam = !!params.eval ? params.eval : '';\r\n /**\r\n * input date part.\r\n * @type {HTMLSelectElement | HTMLInputElement} \r\n */\r\n this.HTMLInputDatePart = pInputDatePart;\r\n\r\n\r\n if (!this.InputHiddenSelector) throw new Error(`Invalid widget target ${pInputDatePart.dataset.widgetTarget}`);\r\n if (!this.DatePartParam || !(this.DatePartParam.includes('yyyy') || this.DatePartParam.includes('MM') || this.DatePartParam.includes('dd'))) {\r\n throw new Error(`Invalid widget part param ${pInputDatePart.dataset.widgetParam}`);\r\n }\r\n\r\n this.init();\r\n }\r\n /**\r\n * Initialize widget\r\n */\r\n init() {\r\n let inputHidden = document.querySelector(this.InputHiddenSelector);\r\n\r\n if (!inputHidden) {\r\n inputHidden = document.createElement('INPUT');\r\n inputHidden.type = \"hidden\";\r\n inputHidden.name = this.InputHiddenSelector.replace('#', '').replace('.', '');\r\n inputHidden.id = inputHidden.name;\r\n inputHidden.setAttribute('aria-describedby', this.AriaDescribedBYParam);\r\n inputHidden.dataset.val = 'true';\r\n inputHidden.dataset.valDate = this.ValMessageParam;\r\n inputHidden.dataset.widgetRelatedTo = !!this.HTMLInputDatePart.id ? this.HTMLInputDatePart.id : '';\r\n inputHidden.dataset.valNoTransmit = \"true\";\r\n inputHidden.value = '';\r\n this.HTMLInputDatePart.insertAdjacentElement('beforebegin', inputHidden);\r\n } else {\r\n inputHidden.dataset.widgetRelatedTo = `${inputHidden.dataset.widgetRelatedTo} ${this.HTMLInputDatePart.id}`;\r\n }\r\n\r\n this.updateCurrentDate(inputHidden, {});\r\n\r\n this.HTMLInputDatePart.addEventListener('change', this.updateCurrentDate.bind(this, inputHidden), false);\r\n }\r\n /**\r\n * Update value on the hidden input.\r\n * @param {HTMLInputElement} inputHidden hidden input full date text.\r\n * @param {Event} evt event object\r\n */\r\n updateCurrentDate(inputHidden, evt) {\r\n let _year,\r\n _month,\r\n _day,\r\n _defaultValue = parseInt(this.DefaultValueParam),\r\n isFromChangeEvent = !!evt.currentTarget, // set true if this method was called by change event.\r\n _changedValue = parseInt(isFromChangeEvent ? evt.currentTarget.value : ''),\r\n _valueToUpdate = '';\r\n\r\n // get current values\r\n !!inputHidden.value && ([_year, _month, _day] = inputHidden.value.split('-'));\r\n\r\n if (isFromChangeEvent) {\r\n _valueToUpdate = _changedValue;\r\n } else {\r\n _valueToUpdate = _defaultValue;\r\n }\r\n // initializes not numbet value\r\n isNaN(_valueToUpdate) && (_valueToUpdate = 0);\r\n //update new value\r\n switch (this.DatePartParam) {\r\n case 'yyyy':\r\n _year = `${'0000'}${_valueToUpdate}`.slice(-4);\r\n break;\r\n case 'MM':\r\n _month = `${'00'}${_valueToUpdate}`.slice(-2);\r\n break;\r\n case 'dd':\r\n _day = `${'00'}${_valueToUpdate}`.slice(-2);\r\n }\r\n //rebuild new value\r\n inputHidden.value = `${_year}-${_month}-${_day}`;\r\n }\r\n}\r\n\r\n/**\r\n * @typedef {Object} recaptcha_collection widget recaptcha params.\r\n * @property {String} version recaptcha version.\r\n * @property {String} message error message.\r\n * @property {String} target input field for saving recaptcha value.\r\n * @property {HTMLInputElement} inputForm Input HTML Element that receives token value after a successful response.\r\n * @property {GrecaptchaV2_JS} grecaptchaV2 Google recaptcha.\r\n */\r\n\r\n/**\r\n * Build Widget for repeated checkbox recatpchas\r\n */\r\nclass RecaptchaWidget {\r\n /**\r\n * @param {Object} pGrecaptcha grecaptcha object.\r\n * @param {Array.} pRecaptchaCollection array of widget recaptcha inputs.\r\n * @param {String} pGeneralMessage error message.\r\n * @param {GRECAPTCHA_OPTIONS} pOptions GrecaptchaV2_JS options.\r\n */\r\n constructor(pGrecaptcha, pRecaptchaCollection, pGeneralMessage, pOptions) {\r\n if (!pGrecaptcha) {\r\n throw new Error('Missing grecaptcha object.');\r\n }\r\n /**\r\n * Flag to signal has recaptcha token value.\r\n * @type {Boolean} \r\n */\r\n this.HasValue = false;\r\n /**\r\n * General Error message.\r\n * @type {String}\r\n */\r\n this.ErrorMessage = pGeneralMessage;\r\n /**\r\n * several recaptchas in a form.\r\n * @type {Array.}\r\n */\r\n this.RecaptchaCollection = (!!pRecaptchaCollection && pRecaptchaCollection.length > 0) &&\r\n (\r\n pRecaptchaCollection = [].slice.call(pRecaptchaCollection, 0)\r\n ,\r\n pRecaptchaCollection.map(r => {\r\n // Load widget params\r\n let widgetParams = !!r.dataset.widgetParam ? JSON.parse(r.dataset.widgetParam) : {},\r\n defaultOptions = {\r\n version: \"2.0\",\r\n message: \"Valida el recaptcha para continuar.\",\r\n target: r.dataset.widgetTarget,\r\n inputForm: r\r\n };\r\n Object.assign(defaultOptions, widgetParams);\r\n return defaultOptions;\r\n })\r\n );\r\n\r\n this.init(pOptions, pGrecaptcha);\r\n }\r\n /**\r\n * Load serveral recaptchas belonged to the same siteKey.\r\n * @param {GRECAPTCHA_OPTIONS} pOptions \r\n */\r\n init(pOptions, pGrecaptcha) {\r\n if (!this.RecaptchaCollection) {\r\n throw new Error('RecaptchaWidget: Missing input recaptcha collection.');\r\n }\r\n\r\n this.RecaptchaCollection.forEach(or => {\r\n let options = {\r\n selector: or.target,\r\n inputForm: or.inputForm,\r\n callback: this.resetRestAfterchecked(),\r\n expiredCallback: this.expiredWidgetRecaptcha(),\r\n ...pOptions\r\n };\r\n Object.assign(options, pOptions)\r\n if (or.version === \"2.0\") {\r\n or.grecaptchaV2 = new GrecaptchaV2_JS(pGrecaptcha, options);\r\n }\r\n });\r\n }\r\n /**\r\n * Reset all Recaptcha.\r\n */\r\n reset() {\r\n this.RecaptchaCollection.forEach(or => or.grecaptchaV2.reset());\r\n }\r\n /**\r\n * Set a function to reset all recaptcha except checked recaptcha.\r\n * @returns {Function} reset all recaptcha except checked recaptcha fuction.\r\n */\r\n resetRestAfterchecked() {\r\n const objThis = this;\r\n return () => {\r\n let arrayCheckedRecaptcha = objThis.RecaptchaCollection.filter(or => or.grecaptchaV2.getResponse().length > 0);\r\n if (!!arrayCheckedRecaptcha && arrayCheckedRecaptcha.length > 0) {\r\n objThis.RecaptchaCollection.forEach(or => {\r\n (or.grecaptchaV2.widget_id != arrayCheckedRecaptcha[0].grecaptchaV2.widget_id) && or.grecaptchaV2.reset();\r\n });\r\n }\r\n objThis.HasValue = true;\r\n }\r\n }\r\n /**\r\n * Set a function to set HasValue flag to true.\r\n * @returns {Function} function to set HasValue flag to true.\r\n */\r\n expiredWidgetRecaptcha() {\r\n const objThis = this;\r\n return () => {\r\n let arrayCheckedRecaptcha = objThis.RecaptchaCollection.filter(or => or.grecaptchaV2.getResponse().length > 0);\r\n if (!!arrayCheckedRecaptcha && arrayCheckedRecaptcha.length > 0) {\r\n objThis.HasValue = true;\r\n } else {\r\n objThis.HasValue = false;\r\n }\r\n }\r\n }\r\n /**\r\n * get Recaptcha value\r\n * @returns {String} Recaptch token value\r\n */\r\n getResponse() {\r\n let tokenValue = '';\r\n this.RecaptchaCollection.some(or => {\r\n tokenValue = or.grecaptchaV2.RecaptchaValue;\r\n return or.grecaptchaV2.isValid()\r\n });\r\n return tokenValue;\r\n }\r\n}","class Alert_JS {\r\n constructor(pMsg, pType = JFMUI_CONST.ICONS.SUCCESS, pHasIcon = true, pIsdismissible = true) {\r\n \r\n this.AlertType = pType;\r\n this.Message = pMsg;\r\n this.Isdismissible = pIsdismissible;\r\n this.HasIcon = pHasIcon;\r\n this.Template = '
' +\r\n '
' +\r\n '
' +\r\n '
';\r\n this.AlertHTML = DOM_Utility.createHTMLFromString(this.Template);\r\n\r\n this.init();\r\n }\r\n\r\n init(){\r\n let strAlertClass = 'alert-info',\r\n strBtnClose = this.Isdismissible ? \r\n DOM_Utility.createHTMLFromString('') : null,\r\n objHTMLIcon = this.HasIcon ? new Icon_JS({IType:this.AlertType }).generateIcon() : null,\r\n objHTMLMsgDiv = this.AlertHTML.querySelector('.message');\r\n\r\n switch (this.AlertType) {\r\n case JFMUI_CONST.ICONS.INFO:\r\n strAlertClass = 'alert-info';\r\n break;\r\n case JFMUI_CONST.ICONS.SUCCESS:\r\n strAlertClass = 'alert-success';\r\n break;\r\n case JFMUI_CONST.ICONS.WARNING:\r\n strAlertClass = 'alert-warning';\r\n break;\r\n case JFMUI_CONST.ICONS.DANGER:\r\n strAlertClass = 'alert-danger';\r\n break;\r\n }\r\n // add alert type class\r\n this.AlertHTML.classList.add(strAlertClass);\r\n if (!!objHTMLMsgDiv) {\r\n objHTMLMsgDiv.innerHTML = this.Message;\r\n !!strBtnClose && (objHTMLMsgDiv.insertAdjacentElement('afterEnd',strBtnClose));\r\n !!objHTMLIcon && (objHTMLMsgDiv.insertAdjacentElement('beforeBegin',objHTMLIcon));\r\n }\r\n }\r\n updateTemplate(pTemplate){\r\n this.Template = pTemplate;\r\n this.AlertHTML = DOM_Utility.createHTMLFromString(pTemplate);\r\n this.init();\r\n }\r\n show(pSelector) {\r\n let objHTMLContainer = (pSelector instanceof HTMLElement) ? pSelector : document.querySelector(pSelector);\r\n !!objHTMLContainer && (objHTMLContainer.insertAdjacentElement('beforeEnd',this.AlertHTML))\r\n return new bootstrap.Alert(this.AlertHTML);\r\n }\r\n}","/**\r\n * @typedef {Object} FORMS_PARAM form params\r\n * @property {String} selector Container of inputs.\r\n * @property {String} confirmTxt Confirm Pop Up Message before submit form.\r\n * @property {REPLACEMODE} insertionMode Replace mode after submit a form.\r\n * @property {String} updateTargetId: location where to insert the HTML response, depends on insertionMode param.\r\n * @property {Loader} loader Loader object with hideLoader/showLoader functions.\r\n * @property {String} method Request method.\r\n * @property {String} url Target Server web method.\r\n * @property {GRECAPTCHA_OPTIONS} recaptchaOptions recaptcha options.\r\n * @property {String} recaptchaError message error.\r\n * @property {Boolean} isSubmitEnable enable/disable the submit button.\r\n * @property {Function} onBeforeSubmit it executes a function before submit the form - must return true otherwise the process is cancelled.\r\n * @property {Function} onBegin: it executes a function before AJAX communications.\r\n * @property {Function} onComplete: it executesa function after AJAX communications.\r\n * @property {Function} onSuccess: it executes afunction after AJAX successful operation.\r\n * @property {Function} onFailure: it executes a function if an error ocurred in the AJAX communications.\r\n * @property {String} contentType: format FORMDATA or JSON data.\r\n * @property {Function} sanitizeFn: Sanitize function.\r\n * @property {Object} dataObject: fill form with data.\r\n */\r\n\r\n\r\n/**\r\n * @typedef {Object} AJAX_DATA data to send.\r\n * @property {Boolean} IsValid True to send the fields.\r\n * @property {Object} Fields object fields.\r\n */\r\n// TODO: add data-list-field-object logic\r\n// todo: add format to the fields\r\n\r\n// TODO: 1 .- insert logic for insertionMode\r\n// updateTargetId\r\n// loader\r\n// method\r\n// url\r\n// onBegin\r\n// onComplete\r\n// onFailure\r\n// onSuccess\r\n// TODO: 2.- logic for formdata\r\n// TODO: 3.- Logic for upload files\r\n// TODO: 4.- Logic for invisible recaptcha\r\n\r\n//TODO: make aware that all validations must run in every field regardless if one of them is changed\r\n/**\r\n * @class\r\n * manage form fields\r\n */\r\nclass Forms_JS {\r\n /**\r\n * @constructor\r\n * @param {FORMS_PARAM} paramOptions forms options\r\n */\r\n constructor(paramOptions) {\r\n /**\r\n * default options\r\n * @type {FORMS_PARAM}\r\n */\r\n let Options = {\r\n selector: '',\r\n confirmTxt: '',\r\n insertionMode: null,\r\n updateTargetId: '',\r\n loader: null,\r\n method: '',\r\n url: '',\r\n recaptchaOptions: null,\r\n recaptchaError: '',\r\n isSubmitEnable: true,\r\n onBeforeSubmit: null,\r\n onBegin: null,\r\n onComplete: null,\r\n onSuccess: null,\r\n onFailure: null,\r\n contentType: JFM_CONST.CONTENTTYPE.JSON,\r\n dataObject: null\r\n };\r\n\r\n Object.assign(Options, paramOptions);\r\n\r\n /**\r\n * Form container\r\n * @type {HTMLFormElement|HTMLDivElement}\r\n */\r\n this.Container = document.querySelector((typeof Options.selector === 'string') ? Options.selector : null);\r\n /**\r\n * Form Confirmation text.\r\n * @type {String}\r\n */\r\n this.ConfirmTxt = (typeof Options.confirmTxt === 'string') ? Options.confirmTxt : '';\r\n /**\r\n * Recaptcha options.\r\n * @type {GRECAPTCHA_OPTIONS}\r\n */\r\n this._recaptchaOptions = (typeof Options.recaptchaOptions === 'object') ? Options.recaptchaOptions : null;\r\n /**\r\n * Has Recaptcha Flag\r\n * @type {Boolean}\r\n */\r\n this.HasRecaptcha = !!this._recaptchaOptions;\r\n /**\r\n * Recaptcha options.\r\n * @type {String}\r\n */\r\n this._recaptchaError = (typeof Options.recaptchaError === 'string') ? Options.recaptchaError : '';\r\n /**\r\n * Recaptcha control.\r\n * @type {RecaptchaWidget}\r\n */\r\n this.WidgetRecaptcha = null;\r\n /**\r\n * enable/disable submit\r\n * @type {Boolean}\r\n * @private\r\n */\r\n this._IsSubmitEnable = !!Options.isSubmitEnable;\r\n /**\r\n * raise a function before submit the form. If returns false the submit event is cancelled\r\n * @type {Function}\r\n */\r\n this.OnBeforeSubmit = (typeof Options.onBeforeSubmit === 'function') ? Options.onBeforeSubmit : null;\r\n /**\r\n * Ajax contentType to submit\r\n * @type {String} \r\n */\r\n this.ContentType = (typeof Options.contentType === 'string') ? Options.contentType.toLocaleLowerCase() : '';\r\n /**\r\n * Form Fields Collection\r\n * @type {Array.}\r\n */\r\n this.FieldCollection = null;\r\n /**\r\n * Submit buttons\r\n * @type {Array.}\r\n */\r\n this.SubmitBtnCollection = null;\r\n /**\r\n * Form validation Layer.\r\n * @type {ValidationForm_JS}\r\n */\r\n this.ValidationForm = null;\r\n /**\r\n * santize function\r\n * @type {Function}\r\n */\r\n this.SanitizeFn = Options.sanitizeFn;\r\n /**\r\n * data to fill the form.\r\n * @type {Object}\r\n */\r\n this._data = Options.dataObject;\r\n\r\n this.init();\r\n }\r\n /**\r\n * return object data\r\n * @returns {Object} object data\r\n */\r\n get Data() {\r\n return this._data;\r\n }\r\n //TODO: test by subscriber\r\n set Data(value) {\r\n const isSubmitEnable = this.IsSubmitEnable;\r\n this._data = typeof value === 'object' ? value : null;\r\n if (!!this._data && Object.keys(this._data).length > 0) {\r\n !!isSubmitEnable && (this.IsSubmitEnable = false);\r\n this.loadData(this._data);\r\n !!isSubmitEnable && (this.IsSubmitEnable = true);\r\n }\r\n }\r\n\r\n get IsSubmitEnable() {\r\n return this._IsSubmitEnable;\r\n }\r\n /**\r\n * Enable / unenable fields\r\n * @param {Boolean} value true for enable submit button.\r\n */\r\n set IsSubmitEnable(value) {\r\n //Enable / unenable fields\r\n this._IsSubmitEnable = !!value;\r\n !!this.SubmitBtnCollection && this.SubmitBtnCollection.forEach(s => (s.disabled = !this.IsSubmitEnable));\r\n }\r\n /**\r\n * Initialize Forms JS\r\n */\r\n init() {\r\n // valid params\r\n //Container\r\n if (!this.Container || !(JFM_CONST.CONTAINER_COLLECTION.some(c => c === this.Container.tagName.toUpperCase()))) {\r\n throw new Error(`invalid form container:${this.Container.tagName}`);\r\n }\r\n //Recaptcha site key config\r\n if (!!this._recaptchaOptions && !this._recaptchaOptions.siteKey) {\r\n throw new Error(`Missing site key in Recaptcha options`);\r\n }\r\n //Content type\r\n if (!this.ContentType.includes(JFM_CONST.CONTENTTYPE.FORMDATA) && !this.ContentType.includes(JFM_CONST.CONTENTTYPE.JSON)) {\r\n throw new Error(`Invalid ajax contentType:${this.ContentType}`);\r\n }\r\n //Look for submit button\r\n this.SubmitBtnCollection = this.Container.querySelectorAll('input[type=\"submit\"], button[type=\"submit\"], a[role=\"submit\"]');\r\n if (!this.SubmitBtnCollection || this.SubmitBtnCollection.length == 0) {\r\n throw new Error(`Missing submit button: looking for input[type=\"submit\"] or button[type=\"submit\"] or a[role=\"submit\"]`);\r\n }\r\n //enable /disable submit button\r\n this.IsSubmitEnable = this._IsSubmitEnable;\r\n //has recaptcha\r\n // set up all recaptcha\r\n !!this.HasRecaptcha && this.initRecaptcha();\r\n\r\n //Init custom widget controls.\r\n this.initWidgets();\r\n //Fill the form with data\r\n if (typeof this._data == 'object' && !!this._data && Object.keys(this._data).length > 0) {\r\n this.Data = this._data;\r\n }\r\n //Get input fields\r\n this.FieldCollection = this.Container.querySelectorAll('input[data-val=\"true\"], textarea[data-val=\"true\"], select[data-val=\"true\"]');\r\n // convert to array \r\n if (!!this.FieldCollection && this.FieldCollection.length > 0) {\r\n this.FieldCollection = [].slice.call(this.FieldCollection, 0);\r\n } else {\r\n throw new Error(`Missing form fields: set [data-val=\"true\"] attribute`);\r\n }\r\n //attach events for validation each fields\r\n this.ValidationForm = new ValidationForm_JS(this.Container, this.FieldCollection)\r\n //add submit event\r\n this.addSubmitEvent();\r\n }\r\n /**\r\n * set up all recaptcha\r\n */\r\n initRecaptcha() {\r\n if (!!grecaptcha) {\r\n const _recaptchaCollection = this.Container.querySelectorAll('input[data-widget=\"recaptcha\"]');\r\n this.WidgetRecaptcha = new RecaptchaWidget(grecaptcha, _recaptchaCollection, this._recaptchaError, this._recaptchaOptions);\r\n } else {\r\n throw new Error(`Missing grecaptcha object for Google Recaptcha V2`);\r\n }\r\n }\r\n /**\r\n * Init custom widget controls.\r\n */\r\n initWidgets() {\r\n const _fieldCollection = this.Container.querySelectorAll('input[data-widget], textarea[data-widget], select[data-widget]');\r\n if (!!_fieldCollection) {\r\n [].slice.call(_fieldCollection, 0)\r\n .forEach(w => {\r\n switch (w.dataset.widget.toLowerCase()) {\r\n case 'date':\r\n w.widget = new DatePartWidget(w);\r\n break;\r\n case 'password':\r\n w.widget = new PasswordWidget(w);\r\n break;\r\n }\r\n });\r\n }\r\n }\r\n /**\r\n * register submit event.\r\n */\r\n addSubmitEvent() {\r\n const isSubmitEvent = this.Container instanceof HTMLFormElement;\r\n if (isSubmitEvent) {\r\n this.Container.addEventListener('submit', this.onSubmit.bind(this), false);\r\n } else {\r\n this.SubmitBtnCollection.forEach(btn => btn.addEventListener('click', this.onSubmit.bind(this), false));\r\n }\r\n }\r\n /**\r\n * Reset form\r\n */\r\n reset() {\r\n if (this.Container instanceof HTMLFormElement) {\r\n this.Container.reset();\r\n this.Container.querySelectorAll('input,textarea,select').forEach(f=>f.classList.remove('is-valid', 'is-invalid'));\r\n } else {\r\n this.FieldCollection.forEach(f => {\r\n switch (f.type.toLowerCase()) {\r\n case 'checkbox':\r\n f.checked = false;\r\n break;\r\n case 'radio':\r\n f.checked = false;\r\n break;\r\n case \"select-one\":\r\n case \"select-multiple\":\r\n f.value = null;\r\n break;\r\n case \"file\":\r\n f.value = null;\r\n break;\r\n default:\r\n f.value = null;\r\n break;\r\n }\r\n f.classList.remove('is-valid', 'is-invalid');\r\n });\r\n }\r\n //Reset recaptcha\r\n if (this.HasRecaptcha) {\r\n this.WidgetRecaptcha.reset();\r\n }\r\n }\r\n /**\r\n * send form if fields are correct.\r\n */\r\n sendForm() {\r\n /**\r\n * @type {AJAX_DATA}\r\n */\r\n let objAjaxData = this.validateForm();\r\n\r\n if (objAjaxData.IsValid) {\r\n this.SendDataByAjax(objAjaxData.Fields);\r\n }\r\n }\r\n /**\r\n * validate Form\r\n * @returns {AJAX_DATA} data to send\r\n */\r\n validateForm() {\r\n /**\r\n * @type {VALIDATION_RESPONSE}\r\n */\r\n let _response = {}, //detail validation response\r\n SanitizeFn = (typeof this.SanitizeFn === 'function') ? this.SanitizeFn : DOM_Utility.encodeHTMLEntities,\r\n _HtmlIL = null, // IL html element\r\n /**\r\n * @type {Array}\r\n */\r\n _arrObjFields = [], // data list object fields\r\n _objFields = {}; // data object to send\r\n\r\n const _errorSumaryHTML = this.Container.querySelector('[data-summary-error=\"true\"]'), //html panel error.\r\n _HtmlUL = document.createElement('UL'); // html
    \r\n\r\n // sanitize fields\r\n this.FieldCollection = this.Container.querySelectorAll('input[data-val=\"true\"], textarea[data-val=\"true\"], select[data-val=\"true\"]');\r\n this.FieldCollection.forEach(f => (f.value = SanitizeFn(f.value)));\r\n // format strings values\r\n // data-field-format must be a preexisting function in the String object\r\n // data-field-format-params args for the function in an array format\r\n this.FieldCollection.forEach(f => {\r\n let jsonParams = '',\r\n Fn = null;\r\n if (!!f.dataset.fieldFormat && !!f.value && typeof f.value[f.dataset.fieldFormat] === 'function') {\r\n //get params\r\n if (!!f.dataset.fieldFormatParams) {\r\n jsonParams = JSON.parse(f.dataset.fieldFormatParams);\r\n }\r\n\r\n Fn = f.value[f.dataset.fieldFormat];\r\n\r\n if (Array.isArray(jsonParams)) {\r\n f.value = Fn.apply(f.value, jsonParams);\r\n } else {\r\n f.value = Fn.call(f.value);\r\n }\r\n }\r\n });\r\n // validate form\r\n _response = this.ValidationForm.evalForm();\r\n // validate recaptcha\r\n this.HasRecaptcha && (_response = this.ValidationForm.evalCheckTypeRecaptcha(this.WidgetRecaptcha, _response));\r\n //Clean error messages\r\n !!_errorSumaryHTML && (_errorSumaryHTML.innerHTML = '');\r\n // print all errors\r\n if (!_response.IsValid) {\r\n if (!!_errorSumaryHTML) {\r\n _response.Errors.forEach((v, k) => {\r\n const _descriptionField = (!!k.hasAttribute && k.hasAttribute('aria-describedby')) ? `${k.getAttribute('aria-describedby')}:` : '';\r\n _HtmlIL = document.createElement('LI')\r\n _HtmlIL.classList.add('text-start');\r\n _HtmlIL.innerHTML = `${_descriptionField} ${v}`;\r\n _HtmlUL.appendChild(_HtmlIL);\r\n })\r\n // _errorSumaryHTML.appendChild(_HtmlUL);\r\n new Alert_JS(_HtmlUL.outerHTML, JFMUI_CONST.ICONS.DANGER).show(_errorSumaryHTML);\r\n }\r\n // set focus to the first incorrect field.\r\n _response.Errors.keys().next().value.focus();\r\n } else {\r\n //get fields to send\r\n _objFields = this.getObjectFromFields(this.FieldCollection);\r\n // get data list fiels\r\n _objFields = this.getArrayFromTemplate(_objFields, this.Container, 1);\r\n _objFields.ReCaptchaToken = this.HasRecaptcha ? this.WidgetRecaptcha.getResponse() : '';\r\n }\r\n /**\r\n * @type {AJAX_DATA}\r\n */\r\n return {\r\n IsValid: (!this.OnBeforeSubmit || !!this.OnBeforeSubmit(_response, _objFields)) && _response.IsValid,\r\n Fields: _objFields\r\n }\r\n }\r\n /**\r\n * Build Object Data\r\n * @param {HTMLInputElement|HTMLTextAreaElement} pObjFields fields to convert.\r\n * @returns {Object} Object Data.\r\n */\r\n getObjectFromFields(pObjFields) {\r\n let objRoot = {};\r\n\r\n pObjFields.forEach((f) => {\r\n let dataObject = f.dataset.fieldObject; //output property name\r\n if (!!dataObject) {\r\n // get property value from input field.\r\n objRoot = this.buildObjectFromData(objRoot, dataObject, f);\r\n }\r\n });\r\n return objRoot;\r\n }\r\n /**\r\n * Add list item property to the root object.\r\n * @param {Object} pObjRoot \r\n * @param {HTMLElement} pScope searching scope.\r\n * @param {Number} pLevel nested level\r\n * @returns {Object} root object\r\n */\r\n getArrayFromTemplate(pObjRoot, pScope, pLevel = 1) {\r\n let arrObject = [],\r\n arrayListContainer = pScope.querySelectorAll(`ul[data-list-level=\"${pLevel}\"]`);\r\n if (!!arrayListContainer && arrayListContainer.length > 0) {\r\n // get array of list objects\r\n arrObject = Array.from(arrayListContainer).map(ul => this.getArrayFromList(ul, pLevel));\r\n // convert array of objects to a single object\r\n arrObject = arrObject.reduce((pV, cV)=>pV={...pV,...cV},{});\r\n Object.assign(pObjRoot, arrObject);\r\n }\r\n return pObjRoot;\r\n }\r\n /**\r\n * get array of Objects from LI elements.\r\n * @param {HTMLUListElement} pUL \r\n * @param {Number} pLevel nested level\r\n * @returns {Object} List field Object.\r\n */\r\n getArrayFromList(pUL, pLevel) {\r\n let objRoot = {},\r\n dataListContainer = pUL.dataset.listContainer,\r\n HTMLLICollection = null\r\n\r\n if (!!dataListContainer) {\r\n objRoot[dataListContainer] = [];\r\n HTMLLICollection = [].slice.call(pUL.children, 0).filter(child => child.tagName == 'LI');\r\n if (!!HTMLLICollection) {\r\n objRoot[dataListContainer] = [].slice.call(HTMLLICollection, 0).map(li => {\r\n let root = {}\r\n let fieldList = null\r\n\r\n if (!!li.dataset.listFieldObject && !!li.dataset.listItemValue) {\r\n root = this.buildObjectFromData(root, li.dataset.listFieldObject, undefined, li.dataset.listItemValue);\r\n fieldList = Array.from(li.querySelectorAll('input[data-list-field-object],textarea[data-list-field-object]')).filter(f => f.closest(`li`) === li);\r\n fieldList.forEach(f => {\r\n root = this.buildObjectFromData(root, f.dataset.listFieldObject, f);\r\n });\r\n root = this.getArrayFromTemplate(root, li, ++pLevel)\r\n }\r\n\r\n return root;\r\n });\r\n }\r\n }\r\n\r\n return objRoot;\r\n }\r\n /**\r\n * Build object of fields\r\n * @param {Object} pObjRoot object root.\r\n * @param {String} pPath property path.\r\n * @param {HTMLInputElement|HTMLTextAreaElement} pHTMLInput input field.\r\n * @param {any} pPropertyValue property value.\r\n * @returns {Object} object of fields\r\n */\r\n buildObjectFromData(pObjRoot, pPath, pHTMLInput, pPropertyValue = '') {\r\n const arrFieldPatch = pPath.split('.').map((item) => item.trim()); // path string\r\n let objResp = pObjRoot, // root object\r\n propertyValue = pPropertyValue; // output property value\r\n\r\n // get property value from input field.\r\n if (!propertyValue) {\r\n switch (pHTMLInput.type.toLowerCase()) {\r\n case 'checkbox':\r\n propertyValue = pHTMLInput.checked;\r\n break;\r\n case 'radio':\r\n propertyValue = this.Container.querySelector(`input[type=\"radio\"][name=\"${pHTMLInput.name}\"]:checked`).value;\r\n break;\r\n case \"select-one\":\r\n case \"select-multiple\":\r\n for (let index = 0, selectOption = null, optionValue = ''; index < pHTMLInput.options.length; index++) {\r\n if (pHTMLInput.options[index].selected) {\r\n selectOption = pHTMLInput.options[index];\r\n if (selectOption.hasAttribute) {\r\n optionValue = (selectOption.hasAttribute(\"value\") ? selectOption.value : selectOption.text);\r\n } else {\r\n optionValue = (selectOption.attributes['value'].specified ? selectOption.value : selectOption.text);\r\n }\r\n propertyValue += optionValue + '&';\r\n }\r\n }\r\n if (propertyValue.lastIndexOf(\"&\") > -1) {\r\n propertyValue = propertyValue.slice(0, propertyValue.lastIndexOf(\"&\"));\r\n }\r\n break;\r\n case \"file\":\r\n for (let index = 0; index < pHTMLInput.files.length; index++) {\r\n propertyValue += pHTMLInput.files[index].name + '&';\r\n }\r\n if (propertyValue.lastIndexOf(\"&\") > -1) {\r\n propertyValue = propertyValue.slice(0, propertyValue.lastIndexOf(\"&\"));\r\n }\r\n break;\r\n default:\r\n // includes textarea also\r\n propertyValue = pHTMLInput.value;\r\n }\r\n }\r\n\r\n // build the object like a linked list\r\n arrFieldPatch.forEach((currentValue, index, arr) => {\r\n if (index == (arr.length - 1)) {\r\n objResp[currentValue] = propertyValue;\r\n } else {\r\n if (!objResp[currentValue]) {\r\n objResp[currentValue] = {}\r\n }\r\n }\r\n objResp = objResp[currentValue];\r\n });\r\n\r\n return pObjRoot;\r\n }\r\n\r\n /**\r\n * load object fields into the form.\r\n * @param {Object} pData data to fill the form.\r\n * @param {String} pPath object path\r\n */\r\n loadData(pData, pPath) {\r\n let _HTMLField = null, //HTML element\r\n _radioField = null; // radio type input\r\n\r\n pPath = !!pPath ? `${pPath}.` : ''; // add '.' accessor\r\n //iterate on object properties\r\n for (let prop in pData) {\r\n if (Array.isArray(pData[prop])) {\r\n // decompose array elements.\r\n pData[prop].forEach(pElem => this.loadDataList(pElem, this.Container, `${prop}`));\r\n } else if (typeof pData[prop] == 'object') {\r\n //descompe objects in inner properties.\r\n !!pData[prop] && this.loadData(pData[prop], `${pPath}${prop}`);\r\n } else if (typeof pData[prop] == 'string' || typeof pData[prop] == 'number' || typeof pData[prop] == 'boolean') {\r\n // assign values to the form\r\n _HTMLField = this.Container.querySelector(`[data-field-object=\"${pPath}${prop}\"]`); //get html element.\r\n\r\n if (_HTMLField instanceof HTMLInputElement || _HTMLField instanceof HTMLTextAreaElement || _HTMLField instanceof HTMLSelectElement) {\r\n // processs input o textarea\r\n switch (_HTMLField.type) {\r\n case 'checkbox':\r\n _HTMLField.checked = !!pData[prop];\r\n break;\r\n case 'radio':\r\n _radioField = this.Container.querySelector(`input[type=\"radio\"][name=\"${_HTMLField.name}\"][value=\"${pData[prop].toString().trim()}\"]`);\r\n !!_radioField && (_radioField.checked = true);\r\n break;\r\n case \"select-one\":\r\n case \"select-multiple\":\r\n [].slice.call(_HTMLField.options, 0).some(o => {\r\n return (o.value == pData[prop].toString().trim()) && (o.selected = true);\r\n });\r\n break;\r\n case 'file':\r\n //reset input file.\r\n _HTMLField.value = null;\r\n break;\r\n default:\r\n //textarea value or another input type element.\r\n _HTMLField.value = pData[prop].toString().trim();\r\n }\r\n } else if (!!_HTMLField) {\r\n _HTMLField.innerText = pData[prop].toString().trim(); //insert string in common tag element.\r\n }\r\n }\r\n }\r\n }\r\n /**\r\n * build html template for array values.\r\n * @param {Object} pData data object.\r\n * @param {HTMLElement} pScope container scope.\r\n * @param {String} pPath path to property.\r\n * @param {HTMLElement} pHTMLTemplate html template in memory only.\r\n * @param {HTMLElement} pHTMLParent html element where pHTMLTemplate is appended to.\r\n */\r\n // loadDataList(pData, pListContainer, pScope, pPath, pHTMLTemplate, pHTMLParent) {\r\n loadDataList(pData, pScope, pPath, pHTMLTemplate = null, pHTMLParent = null) {\r\n /**\r\n * @type {HTMLTemplateElement}\r\n */\r\n let _Template = null, //template element\r\n _HTMLParent = null, //list container\r\n _HTMLTemplate = null, //cloned document fragment\r\n _HTMLField = null, // text input\r\n _radioField = null; // radio input\r\n // get template node.\r\n if (!!pHTMLTemplate) {\r\n _HTMLTemplate = pHTMLTemplate;\r\n } else {\r\n _Template = document.querySelector(`template[data-list-template=\"${pPath}\"]`);\r\n if (!!_Template) {\r\n _HTMLTemplate = _Template.content.cloneNode(true);\r\n } else {\r\n return;\r\n }\r\n }\r\n // get parent element.\r\n if (!!pHTMLParent) {\r\n _HTMLParent = pHTMLParent;\r\n } else {\r\n _HTMLParent = pScope.querySelector(`[data-list-container=\"${pPath}\"]`);\r\n if (!_HTMLParent) {\r\n return;\r\n }\r\n }\r\n //Clean property array name\r\n !pHTMLTemplate && !pHTMLParent && (pPath = '');\r\n\r\n for (let prop in pData) {\r\n if (Array.isArray(pData[prop])) {\r\n // descompe array elements.\r\n pData[prop].forEach(pData => this.loadDataList(pData, _HTMLTemplate, `${prop}`));\r\n } else if (typeof pData[prop] == 'object') {\r\n //descompose object\r\n !!pData[prop] && this.loadDataList(pData[prop], null, `${pPath}${prop}.`, _HTMLTemplate, _HTMLParent);\r\n } else if (typeof pData[prop] == 'string' || typeof pData[prop] == 'number' || typeof pData[prop] == 'boolean') {\r\n // process single properties\r\n !!_HTMLTemplate && (_HTMLField = _HTMLTemplate.querySelector(`[data-list-field-object=\"${pPath}${prop}\"]`));\r\n if (_HTMLField instanceof HTMLInputElement || _HTMLField instanceof HTMLTextAreaElement) {\r\n switch (_HTMLField.type) {\r\n case 'checkbox':\r\n _HTMLField.checked = !!pData[prop];\r\n break;\r\n case 'radio':\r\n _radioField = _HTMLTemplate.querySelector(`input[type=\"radio\"][name=\"${_HTMLField.name}\"][value=\"${pData[prop].toString().trim()}\"]`);\r\n !!_radioField && (_radioField.checked = true);\r\n break;\r\n case \"select-one\":\r\n case \"select-multiple\":\r\n [].slice.call(_HTMLField.options, 0).some(o => {\r\n return (o.value == pData[prop].toString().trim()) && (o.selected = true);\r\n });\r\n break;\r\n case 'file':\r\n _HTMLField.value = null;\r\n break;\r\n default:\r\n _HTMLField.value = pData[prop].toString().trim();\r\n }\r\n } else if (!!_HTMLField) {\r\n if (!!_HTMLField.dataset.listItemValue) {\r\n _HTMLField.dataset.listItemValue = pData[prop].toString().trim();\r\n } else {\r\n _HTMLField.innerText = pData[prop].toString().trim();\r\n }\r\n }\r\n }\r\n }\r\n // add template to the form.\r\n !pHTMLParent && !!_HTMLParent && (_HTMLParent.appendChild(_HTMLTemplate));\r\n }\r\n /**\r\n * TODO: implement AJAX functionality\r\n */\r\n SendDataByAjax(pFields) {\r\n console.log('sended data');\r\n }\r\n /**\r\n * process submit event\r\n * @param {Event} event event object\r\n * @returns \r\n */\r\n onSubmit(event) {\r\n if (!!this.confirmTxt) {\r\n // cancel flow if user abort operation.\r\n new PopUpConfirm_JS(this.ConfirmTxt, '', undefined, undefined, undefined, true).show(this.sendForm.bind(this));\r\n } else {\r\n // process to validate form and send.\r\n this.sendForm();\r\n }\r\n event.stopPropagation();\r\n event.preventDefault();\r\n return false;\r\n }\r\n}"," /**\r\n * Icon parameters.\r\n * @typedef {Object} ICON_PARAMS \r\n * @property {String} color CSS literal/rgb/rgba/hex/hls/hlsa value Icon Color.\r\n * @property {Number} width Icon svg width.\r\n * @property {Number} height Icon svg height.\r\n * @property {ICONS} IType Icon type.\r\n */\r\n\r\n /**\r\n * @class\r\n * Build a html div icon object.\r\n */\r\n class Icon_JS {\r\n /**\r\n * @constructor\r\n * @param {ICON_PARAMS} pOptions Icon_JS params.\r\n */\r\n constructor(pOptions) {\r\n /**\r\n * @type {ICON_PARAMS}\r\n */\r\n let objOptions = {\r\n color: '',\r\n width: 25,\r\n height: 25,\r\n IType: JFMUI_CONST.ICONS.INFO,\r\n }\r\n Object.assign(objOptions, pOptions);\r\n\r\n /**\r\n * CSS literal/rgb/rgba/hex/hls/hlsa value Icon Color.\r\n * @type {String}\r\n */\r\n this.Color = objOptions.color;\r\n /**\r\n * Icon svg width.\r\n * @type {Number}\r\n */\r\n this.Width = objOptions.width;\r\n /**\r\n * Icon svg height.\r\n * @type {Number}\r\n */\r\n this.Height = objOptions.height;\r\n /**\r\n * IType Icon type.\r\n * @type {ICONS}\r\n */\r\n this.IType = objOptions.IType;\r\n /**\r\n * SVG icon HTML.\r\n * @type {String}\r\n */\r\n this.IconSvg = '';\r\n \r\n //Initialize Icon.\r\n this.init();\r\n }\r\n /**\r\n * Generate the icon template according to @see {@link ICONS} IType property.\r\n */\r\n init() {\r\n let strColor = '',\r\n strIconSvg = '';\r\n\r\n switch (this.IType) {\r\n case JFMUI_CONST.ICONS.WARNING:\r\n strIconSvg = `\r\n \r\n `;\r\n strColor = '#664d03';\r\n break;\r\n case JFMUI_CONST.ICONS.DANGER:\r\n strIconSvg = `\r\n \r\n `;\r\n strColor = '#842029';\r\n break;\r\n case JFMUI_CONST.ICONS.INFO:\r\n strIconSvg = `\r\n \r\n `;\r\n strColor = '#084298';\r\n break;\r\n case JFMUI_CONST.ICONS.SUCCESS:\r\n strIconSvg = `\r\n \r\n `;\r\n strColor = '#0f5132';\r\n break;\r\n case JFMUI_CONST.ICONS.CONFIRM:\r\n strIconSvg = `\r\n \r\n `;\r\n strColor = '#084298';\r\n break;\r\n }\r\n\r\n this.Color = !this.Color ? strColor : this.Color;\r\n this.IconSvg = strIconSvg;\r\n }\r\n /**\r\n * Generate Icon HTML.\r\n * @public\r\n * @returns {HTMLDivElement}\r\n */\r\n generateIcon() {\r\n let objDIV = document.createElement('DIV');\r\n objDIV.style.color = this.Color;\r\n objDIV.classList.add('me-2');\r\n objDIV.insertAdjacentHTML('beforeend', this.IconSvg)\r\n return objDIV;\r\n }\r\n }","\r\n/**\r\n * @class\r\n * Interface of Loaders\r\n */\r\nclass Loader{\r\n\thideLoader(){\r\n\r\n\t}\r\n\tshowLoader(){\r\n\r\n\t}\r\n\tdispose(){\r\n\t\t\r\n\t}\r\n}\r\n\r\n/**\r\n * SpinLoader params\r\n * @typedef {Object} SPIN_OPTIONS\r\n * @property {string} id Box Loading Id.\r\n * @property {string} background CSS literal/rgb/rgba/hex/hls/hlsa box background.\r\n * @property {string} spinColor CSS literal/rgb/rgba/hex/hls/hlsa value. Color for the static wheel.\r\n * @property {string} animationColor CSS literal/rgb/rgba/hex/hls/hlsa value. Color for the spinning wheel.\r\n * @property {string} center true for center the spin.\r\n * @property {string} width CSS spin width value.\r\n * @property {string} height CSS spin width value.\r\n * @property {string} position CSS box position.\r\n * @property {string} prefixAnimation prefix for the keyframes animation.\r\n * @property {string} ParentSelector Parent Selector where the Box is appended to.\r\n */\r\n\r\n/**\r\n* Spin Loader.\r\n* @class\r\n*/\r\nclass SpinLoader extends Loader{\r\n\t/**\r\n\t * @constructor\r\n\t * @param {SPIN_OPTIONS} spin Loader options.\r\n\t */\r\n\tconstructor(pOptions) {\r\n\t\t// Default options.\r\n\t\tsuper();\r\n\t\tlet objOptions = {\r\n\t\t\tid: 'box_loader',\r\n\t\t\tbackground: 'rgba(255, 255, 255, 0.74)',\r\n\t\t\tspinColor: '#eee',\r\n\t\t\tanimationColor: '#122566',\r\n\t\t\tcenter: true,\r\n\t\t\twidth: '70px',\r\n\t\t\theight: '70px',\r\n\t\t\tposition: 'fixed',\r\n\t\t\tprefixAnimation: 'SpinLoader',\r\n\t\t\tParentSelector : 'body'\r\n\t\t}\r\n\t\tObject.assign(objOptions,pOptions);\r\n\r\n\t\tthis.ID = objOptions.id;\r\n\t\tthis.Background = objOptions.background;\r\n\t\tthis.SpinColor = objOptions.spinColor;\r\n\t\tthis.AnimationColor = objOptions.animationColor;\r\n\t\tthis.Center = objOptions.center;\r\n\t\tthis.Width = objOptions.width;\r\n\t\tthis.Height = objOptions.height;\r\n\t\tthis.Position = objOptions.position;\r\n\t\tthis.PrefixAnimation = objOptions.prefixAnimation.trim();\r\n\t\tthis.ParentSelector = objOptions.ParentSelector.trim();\r\n\r\n\t\tthis.init();\r\n\t}\r\n\t/** HTML box loader object.\r\n\t\t @type {HTMLDivElement} \r\n\t\t @public\r\n\t\t */\r\n\tget BoxLoader() {\r\n\t\treturn this._boxLoader;\r\n\t}\r\n\t/**\r\n\t * initialize box loading.\r\n\t */\r\n\tinit(){\r\n\t\t\r\n\t\tlet objStyle = document.createElement('STYLE'),\r\n\t\t\tobjDIVParent = document.createElement('DIV'),\r\n\t\t\tobjDIVChild = document.createElement('DIV'),\r\n\t\t\tobjContainer = document.querySelector(this.ParentSelector);\r\n\t\t\r\n\t\t//Build CSS animation\r\n\t\tobjStyle.type = 'text/css';\r\n\t\tobjStyle.innerText = `\r\n\t\t\t@keyframes ${this.PrefixAnimation}_AnimationSpinning { \r\n\t\t\t\tfrom { transform: rotate(0deg); } \r\n\t\t\t\tto { transform: rotate(360deg); } \r\n\t\t\t} \r\n\t\t\t@keyframes ${this.PrefixAnimation}_AnimationFadeIn { \r\n\t\t\t\t0% {opacity:0;} 100% {opacity:1;} \r\n\t\t\t} \r\n\t\t\t@keyframes ${this.PrefixAnimation}_AnimationFadeOut { \r\n\t\t\t\t0% {opacity:1;} 100% {opacity:0;} \r\n\t\t\t}`;\r\n\t\t//Build box\r\n\t\tobjDIVParent.id = this.ID;\r\n\t\tobjDIVParent.style.cssText = `\r\n\t\t\tposition: ${this.Position};\r\n\t\t\theight: 100%;\r\n\t\t\twidth: 100%;\r\n\t\t\tbackground: ${this.Background};\r\n\t\t\tz-index: 2147483647;\r\n\t\t\ttop:0;\r\n\t\t\tleft:0;\r\n\t\t\tdisplay:none;\r\n\t\t\t`;\r\n\t\t//Build spin\r\n\t\tobjDIVChild = document.createElement('DIV');\r\n\t\tobjDIVChild.style.cssText = `\r\n\t\t\t\tposition: ${this.Position};\r\n\t\t\t\tmargin:auto;\r\n\t\t\t\twidth: ${this.Width};\r\n\t\t\t\theight: ${this.Height};\r\n\t\t\t\tleft:0;\r\n\t\t\t\tright:0;\r\n\t\t\t\ttop:0;\r\n\t\t\t\tbottom:${this.Center ? '0' : '20%'};\r\n\t\t\t\tborder: 10px solid ${this.SpinColor};\r\n\t\t\t\tborder-top: 10px solid ${this.AnimationColor};\r\n\t\t\t\tborder-radius: 50%;\r\n\t\t\t\ttransform: translate(-50%, -50%);\r\n\t\t\t\tanimation-name: Gspinning;\r\n\t\t\t\tanimation: ${this.PrefixAnimation}_AnimationSpinning 1s infinite;\r\n\t\t\t\t\t\t\t`;\r\n\t\tobjDIVParent.appendChild(objStyle);\r\n\t\tobjDIVParent.appendChild(objDIVChild);\r\n\r\n\t\tobjDIVParent.addEventListener(\"animationend\", (evt) => {\r\n\t\t\tif (evt.animationName === `${this.PrefixAnimation}_AnimationFadeOut`) {\r\n\t\t\t\tobjDIVParent.style.display = \"none\";\r\n\t\t\t\tthis.dispose();\r\n\t\t\t}\r\n\t\t}, false);\r\n\r\n\t\t// set Box Loader\r\n\t\tif (!!objContainer) {\r\n\t\t\tobjContainer.appendChild(objDIVParent);\r\n\t\t\tthis._boxLoader = objDIVParent;\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tthrow new Error('Loader was not appended to parent Selector:' + this.ParentSelector);\r\n\t\t}\r\n\t}\r\n\t/**\r\n\t * Display Box Loader object.\r\n\t * @public\r\n\t * @param {string} pValue Display CSS style\r\n\t */\r\n\tdisplayBoxLoader(pSecondsInterval, pCSSValue) {\r\n\t\tif (pCSSValue == 'none') {\r\n\t\t\tthis.BoxLoader.style.animation = `${this.PrefixAnimation}_AnimationFadeOut ${pSecondsInterval}s linear`;\r\n\t\t}\r\n\t\telse {\r\n\t\t\tthis.BoxLoader.style.animation = `${this.PrefixAnimation}_AnimationFadeIn ${pSecondsInterval}s linear`;\r\n\t\t\tthis.BoxLoader.style.display = pCSSValue;\r\n\t\t}\r\n\t}\r\n\t/**\r\n\t * Hide Box Loader.\r\n\t * @public\r\n\t */\r\n\thideLoader(pSecondsInterval = 1, pCSSValue = 'none'){\r\n\t\tthis.displayBoxLoader(pSecondsInterval, pCSSValue);\r\n\t}\r\n\t/**\r\n\t * Show Box Loader.\r\n\t * @public\r\n\t */\r\n\t showLoader(pSecondsInterval = 0.85, pCSSValue = 'block'){\r\n\t\tthis.displayBoxLoader(pSecondsInterval, pCSSValue);\r\n\t}\r\n\t/**\r\n\t * Destroy Loader.\r\n\t */\r\n\tdispose(){\r\n\t\tthis.BoxLoader.remove();\r\n\t\tthis._boxLoader = null;\r\n\t}\r\n}","/**\r\n * @class\r\n * Show A PopUp Alert Dialog.\r\n */\r\nclass PopUpAlerts_JS {\r\n /**\r\n * @constructor\r\n * @param {String} pMessage Body HTML Message.\r\n * @param {String} pTitle Title for the modal.\r\n * @param {ICONS} pIconType Icon Type.\r\n * @param {String} ptxtCancelBtn text for the cancel button.\r\n * @param {String} pIDModal PopUp ID.\r\n * @param {Boolean} pSetSmallText True For smallText.\r\n */\r\n constructor(pMessage = '', pTitle = '', pIconType = JFMUI_CONST.ICONS.INFO, ptxtCancelBtn = 'Cerrar', pIDModal = 'Alert', pSetSmallText = false) {\r\n /**\r\n * Modal Id.\r\n * @type {String}\r\n * @public\r\n */\r\n this.IDModal = `PopUp_${pIDModal}`;\r\n /**\r\n * Icon object.\r\n * @type {Icon_JS}\r\n * @public\r\n */\r\n this.Icon = new Icon_JS({\r\n IType: pIconType,\r\n width: 50,\r\n height: 50\r\n });\r\n /**\r\n * Modal Template.\r\n * @type {string}\r\n * @public\r\n */\r\n this.Template =\r\n \"\";\r\n /**\r\n * Cancel Button text\r\n * @type {string}\r\n * @public\r\n */\r\n this.TxtCancelBtn = ptxtCancelBtn;\r\n /**\r\n * Modal Title.\r\n * @type {string}\r\n * @public\r\n */\r\n this.Title = pTitle;\r\n /**\r\n * Body HTML message.\r\n * @type {string}\r\n * @public\r\n */\r\n this.BodyMessage = pMessage;\r\n /**\r\n * Set small text.\r\n * @type {Boolean}\r\n * @public\r\n */\r\n this.SetSmallText = pSetSmallText;\r\n /**\r\n * Modal HTML.\r\n * @type {HTMLDivElement}\r\n * @public\r\n */\r\n this.ModalHTML = null;\r\n // Initialize Modal.\r\n this.init();\r\n }\r\n /**\r\n * Initialize PopUp Modal.\r\n * @private\r\n */\r\n init() {\r\n //Update HTML Modal.\r\n this.updateTemplate(this.Template);\r\n //Insert content to the model.\r\n this.refresh();\r\n }\r\n /**\r\n * Update HTML Modal Template.\r\n * @param {String} pTemplate New HTML template.\r\n */\r\n updateTemplate(pTemplate) {\r\n //Update Template\r\n this.Template = pTemplate;\r\n // Create DocumentFragment from text template.\r\n this.ModalHTML = DOM_Utility.createHTMLFromString(pTemplate);\r\n\r\n if (!this.ModalHTML) {\r\n throw new Error(`Invalid Template content: ${this.Template}`);\r\n }\r\n }\r\n /**\r\n * Refresh the dialog elements\r\n * */\r\n refresh() {\r\n let objTitle = this.ModalHTML.querySelector('.modal-title'),\r\n objModalBodyIcon = this.ModalHTML.querySelector('.modal-icon'),\r\n objBodyMessage = this.ModalHTML.querySelector('.modal-message'),\r\n objBtnFooter = this.ModalHTML.querySelector('.modal-footer > .closeBtn');\r\n\r\n //assing ID selector.\r\n this.ModalHTML.id = this.IDModal;\r\n\r\n //Set content\r\n !!objTitle && (objTitle.innerHTML = this.Title);\r\n !!objBodyMessage && (objBodyMessage.innerHTML = this.BodyMessage);\r\n //Style text\r\n if (this.SetSmallText) {\r\n !!objBodyMessage && objBodyMessage.classList.add('fs-6');\r\n !!objBtnFooter && objBtnFooter.classList.add('btn-sm');\r\n !!objTitle && objTitle.classList.add('fs-6');\r\n this.Icon.Height = 30;\r\n this.Icon.Width = 30;\r\n this.Icon.init();\r\n }\r\n // Add Icon\r\n !!objModalBodyIcon && (objModalBodyIcon.innerHTML = this.Icon.generateIcon().outerHTML);\r\n // Update close text\r\n !!objBtnFooter && (objBtnFooter.innerHTML = this.TxtCancelBtn);\r\n }\r\n /**\r\n * Show PopUp Alert.\r\n */\r\n show() {\r\n this.refresh();\r\n this.showPopUpAlert();\r\n }\r\n /**\r\n * Show Modal Pop Up Alert\r\n * @returns {bootstrap.Modal} Modal control\r\n */\r\n showPopUpAlert() {\r\n let objThis = this,\r\n bootstrapModal = null;\r\n //Add Modal to the DOM.\r\n document.body.appendChild(this.ModalHTML);\r\n // Build bootstrap.Modal\r\n bootstrapModal = new bootstrap.Modal(this.ModalHTML, {\r\n backdrop: 'static'\r\n })\r\n bootstrapModal.show(); // show the dialog\r\n\r\n // on close Modal event\r\n this.ModalHTML.addEventListener('hidden.bs.modal', function (event) {\r\n objThis.ModalHTML.remove();\r\n });\r\n\r\n return bootstrapModal;\r\n }\r\n}\r\n/**\r\n * @class\r\n * Show A PopUp Confirm Modal.\r\n * @augments PopUpAlerts_JS\r\n */\r\nclass PopUpConfirm_JS extends PopUpAlerts_JS {\r\n /**\r\n * @param {String} pMessage Body HTML Message.\r\n * @param {String} pTitle Title for the modal.\r\n * @param {String} ptxtOKBtn Text for the OK button.\r\n * @param {String} ptxtCancelBtn text for the cancel button.\r\n * @param {String} pIDModal PopUp ID.\r\n * @param {Boolean} pSetSmallText True For smallText.\r\n * @constructor\r\n */\r\n constructor(pMessage = '', pTitle = '', ptxtOKBtn = 'Aceptar', ptxtCancelBtn = 'Cancelar', pIDModal = 'PopUpConfirm', pSetSmallText = false) {\r\n super(pMessage, pTitle, JFMUI_CONST.ICONS.CONFIRM, ptxtCancelBtn, pIDModal, pSetSmallText);\r\n /**\r\n * Text for the OK button.\r\n * @type {string}\r\n * @public\r\n */\r\n this.TxtOKBtn = ptxtOKBtn;\r\n /**\r\n * Template for the OK button.\r\n * @type {string}\r\n * @public\r\n */\r\n this.ButtonOKTemplate = \"\";\r\n this.initModal();\r\n }\r\n /**\r\n * Initialize Modal\r\n */\r\n initModal() {\r\n this.updateTemplateConfirm(this.Template);\r\n this.refreshConfirm();\r\n }\r\n /**\r\n * Update template\r\n * @param {String} pTemplate \r\n */\r\n updateTemplateConfirm(pTemplate) {\r\n\r\n this.updateTemplate(pTemplate);\r\n\r\n let objFooter = this.ModalHTML.querySelector('.modal-footer'),\r\n objOkBtn = this.ModalHTML.querySelector('.modal-footer > .OkBtn'),\r\n objCancelBtn = this.ModalHTML.querySelector('.modal-footer > .closeBtn');\r\n\r\n if (!objOkBtn) {\r\n !!objFooter && objFooter.insertAdjacentHTML('afterbegin', this.ButtonOKTemplate);\r\n }\r\n\r\n !!objFooter && (objFooter.classList.remove('justify-content-around'), objFooter.classList.add('justify-content-end'));\r\n !!objCancelBtn && (objCancelBtn.classList.remove('btn-danger'), objCancelBtn.classList.add('btn-outline-danger'));\r\n }\r\n /**\r\n * Refresh Confirm text message.\r\n */\r\n refreshConfirm() {\r\n this.refresh();\r\n let objBtnOk = this.ModalHTML.querySelector('.modal-footer > .OkBtn');\r\n\r\n //Style text\r\n if (this.SetSmallText) {\r\n !!objBtnOk && objBtnOk.classList.add('btn-sm');\r\n }\r\n // Update text\r\n !!objBtnOk && (objBtnOk.innerHTML = this.TxtOKBtn);\r\n }\r\n /**\r\n * Show PopUp Confirm Modal\r\n * @param {Function} pFnCallback On click in Button OK, execute pFnCallback.\r\n * @returns {bootstrap.Modal}\r\n * @private\r\n */\r\n showPopUpConfirm(pFnCallback) {\r\n let bootstrapModal = super.showPopUpAlert(), // show the dialog through the father\r\n objBtnOk = this.ModalHTML.querySelector('.modal-footer > .OkBtn');\r\n !!objBtnOk && objBtnOk.addEventListener('click', function (event) {\r\n pFnCallback(event);\r\n });\r\n return bootstrapModal;\r\n }\r\n /**\r\n * Show PopUp Confirm Modal\r\n * @param {Function} pFnCallback On click in Button OK, execute pFnCallback.\r\n * @returns {bootstrap.Modal}\r\n * @public\r\n */\r\n show(pFnCallback) {\r\n //refresh Confirm Modal text message.\r\n this.refreshConfirm();\r\n return this.showPopUpConfirm(pFnCallback);\r\n }\r\n}","\r\n/**\r\n * July 2022\r\n * @file User Interface constants.\r\n * @author Jorge Flores Miguel \r\n * @version 1.1.1.001\r\n */\r\n\r\n/**\r\n * Icon type for alert messages.\r\n * @typedef {Object} ICONS\r\n * @property {string} INFO Informative icon.\r\n * @property {string} WARNING Exclamation mark.\r\n * @property {string} DANGER x Symbol.\r\n * @property {string} SUCCESS Check mark.\r\n * @property {string} CONFIRM Question mark.\r\n */\r\n\r\n/**\r\n * Constant values for UI use.\r\n * @typedef {Object} UI_CONSTANTS\r\n * @property {ICONS} ICONS Icon type for alert messages.\r\n */\r\n\r\n/**\r\n * Several constant values for general porpuse\r\n * @type {UI_CONSTANTS}\r\n * @constant\r\n */\r\nconst JFMUI_CONST = {\r\n ICONS: {\r\n INFO: 'INFO',\r\n WARNING: 'WARNING',\r\n DANGER: 'DANGER',\r\n SUCCESS: 'SUCCESS',\r\n CONFIRM: 'CONFIRM'\r\n }\r\n};\r\n\r\n\r\n"]}