sparnatural
Version:
Visual client-side SPARQL query builder and knowledge graph exploration tool
208 lines (188 loc) • 7.88 kB
text/typescript
/**
* A single line/criteria
**/
import ISparnaturalSpecification from "../../../../spec-providers/ISparnaturalSpecification";
import UnselectBtn from "../../../buttons/UnselectBtn";
import ObjectPropertyGroup from "./objectpropertygroup/ObjectPropertyGroup";
import EndClassGroup from "./startendclassgroup/EndClassGroup";
import StartClassGroup from "./startendclassgroup/StartClassGroup";
import GroupWrapper from "../GroupWrapper";
import { OptionsGroup, OptionTypes } from "./optionsgroup/OptionsGroup";
import HTMLComponent from "../../../HtmlComponent";
import { SelectedVal } from "../../../SelectedVal";
import {
EndClassWidgetGroup,
EndClassWidgetValue,
} from "./startendclassgroup/EndClassWidgetGroup";
import ActionsGroup from "../../../buttons/actions/ActionsGroup";
import { triggerOption } from "../groupwrapperevents/events/TriggerOption";
import { I18n } from "../../../../settings/I18n";
class CriteriaGroup extends HTMLComponent {
StartClassGroup: StartClassGroup;
OptionsGroup: OptionsGroup; // optional or notexists
ObjectPropertyGroup: ObjectPropertyGroup;
EndClassGroup: EndClassGroup;
endClassWidgetGroup: EndClassWidgetGroup;
ActionsGroup: ActionsGroup;
specProvider: ISparnaturalSpecification;
ParentGroupWrapper: GroupWrapper;
unselectBtn: UnselectBtn;
constructor(
parentComponent: GroupWrapper,
specProvider: any,
startClassVal?: SelectedVal,
startClassEyeBtn?: boolean
) {
super("CriteriaGroup", parentComponent, null);
this.specProvider = specProvider;
this.ParentGroupWrapper = parentComponent;
this.StartClassGroup = new StartClassGroup(
this,
this.specProvider,
I18n.labels.StartClassTemporaryLabel,
startClassVal,
// Decides if the selectviewvarBtn is rendered on the startClass. That is the case only for the first one
startClassEyeBtn
);
}
render(): this {
super.render();
this.#renderChildComponents();
this.unselectBtn = new UnselectBtn(this, () => {
// caught in Parentcomponent
this.html[0].dispatchEvent(
new CustomEvent("onRemoveGrp", { bubbles: true })
);
}).render();
return this;
}
#renderChildComponents() {
// create all the elements of the criteria
this.StartClassGroup.render();
this.OptionsGroup = new OptionsGroup(this, this.specProvider).render();
this.ObjectPropertyGroup = new ObjectPropertyGroup(
this,
this.specProvider,
I18n.labels.ObjectPropertyTemporaryLabel
).render();
this.EndClassGroup = new EndClassGroup(this, this.specProvider).render();
this.endClassWidgetGroup = new EndClassWidgetGroup(this, this.specProvider);
this.ActionsGroup = new ActionsGroup(this, this.specProvider).render();
this.#assembleComponents();
}
#assembleComponents = () => {
// 1. User selects StartClassVal
this.html[0].addEventListener(
"StartClassGroupSelected",
(e: CustomEvent) => {
e.stopImmediatePropagation();
if (!this.#isSelectedVal(e.detail))
throw Error(
"StartClassGroupSelected expects object of type SelectedVal"
);
this.ObjectPropertyGroup.onStartClassGroupSelected(e.detail);
this.EndClassGroup.onStartClassGroupSelected(e.detail);
}
);
// 2. User Selects EndClassVal
this.html[0].addEventListener("EndClassGroupSelected", (e: CustomEvent) => {
e.stopImmediatePropagation();
if (!this.#isSelectedVal(e.detail))
throw Error("EndClassGroupSelected expects object of type SelectedVal");
this.ObjectPropertyGroup.onEndClassGroupSelected(e.detail);
});
// 3. Automatically selected or User selects ObjectPropertyGrpVal
this.html[0].addEventListener(
"onObjectPropertyGroupSelected",
(e: CustomEvent) => {
e.stopImmediatePropagation();
if (!this.#isSelectedVal(e.detail))
throw Error(
"onObjectPropertyGroupSelected expects object of type SelectedVal"
);
// if there is already a where connection or widget values selected, don't change anything
if (
!this.ParentGroupWrapper.whereChild &&
this.endClassWidgetGroup?.widgetValues?.length === 0
) {
this.EndClassGroup.onObjectPropertyGroupSelected(e.detail);
this.endClassWidgetGroup.render();
}
this.OptionsGroup.onObjectPropertyGroupSelected(
this.ParentGroupWrapper.optionState
);
// if there is already a andSibling don't allow to rerender the ActionAnd again
if (!this.ParentGroupWrapper.andSibling)
this.ActionsGroup.onObjectPropertyGroupSelected();
// if property has a sparqlService, switch the state
if (this.specProvider.getProperty(e.detail.type).getServiceEndpoint()) {
triggerOption(this.ParentGroupWrapper, OptionTypes.SERVICE);
} else {
triggerOption(
this.ParentGroupWrapper,
this.ParentGroupWrapper.optionState
);
}
}
);
// gets called by the widget.
this.html[0].addEventListener("renderWidgetVal", (e: CustomEvent) => {
e.stopImmediatePropagation();
if (e.detail == "" || !e.detail)
throw Error(
'No widgetValue received. Widget Value needs to be provided for "renderWidgetVal"'
);
if (Array.isArray(e.detail)) {
// if there is an array with values provided, render all of them
e.detail.forEach((v) => this.endClassWidgetGroup.renderWidgetVal(v));
} else {
this.endClassWidgetGroup.renderWidgetVal(e.detail);
}
});
// when inputgot selected then we remove the where btn and EditComponents
this.html[0].addEventListener("removeEditComponents", (e: CustomEvent) => {
e.stopImmediatePropagation();
this.EndClassGroup.editComponents?.html?.empty()?.remove();
});
//gets called when a user removes a previously selected widgetValue
//removes the widgetValue from the widgetvalues list in the widget
this.html[0].addEventListener("updateWidgetList", (e: CustomEvent) => {
if (!("unselectedVal" in e.detail))
throw Error(
"updateWidgetList expects an object of type EndClassWidgetValue"
);
e.stopImmediatePropagation();
this.html[0].dispatchEvent(
new CustomEvent("generateQuery", { bubbles: true })
);
});
// gets called when the user adds widgetvalues or removes widgetvalues
this.html[0].addEventListener("renderWidgetWrapper", (e: CustomEvent) => {
if (!("selectedValues" in e.detail) && e.detail.selectedValues.isArray)
throw Error("renderWidgetWrapper expects list of selected values.");
e.stopImmediatePropagation();
// removeEditComponents: if add btn got clicked mutiple times or the old widgetwrapper is still rendered while the last selectedvalue got deleted
this.html[0].dispatchEvent(new CustomEvent("removeEditComponents"));
if (
e.detail.selectedValues.length === 0 &&
// if we are not in the case that we edit the last value in the list
// note : editedValue contains the value being edited - it could be passed again to the widget, maybe, instead
// of keeping the state in the widget
!e.detail.editedValue
) {
// Render WidgetsWrapper and ActionWhere
this.EndClassGroup.editComponents.render();
this.html[0].dispatchEvent(
new CustomEvent("onGrpInputNotCompleted", { bubbles: true })
);
} else {
//we only need widgetswrapper
this.EndClassGroup.editComponents.renderWidgetsWrapper();
}
});
};
#isSelectedVal(payload: any): payload is SelectedVal {
return "type" in payload && "variable" in payload;
}
}
export default CriteriaGroup;