novo-elements
Version:
1 lines • 422 kB
Source Map (JSON)
{"version":3,"file":"novo-elements-elements-form.mjs","sources":["../../../projects/novo-elements/src/elements/form/FormValidators.ts","../../../projects/novo-elements/src/elements/form/controls/BaseControl.ts","../../../projects/novo-elements/src/elements/form/controls/address/AddressControl.ts","../../../projects/novo-elements/src/elements/form/controls/check-list/CheckListControl.ts","../../../projects/novo-elements/src/elements/form/controls/checkbox/CheckboxControl.ts","../../../projects/novo-elements/src/elements/form/controls/code-editor/CodeEditorControl.ts","../../../projects/novo-elements/src/elements/form/controls/custom/CustomControl.ts","../../../projects/novo-elements/src/elements/form/controls/date/DateControl.ts","../../../projects/novo-elements/src/elements/form/controls/date-time/DateTimeControl.ts","../../../projects/novo-elements/src/elements/form/controls/editor/EditorControl.ts","../../../projects/novo-elements/src/elements/form/controls/file/FileControl.ts","../../../projects/novo-elements/src/elements/form/controls/grouped/GroupedControl.ts","../../../projects/novo-elements/src/elements/form/controls/native-select/NativeSelectControl.ts","../../../projects/novo-elements/src/elements/form/controls/picker/PickerControl.ts","../../../projects/novo-elements/src/elements/form/controls/quick-note/QuickNoteControl.ts","../../../projects/novo-elements/src/elements/form/controls/radio/RadioControl.ts","../../../projects/novo-elements/src/elements/form/controls/read-only/ReadOnlyControl.ts","../../../projects/novo-elements/src/elements/form/controls/select/SelectControl.ts","../../../projects/novo-elements/src/elements/form/controls/switch/SwitchControl.ts","../../../projects/novo-elements/src/elements/form/controls/text-area/TextAreaControl.ts","../../../projects/novo-elements/src/elements/form/controls/textbox/TextBoxControl.ts","../../../projects/novo-elements/src/elements/form/controls/tiles/TilesControl.ts","../../../projects/novo-elements/src/elements/form/controls/time/TimeControl.ts","../../../projects/novo-elements/src/elements/form/controls/timezone/TimezoneControl.ts","../../../projects/novo-elements/src/elements/form/controls/ControlFactory.ts","../../../projects/novo-elements/src/elements/form/NovoFormControl.ts","../../../projects/novo-elements/src/elements/form/NovoFormGroup.ts","../../../projects/novo-elements/src/elements/form/utils/FormUtils.ts","../../../projects/novo-elements/src/elements/form/FieldInteractionModals.ts","../../../projects/novo-elements/src/elements/form/FieldInteractionApi.ts","../../../projects/novo-elements/src/elements/form/Control.ts","../../../projects/novo-elements/src/elements/form/ControlGroup.ts","../../../projects/novo-elements/src/elements/form/ControlGroup.html","../../../projects/novo-elements/src/elements/form/extras/address/Address.ts","../../../projects/novo-elements/src/elements/form/extras/file/extras/file/File.ts","../../../projects/novo-elements/src/elements/form/extras/file/FileInput.ts","../../../projects/novo-elements/src/elements/form/extras/file/FileInput.html","../../../projects/novo-elements/src/elements/form/ControlTemplates.ts","../../../projects/novo-elements/src/elements/form/DynamicForm.ts","../../../projects/novo-elements/src/elements/form/extras/number-range/number-range.component.ts","../../../projects/novo-elements/src/elements/form/extras/FormExtras.module.ts","../../../projects/novo-elements/src/elements/form/Form.ts","../../../projects/novo-elements/src/elements/form/Form.module.ts","../../../projects/novo-elements/src/elements/form/novo-elements-elements-form.ts"],"sourcesContent":["import { Helpers } from 'novo-elements/utils';\n\nconst MAX_INTEGER = 2147483647;\nconst MIN_YEAR = 1753;\n\nexport class FormValidators {\n private showStateRequiredFlag(subfield, control): boolean {\n return (\n subfield === 'state' &&\n !Helpers.isEmpty(control.config.state) &&\n control.config.state.required &&\n Helpers.isBlank(control.value.state) &&\n control.config.state.updated &&\n !Helpers.isBlank(control.value.countryName) &&\n control.config.state.pickerConfig &&\n control.config.state.pickerConfig.defaultOptions &&\n control.config.state.pickerConfig.defaultOptions.length > 0\n );\n }\n\n // Makes sure the control value does not exceed the max integer value\n static maxInteger(control) {\n return control.value < MAX_INTEGER ? null : { integerTooLarge: true };\n }\n\n // Makes sure the control value is above the minimum year\n static minYear(control) {\n if (!control.value) {\n return null;\n }\n return control.value >= MIN_YEAR ? null : { minYear: true };\n }\n\n // Makes sure the control value does not exceed the max number value\n static maxDouble(control) {\n return control.value < Number.MAX_SAFE_INTEGER ? null : { doubleTooLarge: true };\n }\n\n // Make sure the control value is an email\n static isEmail(control) {\n const EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;\n return !control.value || EMAIL_REGEXP.test(control.value) ? null : { invalidEmail: true };\n }\n // Makes sure the control value is a valid address\n static isValidAddress(control) {\n const fieldList: string[] = ['address1', 'address2', 'city', 'state', 'zip', 'countryID'];\n const invalidAddressFields: string[] = [];\n const maxlengthFields: string[] = [];\n let returnVal: {\n invalidAddress?: boolean;\n invalidAddressFields?: string[];\n invalidAddressForForm?: boolean;\n maxlength?: boolean;\n maxlengthFields?: string[];\n } = null;\n let maxlengthError: boolean = false;\n const showCountryRequiredFlag = (subfield, ctrl) => {\n return (\n subfield === 'countryID' &&\n !Helpers.isEmpty(ctrl.config.countryID) &&\n ctrl.config.countryID.required &&\n Helpers.isBlank(ctrl.value.countryName) &&\n ctrl.config.countryID.updated\n );\n };\n\n const showStateRequiredFlag = (subfield, ctrl): boolean => {\n return (\n subfield === 'state' &&\n !Helpers.isEmpty(ctrl.config.state) &&\n ctrl.config.state.required &&\n Helpers.isBlank(ctrl.value.state) &&\n ctrl.config.state.updated &&\n !Helpers.isBlank(ctrl.value.countryName) &&\n ctrl.config.state.pickerConfig &&\n ctrl.config.state.pickerConfig.defaultOptions &&\n ctrl.config.state.pickerConfig.defaultOptions.length > 0\n );\n };\n\n if (control.value && control.config) {\n let valid = true;\n let formValidity = true;\n fieldList.forEach((subfield: string) => {\n if (!Helpers.isEmpty(control.config[subfield])) {\n if (\n (['countryID', 'state'].indexOf(subfield) === -1 &&\n control.config[subfield].required &&\n !Helpers.isBlank(control.value[subfield]) &&\n Helpers.isEmpty(control.value[subfield])) ||\n showCountryRequiredFlag(subfield, control) ||\n showStateRequiredFlag(subfield, control)\n ) {\n valid = false;\n invalidAddressFields.push(control.config[subfield].label);\n }\n if (\n ((subfield !== 'countryID' && control.config[subfield].required && Helpers.isEmpty(control.value[subfield])) ||\n (subfield === 'countryID' &&\n !Helpers.isEmpty(control.config.countryID) &&\n control.config.countryID.required &&\n Helpers.isEmpty(control.value.countryName))) &&\n !(\n subfield === 'state' &&\n !Helpers.isBlank(control.value.countryName) &&\n control.config.state.pickerConfig &&\n control.config.state.pickerConfig.defaultOptions &&\n control.config.state.pickerConfig.defaultOptions.length === 0\n )\n ) {\n formValidity = false;\n }\n if (\n !Helpers.isEmpty(control.config[subfield].maxlength) &&\n !Helpers.isEmpty(control.value[subfield]) &&\n control.value[subfield].length > control.config[subfield].maxlength\n ) {\n maxlengthError = true;\n maxlengthFields.push(subfield);\n formValidity = false;\n }\n }\n });\n if (!valid || !formValidity || maxlengthError) {\n returnVal = {};\n }\n if (!valid) {\n returnVal.invalidAddress = true;\n returnVal.invalidAddressFields = invalidAddressFields;\n }\n if (!formValidity) {\n returnVal.invalidAddressForForm = true;\n }\n if (maxlengthError) {\n returnVal.maxlength = true;\n returnVal.maxlengthFields = maxlengthFields;\n }\n return returnVal;\n }\n return null;\n }\n}\n","// NG2\nimport { EventEmitter } from '@angular/core';\nimport { Validators } from '@angular/forms';\n// APP\nimport { Helpers, notify } from 'novo-elements/utils';\nimport type { IMaskOptions } from '../Control';\nimport type { NovoControlGroupAddConfig } from '../ControlGroup';\n\nexport interface NovoGroupedControlConfig {\n label?: string;\n icon?: string;\n add?: NovoControlGroupAddConfig;\n remove?: boolean;\n key: string;\n initialValue?: {}[];\n}\n\nclass ControlConfig {\n alwaysActive?: Boolean;\n allowInvalidDate?: boolean;\n appendToBody: boolean; // Deprecated;\n associatedEntity: string;\n asyncValidators?: Array<any>;\n checkboxLabel: string;\n closeOnSelect: boolean;\n config: any;\n controlType: string;\n currencyFormat: string;\n customControl?: any;\n customControlConfig?: any;\n dataSpecialization: string;\n dataType: string;\n dateFormat?: string;\n description?: string;\n dirty: boolean;\n disabled: boolean;\n enabled: boolean;\n encrypted: boolean;\n endDate?: Date | Number;\n fileBrowserImageUploadUrl?: string;\n forceClear: EventEmitter<any>;\n headerConfig: any;\n hidden: boolean;\n interactions: Array<{ event?: 'change' | 'focus' | string; invokeOnInit?: boolean; script? }>;\n isEmpty?: Function;\n key: string;\n label: string;\n maskOptions?: IMaskOptions;\n maxlength: number;\n metaType: string;\n military?: boolean;\n minimal?: boolean;\n minlength: number;\n multiple: boolean;\n name: string;\n options: Array<any>;\n optionsType: string;\n parentScrollSelector: string;\n placeholder: string;\n popoverAlways?: boolean;\n popoverAnimation?: boolean;\n popoverContent?: string;\n popoverDisabled?: boolean;\n popoverDismissTimeout?: number;\n popoverHtmlContent?: string;\n popoverOnHover?: boolean;\n popoverPlacement?: 'left' | 'right' | 'top' | 'bottom';\n popoverTitle?: string;\n readOnly: boolean; // \"disabled\", so it appears in the model still;\n removeTooltipArrow?: boolean;\n required: boolean;\n restrictFieldInteractions?: boolean;\n sortOrder: number;\n startDate?: Date | Number;\n startupFocus?: boolean;\n subType?: string;\n template?: any;\n textMaskEnabled?: boolean;\n tooltip?: string;\n tooltipAutoPosition?: boolean;\n tooltipPosition?: string;\n tooltipPreline?: boolean;\n tooltipSize?: string;\n type: string;\n validators: Array<any>;\n value: any;\n warning?: string;\n width: number;\n layoutOptions?: {\n customActions?: boolean;\n download?: boolean;\n draggable?: boolean;\n edit?: boolean;\n iconStyle?: string;\n labelStyle?: string;\n order?: string;\n removable?: boolean;\n customValidation?: { action: string; fn: Function }[];\n removableWhenNew?: boolean;\n };\n tipWell?: {\n button?: boolean;\n icon?: string;\n tip: string;\n };\n isEmbedded = false;\n isInlineEmbedded = false;\n weekStart?: number;\n highlighted = false;\n disabledDateMessage?: string;\n}\n\nexport type NovoControlConfig = Partial<ControlConfig>;\n\nexport class BaseControl extends ControlConfig {\n __type: string = 'BaseControl';\n __config: NovoControlConfig;\n\n constructor(type: string = 'BaseControl', config: NovoControlConfig = {}) {\n super();\n this.__type = type;\n this.__config = config;\n this.alwaysActive = config.alwaysActive;\n this.validators = config.validators || [];\n this.asyncValidators = config.asyncValidators || [];\n this.value = config.value;\n this.key = config.key || '';\n this.label = config.label || '';\n this.checkboxLabel = config.checkboxLabel;\n this.name = config.name || '';\n this.required = !!config.required;\n this.hidden = !!config.hidden;\n this.encrypted = !!config.encrypted;\n this.sortOrder = config.sortOrder === undefined ? 1 : config.sortOrder;\n this.controlType = config.controlType || '';\n this.type = config.type;\n this.subType = config.subType;\n this.metaType = config.metaType;\n this.placeholder = config.placeholder || '';\n this.config = config.config || null;\n this.dirty = !!(config.value !== undefined && config.value !== null);\n this.multiple = !!config.multiple;\n this.headerConfig = config.headerConfig || null;\n this.currencyFormat = config.currencyFormat || null;\n this.associatedEntity = config.associatedEntity || null;\n this.optionsType = config.optionsType || null;\n this.options = config.options || [];\n this.forceClear = new EventEmitter();\n this.readOnly = !!config.readOnly || !!config.disabled;\n this.disabled = !!config.disabled;\n this.enabled = true;\n this.layoutOptions = config.layoutOptions || {};\n this.military = !!config.military;\n this.dateFormat = config.dateFormat;\n this.textMaskEnabled = config.textMaskEnabled;\n this.maskOptions = config.maskOptions;\n this.allowInvalidDate = config.allowInvalidDate;\n this.startDate = config.startDate;\n this.endDate = config.endDate;\n this.restrictFieldInteractions = !!config.restrictFieldInteractions;\n this.highlighted = !!config.highlighted;\n if (!Helpers.isEmpty(config.warning)) {\n this.warning = config.warning;\n }\n\n if (this.required) {\n this.validators.push(Validators.required);\n }\n if (!Helpers.isBlank(config.maxlength)) {\n this.maxlength = config.maxlength;\n this.validators.push(Validators.maxLength(this.maxlength));\n }\n if (!Helpers.isBlank(config.minlength)) {\n this.minlength = config.minlength;\n this.validators.push(Validators.minLength(this.minlength));\n }\n this.closeOnSelect = !!config.closeOnSelect;\n this.interactions = config.interactions;\n this.dataSpecialization = config.dataSpecialization;\n this.dataType = config.dataType;\n this.appendToBody = !!config.appendToBody;\n if (this.appendToBody) {\n notify('\\'appendToBody\\' has been deprecated. Please remove this attribute.');\n }\n this.parentScrollSelector = config.parentScrollSelector;\n this.description = config.description;\n if (config.tooltip) {\n this.tooltip = config.tooltip;\n this.tooltipPosition = config.tooltipPosition;\n this.tooltipSize = config.tooltipSize;\n this.tooltipPreline = config.tooltipPreline;\n this.removeTooltipArrow = config.removeTooltipArrow;\n this.tooltipAutoPosition = config.tooltipAutoPosition;\n }\n this.popoverAlways = config.popoverAlways;\n this.popoverAnimation = config.popoverAnimation;\n this.popoverContent = config.popoverContent;\n this.popoverDisabled = config.popoverDisabled;\n this.popoverDismissTimeout = config.popoverDismissTimeout;\n this.popoverHtmlContent = config.popoverHtmlContent;\n this.popoverOnHover = config.popoverOnHover;\n this.popoverPlacement = config.popoverPlacement;\n this.popoverTitle = config.popoverTitle;\n this.template = config.template;\n this.customControlConfig = config.customControlConfig;\n this.tipWell = config.tipWell;\n this.width = config.width;\n this.startupFocus = !!config.startupFocus;\n if (config.fileBrowserImageUploadUrl) {\n this.fileBrowserImageUploadUrl = config.fileBrowserImageUploadUrl;\n }\n if (config.isEmpty) {\n this.isEmpty = config.isEmpty;\n }\n this.weekStart = config.weekStart || 0;\n this.disabledDateMessage = config.disabledDateMessage;\n }\n}\n","// APP\nimport { FormValidators } from '../../FormValidators';\nimport { BaseControl, NovoControlConfig } from '../BaseControl';\n\nexport class AddressControl extends BaseControl {\n controlType = 'address';\n\n constructor(config: NovoControlConfig) {\n super('AddressControl', config);\n this.validators.push(FormValidators.isValidAddress);\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class CheckListControl extends BaseControl {\n controlType = 'checklist';\n\n constructor(config: NovoControlConfig) {\n super('CheckListControl', config);\n this.options = config.options || [];\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class CheckboxControl extends BaseControl {\n controlType = 'checkbox';\n\n constructor(config: NovoControlConfig) {\n super('CheckboxControl', config);\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from '../BaseControl';\n\nexport class CodeEditorControl extends BaseControl {\n controlType = 'code-editor';\n\n constructor(config: NovoControlConfig) {\n super('CodeEditorControl', config);\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class CustomControl extends BaseControl {\n controlType = 'custom';\n\n constructor(config: NovoControlConfig) {\n super(config.template, config);\n this.controlType = config.template;\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class DateControl extends BaseControl {\n controlType = 'date';\n\n constructor(config: NovoControlConfig) {\n super('DateControl', config);\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class DateTimeControl extends BaseControl {\n controlType = 'date-time';\n\n constructor(config: NovoControlConfig) {\n super('DateTimeControl', config);\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class EditorControl extends BaseControl {\n controlType = 'editor';\n minimal: boolean = false;\n\n constructor(config: NovoControlConfig) {\n super('EditorControl', config);\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class FileControl extends BaseControl {\n controlType = 'file';\n\n constructor(config: NovoControlConfig) {\n super('FileControl', config);\n // TODO - translate\n this.placeholder = config.placeholder;\n this.multiple = config.multiple;\n }\n}\n","// APP\nimport { NovoGroupedControlConfig } from './../BaseControl';\n\nexport class GroupedControl implements NovoGroupedControlConfig {\n public __type: string;\n key: string;\n\n constructor(config: NovoGroupedControlConfig) {\n this.__type = 'GroupedControl';\n Object.keys(config).forEach((key) => (this[key] = config[key]));\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class NativeSelectControl extends BaseControl {\n controlType = 'native-select';\n options = [];\n\n constructor(config: NovoControlConfig) {\n super('NativeSelectControl', config);\n this.options = config.options || [];\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class PickerControl extends BaseControl {\n controlType = 'picker';\n options = [];\n\n constructor(config: NovoControlConfig) {\n super('PickerControl', config);\n this.options = config.options || [];\n }\n}\n\nexport class TablePickerControl extends PickerControl {\n constructor(config: NovoControlConfig) {\n super(Object.assign(config, { parentScrollSelector: '.table-container' }));\n this.__type = 'TablePickerControl';\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from '../BaseControl';\n\nexport class QuickNoteControl extends BaseControl {\n controlType = 'quick-note';\n options = [];\n\n constructor(config: NovoControlConfig) {\n super('QuickNoteControl', config);\n this.options = config.options || [];\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class RadioControl extends BaseControl {\n controlType = 'radio';\n options = [];\n\n constructor(config: NovoControlConfig) {\n super('RadioControl', config);\n this.options = config.options || [];\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class ReadOnlyControl extends BaseControl {\n controlType = 'read-only';\n\n constructor(config: NovoControlConfig) {\n super('ReadOnlyControl', config);\n config.readOnly = true;\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class SelectControl extends BaseControl {\n controlType = 'select';\n options = [];\n\n constructor(config: NovoControlConfig) {\n super('SelectControl', config);\n this.options = config.options || [];\n this.placeholder = config.placeholder || '';\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from '../BaseControl';\n\nexport class SwitchControl extends BaseControl {\n controlType = 'switch';\n\n constructor(config: NovoControlConfig) {\n super('SwitchControl', config);\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class TextAreaControl extends BaseControl {\n controlType = 'text-area';\n\n constructor(config: NovoControlConfig) {\n super('TextAreaControl', config);\n }\n}\n","// APP\nimport { FormValidators } from './../../FormValidators';\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class TextBoxControl extends BaseControl {\n controlType: string = 'textbox';\n type: string;\n subType: string;\n\n constructor(config: NovoControlConfig) {\n super('TextBoxControl', config);\n this.type = this.getTextboxType(config.type) || '';\n this.subType = config.type || '';\n this.setValidators(this.subType);\n }\n\n setValidators(type) {\n switch (type) {\n case 'email':\n this.validators.push(FormValidators.isEmail);\n break;\n case 'number':\n case 'currency':\n this.validators.push(FormValidators.maxInteger);\n break;\n case 'float':\n case 'percentage':\n this.validators.push(FormValidators.maxDouble);\n break;\n case 'year':\n this.validators.push(FormValidators.minYear);\n break;\n default:\n break;\n }\n }\n\n getTextboxType(type) {\n switch (type) {\n case 'percentage':\n case 'currency':\n case 'float':\n case 'year':\n return 'number';\n default:\n return type;\n }\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class TilesControl extends BaseControl {\n controlType = 'tiles';\n options = [];\n\n constructor(config: NovoControlConfig) {\n super('TilesControl', config);\n this.options = config.options || [];\n }\n}\n","// APP\nimport { BaseControl, NovoControlConfig } from './../BaseControl';\n\nexport class TimeControl extends BaseControl {\n controlType = 'time';\n\n constructor(config: NovoControlConfig) {\n super('TimeControl', config);\n }\n}\n","// APP\nimport { findTimeZone, getZonedTime, listTimeZones } from 'timezone-support';\nimport { formatZonedTime } from 'novo-elements/utils';\nimport { BaseControl, NovoControlConfig } from '../BaseControl';\n\nexport class TimezoneControl extends BaseControl {\n controlType = 'timezone';\n options = [];\n\n constructor(config: NovoControlConfig) {\n super('TimezoneControl', config);\n this.options = this.buildTimezones(new Date());\n this.placeholder = config.placeholder || '';\n // current timezone\n const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;\n this.value = tz;\n }\n\n private buildTimezones = (compareDate: Date) => {\n const timezones = listTimeZones()\n .map((zone) => {\n const timezone = findTimeZone(zone);\n const zonedTime = getZonedTime(compareDate, timezone);\n const formatted = formatZonedTime(zonedTime, `z - [${zone}] ([GMT] Z)`).replace('_', ' ');\n\n const option = {\n value: zone,\n label: formatted,\n offset: zonedTime.zone.offset,\n };\n return option;\n })\n // Formats 'noisy' timezones without a letter acronym.\n .map((option) => {\n const rgx = /(^(\\+|-)\\d+\\s- )/;\n const matches = option.label.match(rgx);\n if (matches) {\n const prefix = matches[0];\n option.label = option.label.split(prefix)[1];\n }\n return option;\n })\n // Sorts W -> E, prioritizes america. could be more nuanced based on system tz but simple for now\n .sort((a, b) => {\n const offsetDelta = b.offset - a.offset;\n if (offsetDelta !== 0) {\n return offsetDelta;\n }\n if (a.label < b.label) {\n return -1;\n }\n if (a.label > b.label) {\n return 1;\n }\n return 0;\n });\n return timezones;\n };\n}\n","import { BaseControl } from './BaseControl';\nimport {\n AddressControl,\n CheckboxControl,\n CheckListControl,\n DateTimeControl,\n EditorControl,\n FileControl,\n NativeSelectControl,\n PickerControl,\n QuickNoteControl,\n RadioControl,\n ReadOnlyControl,\n SelectControl,\n SwitchControl,\n TablePickerControl,\n TextAreaControl,\n TextBoxControl,\n TilesControl,\n TimeControl,\n} from './index';\n\nexport class ControlFactory {\n static create(type: string, config: BaseControl): BaseControl {\n switch (type) {\n case 'AddressControl':\n return new AddressControl(config);\n case 'CheckboxControl':\n return new CheckboxControl(config);\n case 'CheckListControl':\n return new CheckListControl(config);\n case 'DateTimeControl':\n return new DateTimeControl(config);\n case 'EditorControl':\n return new EditorControl(config);\n case 'FileControl':\n return new FileControl(config);\n case 'NativeSelectControl':\n return new NativeSelectControl(config);\n case 'PickerControl':\n return new PickerControl(config);\n case 'TablePickerControl':\n return new TablePickerControl(config);\n case 'QuickNoteControl':\n return new QuickNoteControl(config);\n case 'RadioControl':\n return new RadioControl(config);\n case 'ReadOnlyControl':\n return new ReadOnlyControl(config);\n case 'TextAreaControl':\n return new TextAreaControl(config);\n case 'TextBoxControl':\n return new TextBoxControl(config);\n case 'SelectControl':\n return new SelectControl(config);\n case 'SwitchControl':\n return new SwitchControl(config);\n case 'TilesControl':\n return new TilesControl(config);\n case 'TimeControl':\n return new TimeControl(config);\n default:\n console.warn(\n '[ControlFactory] - unable to find control for type. Make sure to set \"editorType\" and \"editorConfig\" on your column',\n type,\n );\n return null;\n }\n }\n}\n","// NG2\nimport { EventEmitter } from '@angular/core';\nimport { FormControl, Validators } from '@angular/forms';\nimport { notify } from 'novo-elements/utils';\nimport type { IMaskOptions } from './Control';\n// APP\nimport { NovoControlConfig } from './FormControls';\n\nexport class NovoFormControl extends FormControl {\n displayValueChanges: EventEmitter<any> = new EventEmitter<any>();\n hidden: boolean;\n encrypted: boolean;\n key: string;\n required: boolean;\n readOnly: boolean;\n hasRequiredValidator: boolean;\n label: string;\n tooltip: string;\n tooltipPosition: string;\n tooltipSize?: string;\n tooltipPreline?: boolean;\n tooltipIsHTML?: boolean;\n popoverContent?: string;\n popoverHtmlContent?: string;\n popoverTitle?: string;\n popoverPlacement?: 'left' | 'right' | 'top' | 'bottom';\n popoverOnHover?: boolean;\n popoverAlways?: boolean;\n popoverDisabled?: boolean;\n popoverAnimation?: boolean;\n popoverDismissTimeout?: number;\n removeTooltipArrow?: boolean;\n tooltipAutoPosition?: boolean;\n initialValue: any;\n valueHistory = [];\n validators: any;\n config: any;\n sortOrder: number;\n controlType: string;\n placeholder: string;\n minimal: boolean;\n multiple: boolean;\n headerConfig: any;\n optionsType: string;\n maxlength: number;\n minlength: number;\n options: Array<any>;\n type: string;\n subType: string;\n name: string;\n closeOnSelect: boolean;\n interactions: Array<Object>;\n appendToBody: boolean; // Deprecated\n parentScrollSelector: string;\n description?: string;\n layoutOptions?: { order?: string; download?: boolean; labelStyle?: string; draggable?: boolean; iconStyle?: string };\n military?: boolean;\n dateFormat?: string;\n currencyFormat?: string;\n startDate?: Date | Number;\n endDate?: Date | Number;\n weekStart?: number;\n textMaskEnabled?: boolean;\n maskOptions: IMaskOptions;\n allowInvalidDate?: boolean;\n tipWell?: {\n tip: string;\n icon?: string;\n button?: boolean;\n sanitize?: boolean;\n };\n rawValue?: any;\n customControlConfig?: any;\n checkboxLabel?: string;\n restrictFieldInteractions?: boolean;\n warning?: string;\n highlighted?: boolean;\n disabledDateMessage?: string;\n private historyTimeout: any;\n\n constructor(value: any, control: NovoControlConfig) {\n super(value, control.validators, control.asyncValidators);\n this.validators = control.validators;\n this.initialValue = value;\n this.valueHistory.push(value);\n this.key = control.key;\n this.label = control.label;\n this.readOnly = control.readOnly;\n this.hidden = control.hidden;\n this.encrypted = control.encrypted;\n this.config = control.config;\n this.type = control.type;\n this.subType = control.subType;\n this.required = control.required;\n this.hasRequiredValidator = this.required;\n this.tooltip = control.tooltip;\n this.tooltipPosition = control.tooltipPosition;\n this.tooltipSize = control.tooltipSize;\n this.tooltipPreline = control.tooltipPreline;\n this.removeTooltipArrow = control.removeTooltipArrow;\n this.tooltipAutoPosition = control.tooltipAutoPosition;\n this.label = control.label;\n this.name = control.name;\n this.required = control.required;\n this.sortOrder = control.sortOrder;\n this.controlType = control.controlType;\n this.placeholder = control.placeholder;\n this.minimal = control.minimal;\n this.multiple = control.multiple;\n this.headerConfig = control.headerConfig;\n this.optionsType = control.optionsType;\n this.readOnly = control.readOnly;\n this.layoutOptions = control.layoutOptions;\n this.military = control.military;\n this.dateFormat = control.dateFormat;\n this.currencyFormat = control.currencyFormat;\n this.startDate = control.startDate;\n this.endDate = control.endDate;\n this.weekStart = control.weekStart;\n this.textMaskEnabled = control.textMaskEnabled;\n this.maskOptions = control.maskOptions;\n this.allowInvalidDate = control.allowInvalidDate;\n this.maxlength = control.maxlength;\n this.minlength = control.minlength;\n this.closeOnSelect = control.closeOnSelect;\n this.interactions = control.interactions;\n this.checkboxLabel = control.checkboxLabel;\n this.restrictFieldInteractions = control.restrictFieldInteractions;\n this.appendToBody = control.appendToBody;\n if (this.appendToBody) {\n notify('\\'appendToBody\\' has been deprecated. Please remove this attribute.');\n }\n this.parentScrollSelector = control.parentScrollSelector;\n this.description = control.description;\n this.options = control.options;\n this.tipWell = control.tipWell;\n this.customControlConfig = control.customControlConfig;\n this.warning = control.warning;\n this.disabledDateMessage = control.disabledDateMessage;\n\n // Reactive Form, need to enable/disable, can't bind to [disabled]\n if (this.readOnly) {\n this.disable();\n } else {\n this.enable();\n }\n }\n\n /**\n * @param clearValue - flag to reset the control's value\n */\n hide(clearValue: boolean = true): void {\n this.hidden = true;\n if (clearValue) {\n this.setValue(null);\n }\n }\n\n show(): void {\n this.hidden = false;\n }\n\n setRequired(isRequired: boolean): void {\n this.required = isRequired;\n // Update validators to have the required\n if (this.required && !this.hasRequiredValidator) {\n const validators: any = [...this.validators];\n validators.push(Validators.required);\n // TODO: duplicated below\n this.setValidators(validators);\n this.updateValueAndValidity({ emitEvent: false });\n this.hasRequiredValidator = this.required;\n } else if (!this.required && this.hasRequiredValidator) {\n let validators: any = [...this.validators];\n validators = validators.filter((val) => val !== Validators.required);\n // TODO: duplicated above\n this.setValidators(validators);\n this.updateValueAndValidity({ emitEvent: false });\n this.hasRequiredValidator = this.required;\n }\n }\n\n setValue(\n value: any,\n {\n onlySelf,\n emitEvent,\n emitModelToViewChange,\n emitViewToModelChange,\n }: {\n onlySelf?: boolean;\n emitEvent?: boolean;\n emitModelToViewChange?: boolean;\n emitViewToModelChange?: boolean;\n } = {},\n ) {\n this.markAsDirty();\n this.markAsTouched();\n this.displayValueChanges.emit(value);\n super.setValue(value, { onlySelf, emitEvent, emitModelToViewChange, emitViewToModelChange });\n\n // History\n clearTimeout(this.historyTimeout);\n this.historyTimeout = setTimeout(() => {\n this.valueHistory.push(value);\n }, 300);\n }\n\n setReadOnly(isReadOnly: boolean): void {\n this.readOnly = isReadOnly;\n if (this.readOnly) {\n this.disable();\n } else {\n this.enable();\n }\n }\n\n /**\n * Disables the control. This means the control will be exempt from validation checks and\n * excluded from the aggregate value of any parent. Its status is `DISABLED`.\n *\n * If the control has children, all children will be disabled to maintain the model.\n */\n disable(opts: { onlySelf?: boolean; emitEvent?: boolean } = { emitEvent: false }): void {\n if (typeof opts.emitEvent === 'undefined') {\n opts.emitEvent = false;\n }\n super.disable(opts);\n }\n\n enable(opts: { onlySelf?: boolean; emitEvent?: boolean } = { emitEvent: false }): void {\n if (typeof opts.emitEvent === 'undefined') {\n opts.emitEvent = false;\n }\n super.enable(opts);\n }\n\n markAsInvalid(message: string): void {\n this.markAsDirty();\n this.markAsTouched();\n this.setErrors(Object.assign({}, this.errors, { custom: message }));\n }\n\n markAsValid(): void {\n this.setErrors(null);\n }\n}\n","// NG\nimport { EventEmitter } from '@angular/core';\nimport { UntypedFormGroup } from '@angular/forms';\n// App\nimport { IFieldInteractionEvent } from './FormInterfaces';\nimport { NovoFormControl } from './NovoFormControl';\n\nexport class NovoFormGroup extends UntypedFormGroup {\n public fieldInteractionEvents: EventEmitter<IFieldInteractionEvent> = new EventEmitter();\n public layout: string;\n public edit: boolean;\n public currentEntity: string;\n public currentEntityId: string;\n public associations: object;\n public fieldsets: any[];\n public _value: any;\n public controls: { [key: string]: any };\n public novoControls: any[];\n\n public enableAllControls(): void {\n for (const key in this.controls) {\n if ((this.controls[key] as NovoFormControl).readOnly) {\n (this.controls[key] as NovoFormControl).readOnly = false;\n this.controls[key].enable();\n }\n }\n }\n\n public disableAllControls(): void {\n for (const key in this.controls) {\n if (!(this.controls[key] as NovoFormControl).readOnly) {\n (this.controls[key] as NovoFormControl).readOnly = true;\n this.controls[key].disable();\n }\n }\n }\n}\n","// NG\nimport { Injectable } from '@angular/core';\n// Vendor\nimport { startOfToday } from 'date-fns';\n// App\nimport {\n AddressControl,\n BaseControl,\n CheckboxControl,\n CheckListControl,\n CustomControl,\n DateControl,\n DateTimeControl,\n EditorControl,\n FileControl,\n NovoControlConfig,\n PickerControl,\n RadioControl,\n SelectControl,\n SwitchControl,\n TextAreaControl,\n TextBoxControl,\n TilesControl,\n TimeControl,\n TimezoneControl,\n} from '../FormControls';\nimport type { FormField, NovoFieldset } from '../FormInterfaces';\nimport { NovoFormControl } from '../NovoFormControl';\nimport { NovoFormGroup } from '../NovoFormGroup';\nimport { EntityPickerResult, EntityPickerResults } from 'novo-elements/elements/picker';\nimport { NovoLabelService, OptionsService } from 'novo-elements/services';\nimport { DateUtil, Helpers } from 'novo-elements/utils';\n\n@Injectable()\nexport class FormUtils {\n ASSOCIATED_ENTITY_LIST: string[] = [\n 'Candidate',\n 'ClientContact',\n 'ClientCorporation',\n 'CorporationDepartment',\n 'Lead',\n 'Opportunity',\n 'JobOrder',\n 'CorporateUser',\n 'Person',\n 'Placement',\n 'JobShift',\n ];\n ENTITY_PICKER_LIST: string[] = [\n 'Candidate',\n 'CandidateText',\n 'Client',\n 'ClientText',\n 'ClientContact',\n 'ClientContactText',\n 'ClientCorporation',\n 'ClientCorporationText',\n 'Lead',\n 'LeadText',\n 'Opportunity',\n 'OpportunityText',\n 'JobOrder',\n 'JobOrderText',\n 'CorporateUser',\n 'CorporateUserText',\n 'Person',\n 'PersonText',\n 'Placement',\n 'JobShift',\n ];\n\n constructor(public labels: NovoLabelService, public optionsService: OptionsService) {}\n\n toFormGroup(controls: Array<any>): NovoFormGroup {\n const group: any = {};\n controls.forEach((control) => {\n const value = Helpers.isBlank(control.value) ? '' : control.value;\n group[control.key] = new NovoFormControl(value, control);\n });\n return new NovoFormGroup(group);\n }\n\n emptyFormGroup(): NovoFormGroup {\n return new NovoFormGroup({});\n }\n\n addControls(formGroup: NovoFormGroup, controls: Array<NovoControlConfig>): void {\n controls.forEach((control) => {\n const value = Helpers.isBlank(control.value) ? '' : control.value;\n const formControl = new NovoFormControl(value, control);\n formGroup.addControl(control.key, formControl);\n });\n }\n\n removeControls(formGroup: NovoFormGroup, controls: Array<NovoControlConfig>): void {\n controls.forEach((control) => {\n formGroup.removeControl(control.key);\n });\n }\n\n toFormGroupFromFieldset(fieldsets: Array<NovoFieldset>): NovoFormGroup {\n const controls: Array<NovoFormControl> = [];\n fieldsets.forEach((fieldset) => {\n controls.push(...fieldset.controls);\n });\n return this.toFormGroup(controls);\n }\n\n hasAssociatedEntity(field: FormField): boolean {\n return !!(field.associatedEntity && ~this.ASSOCIATED_ENTITY_LIST.indexOf(field.associatedEntity.entity));\n }\n\n determineInputType(field: FormField): string {\n let type: string;\n const dataSpecializationTypeMap = {\n DATETIME: 'datetime',\n TIME: 'time',\n MONEY: 'currency',\n PERCENTAGE: 'percentage',\n HTML: 'editor',\n 'HTML-MINIMAL': 'editor-minimal',\n YEAR: 'year',\n WORKFLOW_OPTIONS: 'select',\n SPECIALIZED_OPTIONS: 'select',\n ALL_WORKFLOW_OPTIONS: 'select',\n WorkflowOptionsLookup: 'select',\n SpecializedOptionsLookup: 'select',\n SimplifiedOptionsLookup: 'select',\n AllWorkflowOptionsLookup: 'select',\n };\n const dataTypeToTypeMap = {\n Timestamp: 'date',\n Date: 'date',\n Boolean: 'tiles', // eslint-disable-line\n };\n const inputTypeToTypeMap = {\n CHECKBOX: 'radio',\n RADIO: 'radio',\n SELECT: 'select',\n TILES: 'tiles',\n };\n const inputTypeMultiToTypeMap = {\n CHECKBOX: 'checklist',\n RADIO: 'checklist',\n SELECT: 'chips',\n };\n const typeToTypeMap = {\n file: 'file',\n COMPOSITE: 'address',\n };\n const numberDataTypeToTypeMap = {\n Double: 'float',\n BigDecimal: 'float',\n Integer: 'number',\n };\n if (field.type === 'TO_MANY') {\n if (this.hasAssociatedEntity(field)) {\n if (field.multiValue === false) {\n type = 'entitypicker';\n } else {\n type = 'entitychips';\n }\n } else {\n if (field.multiValue === false) {\n type = 'picker';\n } else {\n type = 'chips';\n }\n }\n } else if (field.type === 'TO_ONE') {\n if (\n 'SYSTEM' === field.dataSpecialization &&\n ['WorkflowOptionsLookup', 'SpecializedOptionsLookup', 'AllWorkflowOptionsLookup'].includes(field.dataType)\n ) {\n type = dataSpecializationTypeMap[field.dataType];\n } else if (['WORKFLOW_OPTIONS', 'SPECIALIZED_OPTIONS', 'ALL_WORKFLOW_OPTIONS'].includes(field.dataSpecialization)) {\n type = dataSpecializationTypeMap[field.dataSpecialization];\n } else if (['SimplifiedOptionsLookup', 'SpecializedOptionsLookup'].includes(field.dataType)) {\n if (field.options && Object.keys(inputTypeToTypeMap).indexOf(field.inputType) > -1 && !field.multiValue) {\n type = inputTypeToTypeMap[field.inputType];\n } else if (field.options && Object.keys(inputTypeMultiToTypeMap).indexOf(field.inputType) > -1 && field.multiValue) {\n type = inputTypeMultiToTypeMap[field.inputType];\n } else {\n type = dataSpecializationTypeMap[field.dataType];\n }\n } else if (this.hasAssociatedEntity(field)) {\n type = 'entitypicker'; // TODO!\n } else {\n type = 'picker';\n }\n } else if (field.optionsUrl && field.inputType === 'SELECT') {\n if (field.optionsType && ~this.ENTITY_PICKER_LIST.indexOf(field.optionsType)) {\n type = 'entitypicker'; // TODO!\n } else {\n type = 'picker';\n }\n } else if (Object.keys(dataSpecializationTypeMap).indexOf(field.dataSpecialization) > -1) {\n type = dataSpecializationTypeMap[field.dataSpecialization];\n } else if (Object.keys(dataTypeToTypeMap).indexOf(field.dataType) > -1) {\n type = dataTypeToTypeMap[field.dataType];\n } else if (field.inputType === 'TEXTAREA') {\n type = 'textarea';\n } else if (field.options && Object.keys(inputTypeToTypeMap).indexOf(field.inputType) > -1 && !field.multiValue) {\n type = inputTypeToTypeMap[field.inputType];\n } else if (field.options && Object.keys(inputTypeMultiToTypeMap).indexOf(field.inputType) > -1 && field.multiValue) {\n type = inputTypeMultiToTypeMap[field.inputType];\n } else if (Object.keys(typeToTypeMap).indexOf(field.type) > -1) {\n type = typeToTypeMap[field.type];\n } else if (Object.keys(numberDataTypeToTypeMap).indexOf(field.dataType) > -1) {\n type = numberDataTypeToTypeMap[field.dataType];\n } /* else {\n throw new Error('FormUtils: This field type is unsupported.');\n }*/\n return type;\n }\n\n isFieldEncrypted(key: string): boolean {\n return key.indexOf('customEncrypted') > -1;\n }\n\n getControlForField(\n field: any,\n http,\n config: { token?: string; restUrl?: string; military?: boolean; weekStart?: number },\n overrides?: any,\n forTable: boolean = false,\n fieldData?: any,\n ) {\n // TODO: if field.type overrides `determineInputType` we should use it in that method or use this method\n // TODO: (cont.) as the setter of the field argument\n let type: string = this.determineInputType(field) || field.type;\n let control: any;\n const controlConfig: NovoControlConfig = {\n metaType: field.type,\n type,\n key: field.name,\n label: field.label,\n placeholder: field.hint || '',\n required: field.required || field.systemRequired,\n hidden: !field.required,\n encrypted: this.isFieldEncrypted(field.name ? field.name.toString() : ''),\n value: field.value || field.defaultValue,\n sortOrder: field.sortOrder,\n associatedEntity: field.associatedEntity,\n optionsType: field.optionsType,\n multiple: field.multiValue,\n readOnly: !!field.disabled || !!field.readOnly,\n disabled: field.disabled,\n maxlength: field.maxLength,\n interactions: field.interactions,\n dataSpecialization: field.dataSpecialization,\n dataType: field.dataType,\n description: field.description || '',\n tooltip: field.tooltip,\n tooltipPosition: field.tooltipPosition,\n customControl: field.customControl,\n template: field.template,\n customControlConfig: field.customControlConfig,\n restrictFieldInteractions: field.restrictFieldInteractions,\n validators: field.validators,\n warning: field.warning,\n config: field.config || {},\n closeOnSelect: field.closeOnSelect,\n layoutOptions: field.layoutOptions,\n };\n this.inferDateRange(controlConfig, field);\n // TODO: getControlOptions should always return the correct format\n const optionsConfig = this.getControlOptions(field, http, config, fieldData);\n if (Array.isArray(optionsConfig) && !(type === 'chips' || type === 'picker')) {\n controlConfig.options = optionsConfig;\n } else if (Array.isArray(optionsConfig) && (type === 'chips' || type === 'picker')) {\n controlConfig.config = {\n options: optionsConfig,\n };\n } else if (optionsConfig) {\n controlConfig.config = {\n ...optionsConfig,\n ...(controlConfig && controlConfig.config),\n };\n }\n\n if (type === 'year') {\n controlConfig.maxlength = 4;\n }\n // TODO: Overrides should be an iterable of all properties (potentially a private method)\n let overrideResultsTemplate;\n let overridePreviewTemplate;\n if (overrides && overrides[field.name]) {\n if (overrides[field.name].resultsTemplate) {\n overrideResultsTemplate = overrides[field.name].resultsTemplate;\n controlConfig.config.resultsTemplate = overrideResultsTemplate;\n delete overrides[field.name].resultsTemplate;\n }\n if (overrides[field.name].overridePreviewTemplate) {\n overrideResultsTemplate = overrides[field.name].overridePreviewTemplate;\n controlConfig.config.overridePreviewTemplate = overrideResultsTemplate;\n delete overrides[field.name].overridePreviewTemplate;\n }\n if (overrides[field.name].pickerCallback) {\n controlConfig.config.callback = overrides[field.name].pickerCallback;\n }\n if (overrides[field.name].type) {\n type = overrides[field.name].type;\n }\n if (overrides[field.name].columns) {\n controlConfig.config.columns = overrides[field.name].columns;\n controlConfig.closeOnSelect = true;\n delete controlConfig.label;\n }\n if (overrides[field.name].warning) {\n controlConfig.warning = overrides[field.name].warning;\n }\n Object.assign(controlConfig, overrides[field.name]);\n }\n\n switch (type) {\n case 'entitychips':\n // TODO: This doesn't belong in this codebase\n controlConfig.multiple = true;\n controlConfig.config.resultsTemplate = overrideResultsTemplate || EntityPickerResults;\n controlConfig.config.previewTemplate = overridePreviewTemplate || EntityPickerResult;\n // TODO: When appendToBody picker works better in table/form\n control = new PickerControl(controlConfig);\n break;\n case 'chips':\n controlConfig.multiple = true;\n // TODO: When appendToBody picker works better in table/form\n control = new PickerControl(controlConfig);\n break;\n case 'entitypicker':\n // TODO: This doesn't belong in this codebase\n controlConfig.config.resultsTemplate = overrideResultsTemplate || EntityPickerResults;\n // TODO: When appendToBody picker works better in table/form\n control = new PickerControl(controlConfig);\n break;\n case 'picker':\n // TODO: When appendToBody picker works better in table/form\n control = new PickerControl(controlConfig);\n break;\n case 'datetime':\n controlConfig.military = config ? !!config.military : false;\n controlConfig.weekStart = config && config.weekStart ? config.weekStart : 0;\n control = new DateTimeControl(controlConfig);\n break;\n case 'date':\n controlConfig.dateFormat = field.dateFormat;\n controlConfig.textMaskEnabled = field.textMaskEnabled;\n controlConfig.allowInvalidDate = field.allowInvalidDate;\n controlConfig.military = config ? !!config.military : false;\n controlConfig.weekStart = config && config.weekStart ? config.weekStart : 0;\n control = new DateControl(controlConfig);\n break;\n case 'time':\n con