"use strict";
/**
* InputItem holds input DOM and takes care of its validation using QueryValidator.
*/
class InputItem extends CommonFormMethods {
/**
* Create InputItemWrapper.
* @param {QueryDataBlock} queryData - An instance of QueryData.
* @param {number} index - Order index of the input item in a query.
*/
constructor(queryData, index) {
if(!queryData) {
throw new InputItemException("No data passed when creating a new instance of InputItemException");
}
if(!queryData instanceof QueryDataBlock) {
throw new InputItemException("Data passed when creating new instance of InputItemException were not an instance of a QueryDataBlock");
}
super();
this.queryData = queryData;
this.index = index;
this.internalValue = {
assignedOptions: [],
text: "",
checked: false
}
this.valid = true;
this.associateCheckRule();
return this;
}
/**
* Creates InputItem DOM representation.
* @return {InputItem} - This instance.
*/
createInput() {
this.dom = document.createElement("input");
this.dom.classList.add("dt-section-container-input", "dt-section-container-input-type-" + this.queryData.type);
if(this.queryData.direction) {
this.dom.classList.add(this.queryData.direction);
}
this.dom.setAttribute("type", this.queryData.inputType);
this.dom.setAttribute("id", this.htmlId);
this.dom.setAttribute("name", this.name);
if(this.queryData.type) {
if(this.queryData.type === "order" || this.queryData.type === "assign") {
this.restrictWriteAccess = true;
}
}
if(!this.standsAlone) {
if(this.queryData.properInputType) {
if(this.queryData.properInputType === "radio" || this.queryData.properInputType === "checkbox") {
this.dom.setAttribute("value", this.currentSubItem.id);
}
}
CommonFormFunctions.appendStyle(this.dom, this.currentSubItem.css);
}
if(this.queryData.required) {
this.dom.setAttribute("required", "");
}
return this;
}
/**
* Associtate this InputItem with QueryValidator for its future validation.
* Directly refferences to the QueryDataBlock's QueryValidator for this item.
* @return {InputItem} - This instance.
*/
associateCheckRule() {
this.currentSubItem.queryValidator.itemToValidate = this;
return this;
}
/**
* Set if this InputItem's dom input is user editable.
* @param {boolean} readOnly - Of true the input item won't be user editable - usable eg. on value assign queries.
*/
set restrictWriteAccess(readOnly) {
var readOnly = readOnly || false;
this.dom.readOnly = readOnly;
}
/**
* Validate data in this InputItem's DOM input = using adequate QueryValidator.
* @return {InputItem} - This instance.
*/
validate() {
if(this.dom) {
this.valid = this.currentSubItem.queryValidator.validate();
this.setValid();
}
return this.valid;
}
/**
* Get all input item values, either the one typed in or all the assigned options.
* @return {string[]} - An array containing all assigned values or a single inserted text value.
*/
get value() {
if(this.internalValue.assignedOptions && this.internalValue.assignedOptions.length > 0) {
this.orderAssignedOptions();
var optionIds = [];
for(var i = 0; i < this.internalValue.assignedOptions.length; i++) {
optionIds.push(this.internalValue.assignedOptions[i].scope.validatorMatch);
}
return optionIds;
}
this.internalValue.text = this.dom.value;
this.internalValue.checked = this.dom.checked;
return this.internalValue.text ? [this.internalValue.text] : [];
}
/**
* Returns obect with detailed information about this InputItem.
* @return {Object} - {name:string - input item's name, label:string - input item's label or name if no label defined, values:string[], internalValue:string[] - assigned option's text, valid: boolean}
*/
get inputData() {
var options = [];
for(var i = 0; i < this.internalValue.assignedOptions.length; i++) {
options.push(this.internalValue.assignedOptions[i].scope.text);
}
return {
name: this.name,
label: this.currentSubItem.label || this.name,
values: this.value,
internalValue: options,
valid: this.valid,
checked: this.dom.checked
};
}
/**
* Assign OptionItem to this instance of InputItem.
* @param {OptionItem} option - The OptionItem instance.
*/
set option(option) {
var optionIndex = this.internalValue.assignedOptions.indexOf(option);
if(optionIndex === -1) {
this.internalValue.assignedOptions.push(option);
}
}
/**
* Remove OptionItem from this instance of InputItem.
* @return {InputItem} - This instance.
*/
deleteOption(option) {
var optionIndex = this.internalValue.assignedOptions.indexOf(option);
if(optionIndex > -1) {
this.internalValue.assignedOptions.splice(optionIndex, 1);
}
return this;
}
/**
* Order OptionItems in InputItem by their position rather than the order they were dragged in (reorder).
* Depends on Query direction value - "vertical" or "horizontal" - if no match found fallbacks to "horizontal".
* @return {OptionItem[]} - Ordered Option items.
*/
orderAssignedOptions() {
for(let i = 0; i < this.internalValue.assignedOptions.length; i++) {
this.internalValue.assignedOptions[i].updatePosition();
}
if(this.internalValue.assignedOptions && this.internalValue.assignedOptions.length > 1 && this.queryData.direction) {
if(this.queryData.direction === "horizontal") {
this.internalValue.assignedOptions.sort(function(a, b) {
return a.position.left - b.position.left;
});
}
else {
this.internalValue.assignedOptions.sort(function(a, b) {
return a.position.top - b.position.top;
});
}
}
return this.internalValue.assignedOptions;
}
/**
* Modify InputItem DOM input value based on current this.internalValue.assignedOptions state.
* @return {InputItem} - This instance.
*/
changeAssignedOptionsValue() {
var finalValue = "";
if(this.internalValue.assignedOptions && this.internalValue.assignedOptions.length > 0) {
let ordered = this.orderAssignedOptions();
for(var i = 0; i < ordered.length; i++) {
finalValue += (i > 0 ? "&" : "") + ordered[i].scope.id;
}
}
this.dom.value = finalValue;
return this;
}
/**
* Adds attribute with a value to InputItem's DOM input, like: <tagname attribute="value">.
* @param {string} attribute - The name of the attribute.
* @param {string} value - The value of the attribute.
* @return {InputItem} - This instance.
*/
setAttribute(attribute, value) {
if(attribute != null && value != null) {
this.dom.setAttribute(attribute, value);
}
return this;
};
/**
* Changes this InputItem DOM input class based on the validity.
* @param {bollean} [overwriteGraphicsTo] - If set to true, the InputItem will be force-set to valid.
* @return {InputItem} - This instance.
*/
setValid(overwriteGraphicsTo) {
if(this.valid || overwriteGraphicsTo == true) {
this.dom.classList.remove("invalid");
}
else {
this.dom.classList.add("invalid");
}
return this;
}
/**
* InputItem ValueChange event - call function on value change.
* @param {function} callback - The function that should be executed on input's value change.
* @return {InputItem} - This instance.
*/
onInputValueChange(callback) {
this.dom.addEventListener("change", () => {
callback();
this.setValid(true);
});
return this;
}
}
/**
* Exception block for InputItem
* @see {@link https://developer.mozilla.org/cs/docs/Web/JavaScript/Reference/Statements/throw|MDN Throw Statement}
* @param {Object} message - Exception message Object.
* @param {string} message.message - Message text.
*/
function InputItemException(message) {
this.message = message;
this.name = "InputItem";
}