// Copyright (C) 2023 Vaughn Nugent // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . import { cloneDeep, filter, forEach, isEmpty, join, map } from 'lodash-es'; import { watch, Ref, ref } from 'vue'; import { FeedProperty, XmlPropertyContainer } from '../types'; /** * An interface for working with xml properties from an xml feed */ export interface UseXmlProperties { /** * Correctly formats and exports the current properties */ getCurrentProperties(): FeedProperty[] | undefined; /** * Gets the current properties as xml */ getXml(): string | undefined; /** * Saves properties values from a json string * @param json The property json to parse * @returns True if the json was parsed and saved, false otherwise */ saveJson: (json: string | undefined) => boolean; /** * Gets a copy of the current properties */ getModel(): FeedProperty[] | undefined; /** * Manually adds an array of properties to the current properties */ addProperties: (properties: FeedProperty[]) => void; } /** * Creates a new instance of the useXmlProperties api from the given feed * @param feed The feed to read and watch for changes from * @returns An api for working with xml properties */ export const useXmlProperties = (feed: Ref): UseXmlProperties => { //The current properties const currentProperties = ref(feed.value?.properties || []); //Watch for changes to the feed watch(feed, (newFeed) => { currentProperties.value = newFeed?.properties || [] }, { immediate: true }); const getCurrentProperties = (): FeedProperty[] | undefined => { //Get all properties that are not emtpy return filter(currentProperties.value, p => !isEmpty(p.name)); } const getPropertyXml = (properties: FeedProperty[]): string => { let output = ''; forEach(properties, prop => { //Open tag (with namespace if present) output += !isEmpty(prop.namespace) ? `<${prop.namespace}:${prop.name}` : `<${prop.name}` if (!isEmpty(prop.attributes)) { forEach(prop.attributes, (value, key) => output += ` ${key}="${value}"`) } //Recursive call for nested property, or add its value output += !isEmpty(prop.properties) ? `>${getPropertyXml(prop.properties!)}` : `>${prop.value || ''}` //Close tag output += !isEmpty(prop.namespace) ? `` : `` return output; }) return output; } const getModel = (): FeedProperty[] | undefined => { return cloneDeep(currentProperties.value); } const getXml = (): string => { if (currentProperties.value === undefined) { return ''; } return join(map(currentProperties.value, p => getPropertyXml([p])), '\n'); } const saveJson = (json: string | undefined): boolean => { if (isEmpty(json)) { //Clear all properties if json is undefined currentProperties.value = []; return true } try { const parsed = JSON.parse(json!); const props = map(parsed, (prop) => ({ name: prop.name, value: prop.value, namespace: prop.namespace, attributes: prop.attributes, properties: prop.properties })) //Remove any empty properties const nonEmpty = filter(props, p => !isEmpty(p.name)); //Set the properties currentProperties.value = nonEmpty; return true; } catch (err) { return false; } } const addProperties = (properties: FeedProperty[]) => { currentProperties.value = [...currentProperties.value, ...properties]; } return { getCurrentProperties, getXml, saveJson, getModel, addProperties } }