Merge branch 'new-vc-line-element' of https://brutus.artica.lan:8081/artica/pandorafms into new-vc-line-element
This commit is contained in:
commit
996e7df1db
|
@ -110,10 +110,13 @@ if ($getVisualConsole === true) {
|
||||||
return;
|
return;
|
||||||
} else if ($updateVisualConsoleItem === true) {
|
} else if ($updateVisualConsoleItem === true) {
|
||||||
$data = get_parameter('data');
|
$data = get_parameter('data');
|
||||||
|
if ($data) {
|
||||||
$data['id'] = $itemId;
|
$data['id'] = $itemId;
|
||||||
$result = $item->save($data);
|
$result = $item->save($data);
|
||||||
|
|
||||||
echo $item;
|
echo $item;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if ($removeVisualConsoleItem === true) {
|
} else if ($removeVisualConsoleItem === true) {
|
||||||
|
|
|
@ -1816,7 +1816,7 @@ class Item extends CachedModel
|
||||||
// Invalidate the item's cache.
|
// Invalidate the item's cache.
|
||||||
if ($result !== false && $result > 0) {
|
if ($result !== false && $result > 0) {
|
||||||
// TODO: Invalidate the cache with the function clearCachedData.
|
// TODO: Invalidate the cache with the function clearCachedData.
|
||||||
db_process_sql_delete(
|
\db_process_sql_delete(
|
||||||
'tvisual_console_elements_cache',
|
'tvisual_console_elements_cache',
|
||||||
[
|
[
|
||||||
'vc_item_id' => (int) $save['id'],
|
'vc_item_id' => (int) $save['id'],
|
||||||
|
|
|
@ -28,6 +28,50 @@ final class ColorCloud extends Item
|
||||||
protected static $useLinkedModule = true;
|
protected static $useLinkedModule = true;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a valid representation of a record in database.
|
||||||
|
*
|
||||||
|
* @param array $data Input data.
|
||||||
|
*
|
||||||
|
* @return array Data structure representing a record in database.
|
||||||
|
*
|
||||||
|
* @overrides Item->encode.
|
||||||
|
*/
|
||||||
|
protected function encode(array $data): array
|
||||||
|
{
|
||||||
|
$return = parent::encode($data);
|
||||||
|
|
||||||
|
$defaultColor = null;
|
||||||
|
if (isset($data['defaultColor']) === true) {
|
||||||
|
$defaultColor = static::extractDefaultColor($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$colorRanges = null;
|
||||||
|
if (isset($data['colorRanges']) === true) {
|
||||||
|
$colorRanges = static::extractColorRanges($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($data['id']) === true) {
|
||||||
|
$return['label'] = json_encode(
|
||||||
|
[
|
||||||
|
'default_color' => $defaultColor,
|
||||||
|
'color_ranges' => $colorRanges,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$prevData = $this->toArray();
|
||||||
|
$return['label'] = json_encode(
|
||||||
|
[
|
||||||
|
'default_color' => ($defaultColor !== null) ? $defaultColor : $prevData['defaultColor'],
|
||||||
|
'color_ranges' => ($colorRanges !== null) ? $colorRanges : $prevData['colorRanges'],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a valid representation of the model.
|
* Returns a valid representation of the model.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1197,7 +1197,9 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
||||||
}
|
}
|
||||||
|
|
||||||
box.className = "visual-console-item";
|
box.className = "visual-console-item";
|
||||||
box.style.zIndex = this.props.isOnTop ? "2" : "1";
|
if (this.props.isOnTop) {
|
||||||
|
box.classList.add("is-on-top");
|
||||||
|
}
|
||||||
box.style.left = `${this.props.x}px`;
|
box.style.left = `${this.props.x}px`;
|
||||||
box.style.top = `${this.props.y}px`;
|
box.style.top = `${this.props.y}px`;
|
||||||
|
|
||||||
|
@ -1470,6 +1472,14 @@ abstract class VisualConsoleItem<Props extends ItemProps> {
|
||||||
if (!prevProps || prevProps.labelPosition !== this.props.labelPosition) {
|
if (!prevProps || prevProps.labelPosition !== this.props.labelPosition) {
|
||||||
this.changeLabelPosition(this.props.labelPosition);
|
this.changeLabelPosition(this.props.labelPosition);
|
||||||
}
|
}
|
||||||
|
//Change z-index class is-on-top
|
||||||
|
if (!prevProps || prevProps.isOnTop !== this.props.isOnTop) {
|
||||||
|
if (this.props.isOnTop) {
|
||||||
|
this.elementRef.classList.add("is-on-top");
|
||||||
|
} else {
|
||||||
|
this.elementRef.classList.remove("is-on-top");
|
||||||
|
}
|
||||||
|
}
|
||||||
// Change link.
|
// Change link.
|
||||||
if (
|
if (
|
||||||
prevProps &&
|
prevProps &&
|
||||||
|
|
|
@ -318,19 +318,9 @@ export default class VisualConsole {
|
||||||
// Force the first render.
|
// Force the first render.
|
||||||
this.render();
|
this.render();
|
||||||
|
|
||||||
// Sort by isOnTop, id ASC
|
// Sort by id ASC
|
||||||
items = items.sort(function(a, b) {
|
items = items.sort(function(a, b) {
|
||||||
if (
|
if (a.id == null || b.id == null) return 0;
|
||||||
a.isOnTop == null ||
|
|
||||||
b.isOnTop == null ||
|
|
||||||
a.id == null ||
|
|
||||||
b.id == null
|
|
||||||
) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.isOnTop && !b.isOnTop) return 1;
|
|
||||||
else if (!a.isOnTop && b.isOnTop) return -1;
|
|
||||||
else if (a.id > b.id) return 1;
|
else if (a.id > b.id) return 1;
|
||||||
else return -1;
|
else return -1;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { AnyObject } from "../lib/types";
|
import { AnyObject } from "../lib/types";
|
||||||
import { parseIntOr, notEmptyStringOr } from "../lib";
|
import { parseIntOr, notEmptyStringOr, t } from "../lib";
|
||||||
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
|
import Item, { ItemType, ItemProps, itemBasePropsDecoder } from "../Item";
|
||||||
|
import { InputGroup, FormContainer } from "../Form";
|
||||||
|
|
||||||
interface BoxProps extends ItemProps {
|
interface BoxProps extends ItemProps {
|
||||||
// Overrided properties.
|
// Overrided properties.
|
||||||
|
@ -39,6 +40,95 @@ export function boxPropsDecoder(data: AnyObject): BoxProps | never {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to add item to the Box item form
|
||||||
|
* This item consists of a label and a color type input color.
|
||||||
|
* Element border color is stored in the borderColor property
|
||||||
|
*/
|
||||||
|
class BorderColorInputGroup extends InputGroup<Partial<BoxProps>> {
|
||||||
|
protected createContent(): HTMLElement | HTMLElement[] {
|
||||||
|
const borderColorLabel = document.createElement("label");
|
||||||
|
borderColorLabel.textContent = t("Border color");
|
||||||
|
|
||||||
|
const borderColorInput = document.createElement("input");
|
||||||
|
borderColorInput.type = "color";
|
||||||
|
borderColorInput.required = true;
|
||||||
|
|
||||||
|
borderColorInput.value = `${this.currentData.borderColor ||
|
||||||
|
this.initialData.borderColor ||
|
||||||
|
"#000000"}`;
|
||||||
|
|
||||||
|
borderColorInput.addEventListener("change", e => {
|
||||||
|
this.updateData({
|
||||||
|
borderColor: (e.target as HTMLInputElement).value
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
borderColorLabel.appendChild(borderColorInput);
|
||||||
|
|
||||||
|
return borderColorLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to add item to the Box item form
|
||||||
|
* This item consists of a label and a color type input number.
|
||||||
|
* Element border width is stored in the borderWidth property
|
||||||
|
*/
|
||||||
|
class BorderWidthInputGroup extends InputGroup<Partial<BoxProps>> {
|
||||||
|
protected createContent(): HTMLElement | HTMLElement[] {
|
||||||
|
const borderWidthLabel = document.createElement("label");
|
||||||
|
borderWidthLabel.textContent = t("Border Width");
|
||||||
|
|
||||||
|
const borderWidthInput = document.createElement("input");
|
||||||
|
borderWidthInput.type = "number";
|
||||||
|
borderWidthInput.min = "0";
|
||||||
|
borderWidthInput.required = true;
|
||||||
|
borderWidthInput.value = `${this.currentData.borderWidth ||
|
||||||
|
this.initialData.borderWidth ||
|
||||||
|
0}`;
|
||||||
|
borderWidthInput.addEventListener("change", e =>
|
||||||
|
this.updateData({
|
||||||
|
borderWidth: parseIntOr((e.target as HTMLInputElement).value, 0)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
borderWidthLabel.appendChild(borderWidthInput);
|
||||||
|
|
||||||
|
return borderWidthLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to add item to the Box item form
|
||||||
|
* This item consists of a label and a color type input color.
|
||||||
|
* Element fill color is stored in the fillcolor property
|
||||||
|
*/
|
||||||
|
class FillColorInputGroup extends InputGroup<Partial<BoxProps>> {
|
||||||
|
protected createContent(): HTMLElement | HTMLElement[] {
|
||||||
|
const fillColorLabel = document.createElement("label");
|
||||||
|
fillColorLabel.textContent = t("Fill color");
|
||||||
|
|
||||||
|
const fillColorInput = document.createElement("input");
|
||||||
|
fillColorInput.type = "color";
|
||||||
|
fillColorInput.required = true;
|
||||||
|
|
||||||
|
fillColorInput.value = `${this.currentData.fillColor ||
|
||||||
|
this.initialData.fillColor ||
|
||||||
|
"#000000"}`;
|
||||||
|
|
||||||
|
fillColorInput.addEventListener("change", e => {
|
||||||
|
this.updateData({
|
||||||
|
fillColor: (e.target as HTMLInputElement).value
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
fillColorLabel.appendChild(fillColorInput);
|
||||||
|
|
||||||
|
return fillColorLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default class Box extends Item<BoxProps> {
|
export default class Box extends Item<BoxProps> {
|
||||||
protected createDomElement(): HTMLElement {
|
protected createDomElement(): HTMLElement {
|
||||||
const box: HTMLDivElement = document.createElement("div");
|
const box: HTMLDivElement = document.createElement("div");
|
||||||
|
@ -65,4 +155,46 @@ export default class Box extends Item<BoxProps> {
|
||||||
|
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To update the content element.
|
||||||
|
* @override Item.updateDomElement
|
||||||
|
*/
|
||||||
|
protected updateDomElement(element: HTMLElement): void {
|
||||||
|
if (this.props.fillColor) {
|
||||||
|
element.style.backgroundColor = this.props.fillColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Border.
|
||||||
|
if (this.props.borderWidth > 0) {
|
||||||
|
element.style.borderStyle = "solid";
|
||||||
|
// Control the max width to prevent this item to expand beyond its parent.
|
||||||
|
const maxBorderWidth = Math.min(this.props.width, this.props.height) / 2;
|
||||||
|
const borderWidth = Math.min(this.props.borderWidth, maxBorderWidth);
|
||||||
|
element.style.borderWidth = `${borderWidth}px`;
|
||||||
|
|
||||||
|
if (this.props.borderColor) {
|
||||||
|
element.style.borderColor = this.props.borderColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override function to add or remove inputsGroups those that are not necessary.
|
||||||
|
* Add to:
|
||||||
|
* LinkConsoleInputGroup
|
||||||
|
*/
|
||||||
|
public getFormContainer(): FormContainer {
|
||||||
|
const formContainer = super.getFormContainer();
|
||||||
|
formContainer.addInputGroup(
|
||||||
|
new BorderColorInputGroup("border-color", this.props)
|
||||||
|
);
|
||||||
|
formContainer.addInputGroup(
|
||||||
|
new BorderWidthInputGroup("border-width", this.props)
|
||||||
|
);
|
||||||
|
formContainer.addInputGroup(
|
||||||
|
new FillColorInputGroup("fill-width", this.props)
|
||||||
|
);
|
||||||
|
return formContainer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,26 @@ import {
|
||||||
LinkedVisualConsoleProps,
|
LinkedVisualConsoleProps,
|
||||||
AnyObject
|
AnyObject
|
||||||
} from "../lib/types";
|
} from "../lib/types";
|
||||||
import { modulePropsDecoder, linkedVCPropsDecoder } from "../lib";
|
import { modulePropsDecoder, linkedVCPropsDecoder, t } from "../lib";
|
||||||
import Item, {
|
import Item, {
|
||||||
itemBasePropsDecoder,
|
itemBasePropsDecoder,
|
||||||
ItemType,
|
ItemType,
|
||||||
ItemProps,
|
ItemProps,
|
||||||
LinkConsoleInputGroup
|
LinkConsoleInputGroup
|
||||||
} from "../Item";
|
} from "../Item";
|
||||||
import { FormContainer } from "../Form";
|
import { FormContainer, InputGroup } from "../Form";
|
||||||
|
import fontAwesomeIcon from "../lib/FontAwesomeIcon";
|
||||||
|
import { faTrashAlt, faPlusCircle } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
export type ColorCloudProps = {
|
export type ColorCloudProps = {
|
||||||
type: ItemType.COLOR_CLOUD;
|
type: ItemType.COLOR_CLOUD;
|
||||||
color: string;
|
color: string;
|
||||||
|
defaultColor: string;
|
||||||
|
colorRanges: {
|
||||||
|
color: string;
|
||||||
|
fromValue: number;
|
||||||
|
toValue: number;
|
||||||
|
}[];
|
||||||
// TODO: Add the rest of the color cloud values?
|
// TODO: Add the rest of the color cloud values?
|
||||||
} & ItemProps &
|
} & ItemProps &
|
||||||
WithModuleProps &
|
WithModuleProps &
|
||||||
|
@ -41,11 +49,292 @@ export function colorCloudPropsDecoder(
|
||||||
...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
|
...itemBasePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
|
||||||
type: ItemType.COLOR_CLOUD,
|
type: ItemType.COLOR_CLOUD,
|
||||||
color: data.color,
|
color: data.color,
|
||||||
|
defaultColor: data.defaultColor,
|
||||||
|
colorRanges: data.colorRanges,
|
||||||
...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
|
...modulePropsDecoder(data), // Object spread. It will merge the properties of the two objects.
|
||||||
...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
|
...linkedVCPropsDecoder(data) // Object spread. It will merge the properties of the two objects.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to add item to the Color cloud item form
|
||||||
|
* This item consists of a label and a color type input color.
|
||||||
|
* Element default color is stored in the color property
|
||||||
|
*/
|
||||||
|
class ColorInputGroup extends InputGroup<Partial<ColorCloudProps>> {
|
||||||
|
protected createContent(): HTMLElement | HTMLElement[] {
|
||||||
|
const ColorLabel = document.createElement("label");
|
||||||
|
ColorLabel.textContent = t("Default color");
|
||||||
|
|
||||||
|
const ColorInput = document.createElement("input");
|
||||||
|
ColorInput.type = "color";
|
||||||
|
ColorInput.required = true;
|
||||||
|
|
||||||
|
ColorInput.value = `${this.currentData.defaultColor ||
|
||||||
|
this.initialData.defaultColor ||
|
||||||
|
"#000000"}`;
|
||||||
|
|
||||||
|
ColorInput.addEventListener("change", e => {
|
||||||
|
this.updateData({
|
||||||
|
defaultColor: (e.target as HTMLInputElement).value
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ColorLabel.appendChild(ColorInput);
|
||||||
|
|
||||||
|
return ColorLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ColorRanges = ColorCloudProps["colorRanges"];
|
||||||
|
type ColorRange = ColorRanges[0];
|
||||||
|
|
||||||
|
class RangesInputGroup extends InputGroup<Partial<ColorCloudProps>> {
|
||||||
|
protected createContent(): HTMLElement | HTMLElement[] {
|
||||||
|
const rangesLabel = this.createLabel("Ranges");
|
||||||
|
const rangesControlsContainer = document.createElement("div");
|
||||||
|
const createdRangesContainer = document.createElement("div");
|
||||||
|
|
||||||
|
rangesControlsContainer.appendChild(createdRangesContainer);
|
||||||
|
rangesLabel.appendChild(rangesControlsContainer);
|
||||||
|
|
||||||
|
const colorRanges =
|
||||||
|
this.currentData.colorRanges || this.initialData.colorRanges || [];
|
||||||
|
|
||||||
|
let buildRanges: (ranges: ColorRanges) => void;
|
||||||
|
|
||||||
|
const handleRangeUpdatePartial = (index: number) => (
|
||||||
|
range: ColorRange
|
||||||
|
): void => {
|
||||||
|
const colorRanges =
|
||||||
|
this.currentData.colorRanges || this.initialData.colorRanges || [];
|
||||||
|
this.updateData({
|
||||||
|
colorRanges: [
|
||||||
|
...colorRanges.slice(0, index),
|
||||||
|
range,
|
||||||
|
...colorRanges.slice(index)
|
||||||
|
]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = (index: number) => () => {
|
||||||
|
const colorRanges =
|
||||||
|
this.currentData.colorRanges || this.initialData.colorRanges || [];
|
||||||
|
const newRanges = [
|
||||||
|
...colorRanges.slice(0, index),
|
||||||
|
...colorRanges.slice(index + 1)
|
||||||
|
];
|
||||||
|
|
||||||
|
this.updateData({
|
||||||
|
colorRanges: newRanges
|
||||||
|
});
|
||||||
|
buildRanges(newRanges);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreate = (range: ColorRange): void => {
|
||||||
|
const colorRanges =
|
||||||
|
this.currentData.colorRanges || this.initialData.colorRanges || [];
|
||||||
|
const newRanges = [...colorRanges, range];
|
||||||
|
this.updateData({
|
||||||
|
colorRanges: newRanges
|
||||||
|
});
|
||||||
|
buildRanges(newRanges);
|
||||||
|
};
|
||||||
|
|
||||||
|
buildRanges = ranges => {
|
||||||
|
createdRangesContainer.innerHTML = "";
|
||||||
|
console.log(ranges);
|
||||||
|
ranges.forEach((colorRange, index) =>
|
||||||
|
createdRangesContainer.appendChild(
|
||||||
|
this.rangeContainer(
|
||||||
|
colorRange,
|
||||||
|
handleRangeUpdatePartial(index),
|
||||||
|
handleDelete(index)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
buildRanges(colorRanges);
|
||||||
|
|
||||||
|
rangesControlsContainer.appendChild(
|
||||||
|
this.initialRangeContainer(handleCreate)
|
||||||
|
);
|
||||||
|
|
||||||
|
return rangesLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private initialRangeContainer(onCreate: (range: ColorRange) => void) {
|
||||||
|
// TODO: Document
|
||||||
|
const initialState = { color: "#fff" };
|
||||||
|
const state: Partial<ColorRange> = initialState;
|
||||||
|
|
||||||
|
const handleFromValue = (value: ColorRange["fromValue"]): void => {
|
||||||
|
state.fromValue = value;
|
||||||
|
};
|
||||||
|
const handleToValue = (value: ColorRange["toValue"]): void => {
|
||||||
|
state.toValue = value;
|
||||||
|
};
|
||||||
|
const handleColor = (value: ColorRange["color"]): void => {
|
||||||
|
state.color = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// User defined type guard.
|
||||||
|
// Docs: https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards
|
||||||
|
const isValid = (range: Partial<ColorRange>): range is ColorRange =>
|
||||||
|
typeof range.color !== "undefined" &&
|
||||||
|
typeof range.toValue !== "undefined" &&
|
||||||
|
typeof range.fromValue !== "undefined";
|
||||||
|
|
||||||
|
const handleCreate = () => {
|
||||||
|
if (isValid(state)) onCreate(state);
|
||||||
|
};
|
||||||
|
|
||||||
|
const rangesContainer = document.createElement("div");
|
||||||
|
|
||||||
|
// Div From value.
|
||||||
|
const rangesContainerFromValue = document.createElement("div");
|
||||||
|
const rangesLabelFromValue = this.createLabel("From Value");
|
||||||
|
const rangesInputFromValue = this.createInputNumber(null, handleFromValue);
|
||||||
|
rangesContainerFromValue.appendChild(rangesLabelFromValue);
|
||||||
|
rangesContainerFromValue.appendChild(rangesInputFromValue);
|
||||||
|
rangesContainer.appendChild(rangesContainerFromValue);
|
||||||
|
|
||||||
|
// Div To Value.
|
||||||
|
const rangesDivContainerToValue = document.createElement("div");
|
||||||
|
const rangesLabelToValue = this.createLabel("To Value");
|
||||||
|
const rangesInputToValue = this.createInputNumber(null, handleToValue);
|
||||||
|
rangesContainerFromValue.appendChild(rangesLabelToValue);
|
||||||
|
rangesContainerFromValue.appendChild(rangesInputToValue);
|
||||||
|
rangesContainer.appendChild(rangesDivContainerToValue);
|
||||||
|
|
||||||
|
// Div Color.
|
||||||
|
const rangesDivContainerColor = document.createElement("div");
|
||||||
|
const rangesLabelColor = this.createLabel("Color");
|
||||||
|
const rangesInputColor = this.createInputColor(
|
||||||
|
initialState.color,
|
||||||
|
handleColor
|
||||||
|
);
|
||||||
|
rangesContainerFromValue.appendChild(rangesLabelColor);
|
||||||
|
rangesContainerFromValue.appendChild(rangesInputColor);
|
||||||
|
rangesContainer.appendChild(rangesDivContainerColor);
|
||||||
|
|
||||||
|
// Button delete.
|
||||||
|
const createBtn = document.createElement("a");
|
||||||
|
createBtn.appendChild(
|
||||||
|
fontAwesomeIcon(faPlusCircle, t("Create color range"))
|
||||||
|
);
|
||||||
|
createBtn.addEventListener("click", handleCreate);
|
||||||
|
|
||||||
|
rangesContainer.appendChild(createBtn);
|
||||||
|
|
||||||
|
return rangesContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private rangeContainer(
|
||||||
|
colorRange: ColorRange,
|
||||||
|
onUpdate: (range: ColorRange) => void,
|
||||||
|
onDelete: () => void
|
||||||
|
): HTMLDivElement {
|
||||||
|
// TODO: Document
|
||||||
|
const state = { ...colorRange };
|
||||||
|
|
||||||
|
const handleFromValue = (value: ColorRange["fromValue"]): void => {
|
||||||
|
state.fromValue = value;
|
||||||
|
onUpdate({ ...state });
|
||||||
|
};
|
||||||
|
const handleToValue = (value: ColorRange["toValue"]): void => {
|
||||||
|
state.toValue = value;
|
||||||
|
onUpdate({ ...state });
|
||||||
|
};
|
||||||
|
const handleColor = (value: ColorRange["color"]): void => {
|
||||||
|
state.color = value;
|
||||||
|
onUpdate({ ...state });
|
||||||
|
};
|
||||||
|
|
||||||
|
const rangesContainer = document.createElement("div");
|
||||||
|
|
||||||
|
// Div From value.
|
||||||
|
const rangesContainerFromValue = document.createElement("div");
|
||||||
|
const rangesLabelFromValue = this.createLabel("From Value");
|
||||||
|
const rangesInputFromValue = this.createInputNumber(
|
||||||
|
colorRange.fromValue,
|
||||||
|
handleFromValue
|
||||||
|
);
|
||||||
|
rangesContainerFromValue.appendChild(rangesLabelFromValue);
|
||||||
|
rangesContainerFromValue.appendChild(rangesInputFromValue);
|
||||||
|
rangesContainer.appendChild(rangesContainerFromValue);
|
||||||
|
|
||||||
|
// Div To Value.
|
||||||
|
const rangesDivContainerToValue = document.createElement("div");
|
||||||
|
const rangesLabelToValue = this.createLabel("To Value");
|
||||||
|
const rangesInputToValue = this.createInputNumber(
|
||||||
|
colorRange.toValue,
|
||||||
|
handleToValue
|
||||||
|
);
|
||||||
|
rangesContainerFromValue.appendChild(rangesLabelToValue);
|
||||||
|
rangesContainerFromValue.appendChild(rangesInputToValue);
|
||||||
|
rangesContainer.appendChild(rangesDivContainerToValue);
|
||||||
|
|
||||||
|
// Div Color.
|
||||||
|
const rangesDivContainerColor = document.createElement("div");
|
||||||
|
const rangesLabelColor = this.createLabel("Color");
|
||||||
|
const rangesInputColor = this.createInputColor(
|
||||||
|
colorRange.color,
|
||||||
|
handleColor
|
||||||
|
);
|
||||||
|
rangesContainerFromValue.appendChild(rangesLabelColor);
|
||||||
|
rangesContainerFromValue.appendChild(rangesInputColor);
|
||||||
|
rangesContainer.appendChild(rangesDivContainerColor);
|
||||||
|
|
||||||
|
// Button delete.
|
||||||
|
const deleteBtn = document.createElement("a");
|
||||||
|
deleteBtn.appendChild(fontAwesomeIcon(faTrashAlt, t("Delete color range")));
|
||||||
|
deleteBtn.addEventListener("click", onDelete);
|
||||||
|
|
||||||
|
rangesContainer.appendChild(deleteBtn);
|
||||||
|
|
||||||
|
return rangesContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createLabel(text: string): HTMLLabelElement {
|
||||||
|
const label = document.createElement("label");
|
||||||
|
label.textContent = t(text);
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createInputNumber(
|
||||||
|
value: number | null,
|
||||||
|
onUpdate: (value: number) => void
|
||||||
|
): HTMLInputElement {
|
||||||
|
const input = document.createElement("input");
|
||||||
|
input.type = "number";
|
||||||
|
input.required = true;
|
||||||
|
if (value !== null) input.value = `${value}`;
|
||||||
|
input.addEventListener("change", e => {
|
||||||
|
const value = parseInt((e.target as HTMLInputElement).value);
|
||||||
|
if (!isNaN(value)) onUpdate(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createInputColor(
|
||||||
|
value: string | null,
|
||||||
|
onUpdate: (value: string) => void
|
||||||
|
): HTMLInputElement {
|
||||||
|
const input = document.createElement("input");
|
||||||
|
input.type = "color";
|
||||||
|
input.required = true;
|
||||||
|
if (value !== null) input.value = value;
|
||||||
|
input.addEventListener("change", e =>
|
||||||
|
onUpdate((e.target as HTMLInputElement).value)
|
||||||
|
);
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const svgNS = "http://www.w3.org/2000/svg";
|
const svgNS = "http://www.w3.org/2000/svg";
|
||||||
|
|
||||||
export default class ColorCloud extends Item<ColorCloudProps> {
|
export default class ColorCloud extends Item<ColorCloudProps> {
|
||||||
|
@ -112,12 +401,18 @@ export default class ColorCloud extends Item<ColorCloudProps> {
|
||||||
* @override function to add or remove inputsGroups those that are not necessary.
|
* @override function to add or remove inputsGroups those that are not necessary.
|
||||||
* Add to:
|
* Add to:
|
||||||
* LinkConsoleInputGroup
|
* LinkConsoleInputGroup
|
||||||
|
* ColorInputGroup
|
||||||
|
* RangesInputGroup
|
||||||
*/
|
*/
|
||||||
public getFormContainer(): FormContainer {
|
public getFormContainer(): FormContainer {
|
||||||
const formContainer = super.getFormContainer();
|
const formContainer = super.getFormContainer();
|
||||||
formContainer.addInputGroup(
|
formContainer.addInputGroup(
|
||||||
new LinkConsoleInputGroup("link-console", this.props)
|
new LinkConsoleInputGroup("link-console", this.props)
|
||||||
);
|
);
|
||||||
|
formContainer.addInputGroup(new ColorInputGroup("color-cloud", this.props));
|
||||||
|
formContainer.addInputGroup(
|
||||||
|
new RangesInputGroup("ranges-cloud", this.props)
|
||||||
|
);
|
||||||
return formContainer;
|
return formContainer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,17 @@ import {
|
||||||
notEmptyStringOr,
|
notEmptyStringOr,
|
||||||
stringIsEmpty,
|
stringIsEmpty,
|
||||||
decodeBase64,
|
decodeBase64,
|
||||||
parseBoolean
|
parseBoolean,
|
||||||
|
t
|
||||||
} from "../lib";
|
} from "../lib";
|
||||||
import Item, {
|
import Item, {
|
||||||
ItemProps,
|
ItemProps,
|
||||||
itemBasePropsDecoder,
|
itemBasePropsDecoder,
|
||||||
ItemType,
|
ItemType,
|
||||||
LinkConsoleInputGroup
|
LinkConsoleInputGroup,
|
||||||
|
ImageInputGroup
|
||||||
} from "../Item";
|
} from "../Item";
|
||||||
import { FormContainer } from "../Form";
|
import { FormContainer, InputGroup } from "../Form";
|
||||||
|
|
||||||
export type GroupProps = {
|
export type GroupProps = {
|
||||||
type: ItemType.GROUP_ITEM;
|
type: ItemType.GROUP_ITEM;
|
||||||
|
@ -66,6 +68,39 @@ export function groupPropsDecoder(data: AnyObject): GroupProps | never {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Document
|
||||||
|
class ShowStatisticsInputGroup extends InputGroup<Partial<GroupProps>> {
|
||||||
|
protected createContent(): HTMLElement | HTMLElement[] {
|
||||||
|
const showStatisticsLabel = document.createElement("label");
|
||||||
|
showStatisticsLabel.textContent = t("Show statistics");
|
||||||
|
|
||||||
|
const showStatisticsInputChkbx = document.createElement("input");
|
||||||
|
showStatisticsInputChkbx.id = "checkbox-switch";
|
||||||
|
showStatisticsInputChkbx.className = "checkbox-switch";
|
||||||
|
showStatisticsInputChkbx.type = "checkbox";
|
||||||
|
showStatisticsInputChkbx.name = "checkbox-enable-link";
|
||||||
|
showStatisticsInputChkbx.value = "1";
|
||||||
|
showStatisticsInputChkbx.checked =
|
||||||
|
this.currentData.showStatistics ||
|
||||||
|
this.initialData.showStatistics ||
|
||||||
|
false;
|
||||||
|
showStatisticsInputChkbx.addEventListener("change", e =>
|
||||||
|
this.updateData({
|
||||||
|
showStatistics: (e.target as HTMLInputElement).checked
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const linkInputLabel = document.createElement("label");
|
||||||
|
linkInputLabel.className = "label-switch";
|
||||||
|
linkInputLabel.htmlFor = "checkbox-switch";
|
||||||
|
|
||||||
|
showStatisticsLabel.appendChild(showStatisticsInputChkbx);
|
||||||
|
showStatisticsLabel.appendChild(linkInputLabel);
|
||||||
|
|
||||||
|
return showStatisticsLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default class Group extends Item<GroupProps> {
|
export default class Group extends Item<GroupProps> {
|
||||||
protected createDomElement(): HTMLElement {
|
protected createDomElement(): HTMLElement {
|
||||||
const element = document.createElement("div");
|
const element = document.createElement("div");
|
||||||
|
@ -73,7 +108,8 @@ export default class Group extends Item<GroupProps> {
|
||||||
|
|
||||||
if (!this.props.showStatistics && this.props.statusImageSrc !== null) {
|
if (!this.props.showStatistics && this.props.statusImageSrc !== null) {
|
||||||
// Icon with status.
|
// Icon with status.
|
||||||
element.style.background = `url(${this.props.statusImageSrc}) no-repeat`;
|
element.style.backgroundImage = `url(${this.props.statusImageSrc})`;
|
||||||
|
element.style.backgroundRepeat = "no-repeat";
|
||||||
element.style.backgroundSize = "contain";
|
element.style.backgroundSize = "contain";
|
||||||
element.style.backgroundPosition = "center";
|
element.style.backgroundPosition = "center";
|
||||||
} else if (this.props.showStatistics && this.props.html != null) {
|
} else if (this.props.showStatistics && this.props.html != null) {
|
||||||
|
@ -84,16 +120,46 @@ export default class Group extends Item<GroupProps> {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To update the content element.
|
||||||
|
* @override Item.updateDomElement
|
||||||
|
*/
|
||||||
|
protected updateDomElement(element: HTMLElement): void {
|
||||||
|
if (!this.props.showStatistics && this.props.statusImageSrc !== null) {
|
||||||
|
// Icon with status.
|
||||||
|
element.style.backgroundImage = `url(${this.props.statusImageSrc})`;
|
||||||
|
element.style.backgroundRepeat = "no-repeat";
|
||||||
|
element.style.backgroundSize = "contain";
|
||||||
|
element.style.backgroundPosition = "center";
|
||||||
|
element.innerHTML = "";
|
||||||
|
} else if (this.props.showStatistics && this.props.html != null) {
|
||||||
|
// Stats table.
|
||||||
|
element.innerHTML = this.props.html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override function to add or remove inputsGroups those that are not necessary.
|
* @override function to add or remove inputsGroups those that are not necessary.
|
||||||
* Add to:
|
* Add to:
|
||||||
* LinkConsoleInputGroup
|
* LinkConsoleInputGroup
|
||||||
|
* ImageInputGroup
|
||||||
|
* ShowStatisticsInputGroup
|
||||||
*/
|
*/
|
||||||
public getFormContainer(): FormContainer {
|
public getFormContainer(): FormContainer {
|
||||||
const formContainer = super.getFormContainer();
|
const formContainer = super.getFormContainer();
|
||||||
formContainer.addInputGroup(
|
formContainer.addInputGroup(
|
||||||
new LinkConsoleInputGroup("link-console", this.props)
|
new LinkConsoleInputGroup("link-console", this.props)
|
||||||
);
|
);
|
||||||
|
formContainer.addInputGroup(
|
||||||
|
new ImageInputGroup("image-console", {
|
||||||
|
...this.props,
|
||||||
|
imageKey: "imageSrc",
|
||||||
|
showStatusImg: true
|
||||||
|
})
|
||||||
|
);
|
||||||
|
formContainer.addInputGroup(
|
||||||
|
new ShowStatisticsInputGroup("show-statistic", this.props)
|
||||||
|
);
|
||||||
return formContainer;
|
return formContainer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,11 @@
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
user-select: text;
|
user-select: text;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.visual-console-item.is-on-top {
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.visual-console-item.is-editing {
|
.visual-console-item.is-editing {
|
||||||
|
|
Loading…
Reference in New Issue