Merge branch 'new-vc-line-element' of brutus.artica.lan:artica/pandorafms into new-vc-line-element
This commit is contained in:
commit
09817311eb
|
@ -187,18 +187,19 @@ class Item extends CachedModel
|
|||
protected function decode(array $data): array
|
||||
{
|
||||
$decodedData = [
|
||||
'id' => (int) $data['id'],
|
||||
'type' => (int) $data['type'],
|
||||
'label' => static::extractLabel($data),
|
||||
'labelPosition' => static::extractLabelPosition($data),
|
||||
'isLinkEnabled' => static::extractIsLinkEnabled($data),
|
||||
'isOnTop' => static::extractIsOnTop($data),
|
||||
'parentId' => static::extractParentId($data),
|
||||
'aclGroupId' => static::extractAclGroupId($data),
|
||||
'width' => (int) $data['width'],
|
||||
'height' => (int) $data['height'],
|
||||
'x' => static::extractX($data),
|
||||
'y' => static::extractY($data),
|
||||
'id' => (int) $data['id'],
|
||||
'type' => (int) $data['type'],
|
||||
'label' => static::extractLabel($data),
|
||||
'labelPosition' => static::extractLabelPosition($data),
|
||||
'isLinkEnabled' => static::extractIsLinkEnabled($data),
|
||||
'isOnTop' => static::extractIsOnTop($data),
|
||||
'parentId' => static::extractParentId($data),
|
||||
'aclGroupId' => static::extractAclGroupId($data),
|
||||
'width' => (int) $data['width'],
|
||||
'height' => (int) $data['height'],
|
||||
'x' => static::extractX($data),
|
||||
'y' => static::extractY($data),
|
||||
'cacheExpiration' => static::extractCacheExpiration($data),
|
||||
];
|
||||
|
||||
if (static::$useLinkedModule === true) {
|
||||
|
@ -434,6 +435,28 @@ class Item extends CachedModel
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the cache expiration value.
|
||||
*
|
||||
* @param array $data Unknown input data structure.
|
||||
*
|
||||
* @return integer Cache expiration time.
|
||||
*/
|
||||
private static function extractCacheExpiration(array $data)
|
||||
{
|
||||
return static::parseIntOr(
|
||||
static::issetInArray(
|
||||
$data,
|
||||
[
|
||||
'cacheExpiration',
|
||||
'cache_expiration',
|
||||
]
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract an module Id value.
|
||||
*
|
||||
|
@ -1254,6 +1277,9 @@ class Item extends CachedModel
|
|||
|
||||
|
||||
/**
|
||||
* TODO: CRITICAL. This function contains values which belong to its
|
||||
* subclasses. This function should be overrided there to add them.
|
||||
*
|
||||
* Return a valid representation of a record in database.
|
||||
*
|
||||
* @param array $data Input data.
|
||||
|
@ -1568,18 +1594,9 @@ class Item extends CachedModel
|
|||
$result['show_last_value'] = $show_last_value;
|
||||
}
|
||||
|
||||
$cache_expiration = static::parseIntOr(
|
||||
static::issetInArray(
|
||||
$data,
|
||||
[
|
||||
'cache_expiration',
|
||||
'cacheExpiration',
|
||||
]
|
||||
),
|
||||
null
|
||||
);
|
||||
if ($cache_expiration !== null) {
|
||||
$result['cache_expiration'] = $cache_expiration;
|
||||
$cacheExpiration = static::extractCacheExpiration($data);
|
||||
if ($cacheExpiration !== null) {
|
||||
$result['cache_expiration'] = $cacheExpiration;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
|
|
@ -19,7 +19,8 @@ import {
|
|||
debounce,
|
||||
addResizementListener,
|
||||
t,
|
||||
helpTip
|
||||
helpTip,
|
||||
periodSelector
|
||||
} from "./lib";
|
||||
import TypedEvent, { Listener, Disposable } from "./lib/TypedEvent";
|
||||
import { FormContainer, InputGroup } from "./Form";
|
||||
|
@ -66,6 +67,7 @@ export interface ItemProps extends Position, Size {
|
|||
isOnTop: boolean;
|
||||
parentId: number | null;
|
||||
aclGroupId: number | null;
|
||||
cacheExpiration: number | null;
|
||||
}
|
||||
|
||||
export interface ItemClickEvent {
|
||||
|
@ -355,6 +357,33 @@ class AclGroupInputGroup extends InputGroup<Partial<ItemProps>> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
class CacheExpirationInputGroup extends InputGroup<Partial<ItemProps>> {
|
||||
protected createContent(): HTMLElement | HTMLElement[] {
|
||||
const periodLabel = document.createElement("label");
|
||||
periodLabel.textContent = t("Cache expiration");
|
||||
|
||||
const periodControl = periodSelector(
|
||||
this.currentData.cacheExpiration || this.initialData.cacheExpiration || 0,
|
||||
{ text: t("No cache"), value: 0 },
|
||||
[
|
||||
{ text: t("10 seconds"), value: 10 },
|
||||
{ text: t("30 seconds"), value: 30 },
|
||||
{ text: t("60 seconds"), value: 60 },
|
||||
{ text: t("5 minutes"), value: 300 },
|
||||
{ text: t("15 minutes"), value: 900 },
|
||||
{ text: t("30 minutes"), value: 1800 },
|
||||
{ text: t("1 hour"), value: 3600 }
|
||||
],
|
||||
value => this.updateData({ cacheExpiration: value })
|
||||
);
|
||||
|
||||
periodLabel.appendChild(periodControl);
|
||||
|
||||
return periodLabel;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to add item to the general items form
|
||||
* This item consists of a label and a color type select.
|
||||
|
@ -910,6 +939,7 @@ export function itemBasePropsDecoder(data: AnyObject): ItemProps | never {
|
|||
isOnTop: parseBoolean(data.isOnTop),
|
||||
parentId: parseIntOr(data.parentId, null),
|
||||
aclGroupId: parseIntOr(data.aclGroupId, null),
|
||||
cacheExpiration: parseIntOr(data.cacheExpiration, null),
|
||||
...sizePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
|
||||
...positionPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
|
||||
};
|
||||
|
@ -1766,9 +1796,18 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
|||
new LinkInputGroup("link", this.props),
|
||||
new OnTopInputGroup("show-on-top", this.props),
|
||||
new ParentInputGroup("parent", this.props),
|
||||
new AclGroupInputGroup("acl-group", this.props)
|
||||
new AclGroupInputGroup("acl-group", this.props),
|
||||
new CacheExpirationInputGroup("cache-expiration", this.props)
|
||||
],
|
||||
["position", "size", "link", "show-on-top", "parent", "acl-group"]
|
||||
[
|
||||
"position",
|
||||
"size",
|
||||
"link",
|
||||
"show-on-top",
|
||||
"parent",
|
||||
"acl-group",
|
||||
"cache-expiration"
|
||||
]
|
||||
);
|
||||
|
||||
//return VisualConsoleItem.getFormContainer(this.props);
|
||||
|
@ -1784,9 +1823,18 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
|||
new LinkInputGroup("link", props),
|
||||
new OnTopInputGroup("show-on-top", props),
|
||||
new ParentInputGroup("parent", props),
|
||||
new AclGroupInputGroup("acl-group", props)
|
||||
new AclGroupInputGroup("acl-group", props),
|
||||
new CacheExpirationInputGroup("cache-expiration", props)
|
||||
],
|
||||
["position", "size", "link", "show-on-top", "parent", "acl-group"]
|
||||
[
|
||||
"position",
|
||||
"size",
|
||||
"link",
|
||||
"show-on-top",
|
||||
"parent",
|
||||
"acl-group",
|
||||
"cache-expiration"
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ interface ExtraProps {
|
|||
const fontAwesomeIcon = (
|
||||
iconDefinition: IconDefinition,
|
||||
title: string,
|
||||
{ size, color, spin, pulse }: ExtraProps
|
||||
{ size, color, spin, pulse }: ExtraProps = {}
|
||||
): HTMLElement => {
|
||||
const container = document.createElement("figure");
|
||||
container.title = title;
|
||||
|
|
|
@ -11,6 +11,8 @@ import {
|
|||
} from "./types";
|
||||
|
||||
import helpTipIcon from "./help-tip.png";
|
||||
import fontAwesomeIcon from "./FontAwesomeIcon";
|
||||
import { faPencilAlt, faListAlt } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
/**
|
||||
* Return a number or a default value from a raw value.
|
||||
|
@ -752,13 +754,199 @@ export function helpTip(text: string): HTMLElement {
|
|||
return container;
|
||||
}
|
||||
|
||||
interface PeriodSelectorOption {
|
||||
value: number;
|
||||
text: string;
|
||||
}
|
||||
export function periodSelector(
|
||||
selectedValue: PeriodSelectorOption["value"] | null,
|
||||
emptyOption: PeriodSelectorOption | null,
|
||||
options: PeriodSelectorOption[],
|
||||
onChange: (value: PeriodSelectorOption["value"]) => void
|
||||
): HTMLElement {
|
||||
if (selectedValue === null) selectedValue = 0;
|
||||
const initialValue = emptyOption ? emptyOption.value : 0;
|
||||
let currentValue: number =
|
||||
selectedValue != null ? selectedValue : initialValue;
|
||||
// Main container.
|
||||
const container = document.createElement("div");
|
||||
// Container for the period selector.
|
||||
const periodsContainer = document.createElement("div");
|
||||
const selectPeriods = document.createElement("select");
|
||||
const useManualPeriodsBtn = document.createElement("a");
|
||||
// Container for the custom period input.
|
||||
const manualPeriodsContainer = document.createElement("div");
|
||||
const inputTimeValue = document.createElement("input");
|
||||
const unitsSelect = document.createElement("select");
|
||||
const usePeriodsBtn = document.createElement("a");
|
||||
// Units to multiply the custom period input.
|
||||
const unitOptions: { value: string; text: string }[] = [
|
||||
{ value: "1", text: t("Seconds").toLowerCase() },
|
||||
{ value: "60", text: t("Minutes").toLowerCase() },
|
||||
{ value: "3600", text: t("Hours").toLowerCase() },
|
||||
{ value: "86400", text: t("Days").toLowerCase() },
|
||||
{ value: "604800", text: t("Weeks").toLowerCase() },
|
||||
{ value: `${86400 * 30}`, text: t("Months").toLowerCase() },
|
||||
{ value: `${86400 * 30 * 12}`, text: t("Years").toLowerCase() }
|
||||
];
|
||||
|
||||
// Will be executed every time the value changes.
|
||||
const handleChange = (value: number) => {
|
||||
currentValue = value;
|
||||
onChange(currentValue);
|
||||
};
|
||||
// Will return the first period option smaller than the value.
|
||||
const findPeriodsOption = (value: number) =>
|
||||
options
|
||||
.sort((a, b) => (a.value < b.value ? 1 : -1))
|
||||
.find(optionVal => value >= optionVal.value);
|
||||
// Will return the first multiple of the value using the custom input multipliers.
|
||||
const findManualPeriodsOptionValue = (value: number) =>
|
||||
unitOptions
|
||||
.map(unitOption => Number.parseInt(unitOption.value))
|
||||
.sort((a, b) => (a < b ? 1 : -1))
|
||||
.find(optionVal => value % optionVal === 0);
|
||||
// Will find and set a valid option for the period selector.
|
||||
const setPeriodsValue = (value: number) => {
|
||||
let option = findPeriodsOption(value);
|
||||
selectPeriods.value = `${option ? option.value : initialValue}`;
|
||||
};
|
||||
// Will transform the value to show the perfect fit for the custom input period.
|
||||
const setManualPeriodsValue = (value: number) => {
|
||||
const optionVal = findManualPeriodsOptionValue(value);
|
||||
if (optionVal) {
|
||||
inputTimeValue.value = `${value / optionVal}`;
|
||||
unitsSelect.value = `${optionVal}`;
|
||||
} else {
|
||||
inputTimeValue.value = `${value}`;
|
||||
unitsSelect.value = "1";
|
||||
}
|
||||
};
|
||||
|
||||
// Will modify the value to show the perfect fit for this element and show its container.
|
||||
const showPeriods = () => {
|
||||
let option = findPeriodsOption(currentValue);
|
||||
const newValue = option ? option.value : initialValue;
|
||||
selectPeriods.value = `${newValue}`;
|
||||
|
||||
if (newValue !== currentValue) handleChange(newValue);
|
||||
|
||||
container.replaceChild(periodsContainer, manualPeriodsContainer);
|
||||
};
|
||||
// Will modify the value to show the perfect fit for this element and show its container.
|
||||
const showManualPeriods = () => {
|
||||
const optionVal = findManualPeriodsOptionValue(currentValue);
|
||||
|
||||
if (optionVal) {
|
||||
inputTimeValue.value = `${currentValue / optionVal}`;
|
||||
unitsSelect.value = `${optionVal}`;
|
||||
} else {
|
||||
inputTimeValue.value = `${currentValue}`;
|
||||
unitsSelect.value = "1";
|
||||
}
|
||||
|
||||
container.replaceChild(manualPeriodsContainer, periodsContainer);
|
||||
};
|
||||
|
||||
// Append the elements
|
||||
|
||||
periodsContainer.appendChild(selectPeriods);
|
||||
periodsContainer.appendChild(useManualPeriodsBtn);
|
||||
|
||||
manualPeriodsContainer.appendChild(inputTimeValue);
|
||||
manualPeriodsContainer.appendChild(unitsSelect);
|
||||
manualPeriodsContainer.appendChild(usePeriodsBtn);
|
||||
|
||||
if (
|
||||
options.find(option => option.value === selectedValue) ||
|
||||
(emptyOption && emptyOption.value === selectedValue)
|
||||
) {
|
||||
// Start with the custom periods select.
|
||||
container.appendChild(periodsContainer);
|
||||
} else {
|
||||
// Start with the manual time input
|
||||
container.appendChild(manualPeriodsContainer);
|
||||
}
|
||||
|
||||
// Set and fill the elements.
|
||||
|
||||
// Periods selector.
|
||||
|
||||
selectPeriods.addEventListener("change", (e: Event) =>
|
||||
handleChange(
|
||||
parseIntOr((e.target as HTMLSelectElement).value, initialValue)
|
||||
)
|
||||
);
|
||||
if (emptyOption) {
|
||||
const optionElem = document.createElement("option");
|
||||
optionElem.value = `${emptyOption.value}`;
|
||||
optionElem.text = emptyOption.text;
|
||||
selectPeriods.appendChild(optionElem);
|
||||
}
|
||||
options.forEach(option => {
|
||||
const optionElem = document.createElement("option");
|
||||
optionElem.value = `${option.value}`;
|
||||
optionElem.text = option.text;
|
||||
selectPeriods.appendChild(optionElem);
|
||||
});
|
||||
|
||||
setPeriodsValue(selectedValue);
|
||||
|
||||
useManualPeriodsBtn.appendChild(
|
||||
fontAwesomeIcon(faPencilAlt, t("Show manual period input"), {
|
||||
size: "small"
|
||||
})
|
||||
);
|
||||
useManualPeriodsBtn.addEventListener("click", e => {
|
||||
e.preventDefault();
|
||||
showManualPeriods();
|
||||
});
|
||||
|
||||
// Manual periods input.
|
||||
|
||||
inputTimeValue.type = "number";
|
||||
inputTimeValue.min = "0";
|
||||
inputTimeValue.required = true;
|
||||
inputTimeValue.addEventListener("change", (e: Event) =>
|
||||
handleChange(
|
||||
parseIntOr((e.target as HTMLSelectElement).value, 0) *
|
||||
parseIntOr(unitsSelect.value, 1)
|
||||
)
|
||||
);
|
||||
// Select for time units.
|
||||
unitsSelect.addEventListener("change", (e: Event) =>
|
||||
handleChange(
|
||||
parseIntOr(inputTimeValue.value, 0) *
|
||||
parseIntOr((e.target as HTMLSelectElement).value, 1)
|
||||
)
|
||||
);
|
||||
unitOptions.forEach(option => {
|
||||
const optionElem = document.createElement("option");
|
||||
optionElem.value = `${option.value}`;
|
||||
optionElem.text = option.text;
|
||||
unitsSelect.appendChild(optionElem);
|
||||
});
|
||||
|
||||
setManualPeriodsValue(selectedValue);
|
||||
|
||||
usePeriodsBtn.appendChild(
|
||||
fontAwesomeIcon(faListAlt, t("Show periods selector"), { size: "small" })
|
||||
);
|
||||
usePeriodsBtn.addEventListener("click", e => {
|
||||
e.preventDefault();
|
||||
showPeriods();
|
||||
});
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cuts the text if their length is greater than the selected max length
|
||||
* and applies the selected ellipse to the result text.
|
||||
* @param {string} str Text to cut
|
||||
* @param {number} max Maximum length after cutting the text
|
||||
* @param {string} ellipse String to be added to the cutted text
|
||||
* @returns {string} Full text or text cutted with the ellipse
|
||||
* @param str Text to cut
|
||||
* @param max Maximum length after cutting the text
|
||||
* @param ellipse String to be added to the cutted text
|
||||
* @returns Full text or text cutted with the ellipse
|
||||
*/
|
||||
export function ellipsize(
|
||||
str: string,
|
||||
|
|
Loading…
Reference in New Issue