Skip to content

Commit

Permalink
fix(editor/104): Small improvements and fix. (openscd#874)
Browse files Browse the repository at this point in the history
* Small improvements and one fix.
* Split function to make it more readable.
* Small improvements and one fix.
  • Loading branch information
Dennis Labordus authored Jul 18, 2022
1 parent d100042 commit eb22280
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 60 deletions.
30 changes: 19 additions & 11 deletions src/editors/protocol104/foundation/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export function getCdcValueFromDOIElement(doiElement: Element): string | null {
const doName = doiElement.getAttribute('name');

const doElement = doiElement.ownerDocument.querySelector(
`LNodeType[id="${lnType}"] > DO[name="${doName}"]`
`:root > DataTypeTemplates > LNodeType[id="${lnType}"] > DO[name="${doName}"]`
);
if (doElement) {
return getCdcValueFromDOElement(doElement);
Expand All @@ -78,7 +78,7 @@ export function getCdcValueFromDOIElement(doiElement: Element): string | null {
export function getCdcValueFromDOElement(doElement: Element): string | null {
const doType = getTypeAttribute(doElement);
const doTypeElement = doElement.ownerDocument.querySelector(
`DOType[id="${doType}"]`
`:root > DataTypeTemplates > DOType[id="${doType}"]`
);
return doTypeElement ? doTypeElement.getAttribute('cdc') : null;
}
Expand Down Expand Up @@ -145,7 +145,7 @@ export function getDaElement(doElement: Element, name: string): Element | null {
const doType = getTypeAttribute(doElement);
if (doType) {
return doElement.ownerDocument.querySelector(
`DOType[id="${doType}"] > DA[name="${name}"]`
`:root > DataTypeTemplates > DOType[id="${doType}"] > DA[name="${name}"]`
);
}
return null;
Expand Down Expand Up @@ -199,7 +199,7 @@ export function getDoiElement(
lnElement: Element,
doName: string
): Element | null {
return lnElement.querySelector(`DOI[name="${doName}"]`);
return lnElement.querySelector(`:scope > DOI[name="${doName}"]`);
}

export function getDoElement(
Expand All @@ -209,7 +209,7 @@ export function getDoElement(
const lnType = lnElement.getAttribute('lnType');
if (lnType) {
return lnElement.ownerDocument.querySelector(
`LNodeType[id="${lnType}"] > DO[name="${doName}"]`
`:root > DataTypeTemplates > LNodeType[id="${lnType}"] > DO[name="${doName}"]`
);
}
return null;
Expand All @@ -219,7 +219,9 @@ export function getDoElements(lnElement: Element): Element[] {
const lnType = lnElement.getAttribute('lnType');
if (lnType) {
return Array.from(
lnElement.ownerDocument.querySelectorAll(`LNodeType[id="${lnType}"] > DO`)
lnElement.ownerDocument.querySelectorAll(
`:root > DataTypeTemplates > LNodeType[id="${lnType}"] > DO`
)
);
}
return [];
Expand Down Expand Up @@ -286,7 +288,9 @@ function buildTemplateChainFromInstanceElements(
// The LN Element will only be used as starting point to find the LNodeType.
const lnElement = element.closest('LN, LN0')!;
const typeId = lnElement.getAttribute('lnType') ?? '';
typeElement = doc.querySelector(`LNodeType[id="${typeId}"]`);
typeElement = doc.querySelector(
`:root > DataTypeTemplates > LNodeType[id="${typeId}"]`
);

if (typeElement) {
// Next search for the DO Element below the LNodeType Element.
Expand All @@ -299,7 +303,9 @@ function buildTemplateChainFromInstanceElements(

// For the next element search the DOType that is linked to the DO Element.
const typeId = getTypeAttribute(doElement) ?? '';
typeElement = doc.querySelector(`DOType[id="${typeId}"]`);
typeElement = doc.querySelector(
`:root > DataTypeTemplates > DOType[id="${typeId}"]`
);
} else {
typeElement = null;
}
Expand All @@ -317,7 +323,9 @@ function buildTemplateChainFromInstanceElements(
if (daElement.getAttribute('bType') === 'Struct') {
// Only if the bType is a struct we need to search for the DAType for the next element.
const typeId = getTypeAttribute(element) ?? '';
typeElement = doc.querySelector(`DAType[id="${typeId}"]`);
typeElement = doc.querySelector(
`:root > DataTypeTemplates > DAType[id="${typeId}"]`
);
} else {
typeElement = null;
}
Expand Down Expand Up @@ -385,7 +393,7 @@ export function getEnumVal(daiElement: Element, ord: string): string | null {
if (isEnumType(daElement)) {
const enumType = getTypeAttribute(daElement!);
const enumVal = daiElement.ownerDocument.querySelector(
`EnumType[id="${enumType}"] > EnumVal[ord="${ord}"]`
`:root > DataTypeTemplates > EnumType[id="${enumType}"] > EnumVal[ord="${ord}"]`
);
if (enumVal) {
return enumVal.textContent;
Expand All @@ -405,7 +413,7 @@ export function getEnumOrds(daiElement: Element): string[] {
if (isEnumType(daElement)) {
const enumType = getTypeAttribute(daElement!);
const enumVals = daiElement.ownerDocument.querySelectorAll(
`EnumType[id="${enumType}"] > EnumVal`
`:root > DataTypeTemplates > EnumType[id="${enumType}"] > EnumVal`
);
Array.from(enumVals)
.filter(valElement => valElement.getAttribute('ord'))
Expand Down
111 changes: 62 additions & 49 deletions src/editors/protocol104/wizards/selectDo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,56 +21,63 @@ import {
import { createAddressesWizard } from './createAddresses.js';
import { SupportedCdcType, supportedCdcTypes } from '../foundation/cdc.js';
import { PROTOCOL_104_PRIVATE } from '../foundation/private.js';
import { getDoElements, getTypeAttribute } from '../foundation/foundation.js';
import {
getCdcValueFromDOElement,
getDoElements,
} from '../foundation/foundation.js';

/**
* Check if there are DO Elements that aren't initiated and are supported by the 104 protocol available.
* Check if the passed DO Element is supported by the 104 protocol and isn't initiated.
*
* @param parent - The parent element of the child, mainly needed to link the LN Element to the DO Elements.
* @param child - The child to check if it should still be displayed in the finder list.
* @param lnElement - The LN Element used to search for Address Element below DOI, if available.
* @param doElement - The DO Element to check.
*/
function filterAvailableDOElements(parent: Element, child: Element): boolean {
if (child.tagName === 'DO') {
// First check if this DO Element is supported by the 104 Protocol.
const doType = getTypeAttribute(child) ?? '';
const doTypeElement = child.ownerDocument.querySelector(
`DOType[id="${doType}"]`
);
const cdc = doTypeElement?.getAttribute('cdc') ?? '';
if (!supportedCdcTypes.includes(<SupportedCdcType>cdc)) {
return false;
}
function filterAvailableDOElements(
lnElement: Element,
doElement: Element
): boolean {
// First check if this DO Element is supported by the 104 Protocol.
const cdc = getCdcValueFromDOElement(doElement) ?? '';
if (!supportedCdcTypes.includes(<SupportedCdcType>cdc)) {
return false;
}

// Use the parent (LN) to find the DOI that's linked to the DO Element
const doName = getNameAttribute(child);
return (
Array.from(
parent.querySelectorAll(
`:scope > DOI[name="${doName}"] DAI > Private[type="${PROTOCOL_104_PRIVATE}"] > Address`
)
).length <= 0
);
} else {
// For other elements create a list of LN Elements for processing the DO Element from the LN Elements.
let lnElements: Element[];
if (['LN0', 'LN'].includes(child.tagName)) {
lnElements = [child];
} else {
// For the other Elements we will just retrieve all the DOI Elements.
lnElements = Array.from(child.querySelectorAll('LN0, LN'));
}
// Use the parent (LN) to find the DOI that's linked to the DO Element
// And check if there is DOI if it doesn't already contain Address Elements for the 104 Protocol.
const doName = getNameAttribute(doElement);
return (
lnElement.querySelectorAll(
`:scope > DOI[name="${doName}"] DAI > Private[type="${PROTOCOL_104_PRIVATE}"] > Address`
).length <= 0
);
}

// If after filtering there are still LN/DO Element(s) to be displayed, this element will be included.
return (
lnElements.filter(
lnElement =>
// Check if there are available DO Elements that aren't initiated and supported by 104 protocol
getDoElements(lnElement).filter(doElement =>
filterAvailableDOElements(lnElement, doElement)
).length > 0
).length > 0
);
/**
* Check if there are DO Elements that aren't initiated and are supported by the 104 protocol. If this is the
* case the Element can be shown in the Finder.
*
* @param child - The child to check if it should still be displayed in the finder list.
*/
function filterAvailableElements(child: Element): boolean {
// For other elements create a list of LN Elements for processing the DO Element from the LN Elements.
let lnElements: Element[];
if (['LN0', 'LN'].includes(child.tagName)) {
lnElements = [child];
} else {
// For the other Elements we will just retrieve all the DOI Elements.
lnElements = Array.from(child.querySelectorAll('LN0, LN'));
}

// If after filtering there are still LN/DO Element(s) to be displayed, this element will be included.
return (
lnElements.filter(
lnElement =>
// Check if there are available DO Elements that aren't initiated and supported by 104 protocol
getDoElements(lnElement).filter(doElement =>
filterAvailableDOElements(lnElement, doElement)
).length > 0
).length > 0
);
}

/**
Expand All @@ -85,23 +92,29 @@ export function getDataChildren(parent: Element): Element[] {
// For LN Element we will not search for the children, but the DO Element linked to LN from the Template Section.
const lnType = parent.getAttribute('lnType') ?? '';
children = Array.from(
parent.ownerDocument.querySelectorAll(`LNodeType[id="${lnType}"] > DO`)
).sort((a, b) => compareNames(`${identity(a)}`, `${identity(b)}`));
parent.ownerDocument.querySelectorAll(
`:root > DataTypeTemplates > LNodeType[id="${lnType}"] > DO`
)
)
.filter(child => filterAvailableDOElements(parent, child))
.sort((a, b) => compareNames(`${identity(a)}`, `${identity(b)}`));
} else if (parent.tagName === 'AccessPoint') {
// From the Access Point we will skip directly to the LDevice Element and skip the Server element.
children = Array.from(parent.querySelectorAll('LDevice')).sort((a, b) =>
compareNames(`${identity(a)}`, `${identity(b)}`)
);
// Or retrieve the LN Elements directly below the AccessPoint.
children = Array.from(parent.querySelectorAll('LDevice, :scope > LN'))
.filter(child => filterAvailableElements(child))
.sort((a, b) => compareNames(`${identity(a)}`, `${identity(b)}`));
} else {
// The other element, just retrieve the children and if the tagName is one we need return that child.
children = Array.from(parent.children)
.filter(child =>
['IED', 'AccessPoint', 'LN0', 'LN'].includes(child.tagName)
)
.filter(child => filterAvailableElements(child))
.sort((a, b) => compareNames(`${identity(a)}`, `${identity(b)}`));
}

return children.filter(child => filterAvailableDOElements(parent, child));
return children;
}

/**
Expand Down

0 comments on commit eb22280

Please sign in to comment.