/** * Copyright 2015 CANAL+ Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import arrayFind from "../../../utils/array_find"; import arrayIncludes from "../../../utils/array_includes"; import isNonEmptyString from "../../../utils/is_non_empty_string"; import startsWith from "../../../utils/starts_with"; export type IStyleList = Partial>; // Object defining a single element's (region/style...) style parameters export interface IStyleObject { id: string; // The ID of the current element style: IStyleList; // All set style preference extendsStyles: string[]; // ID of the "style" elements this element extends } /** * Retrieve the attributes given in arguments in the given nodes and their * associated style(s)/region. * The first notion of the attribute encountered will be taken (by looping * through the given nodes in order). * * TODO manage IDREFS (plural) for styles and regions, that is, multiple one * @param {Array.} attributes * @param {Array.} nodes * @param {Array.} styles * @param {Array.} regions * @returns {Object} */ export function getStylingAttributes( attributes: string[], nodes: Node[], styles: IStyleObject[], regions: IStyleObject[], ): IStyleList { const currentStyle: IStyleList = {}; const leftAttributes = attributes.slice(); for (let i = 0; i <= nodes.length - 1; i++) { const node = nodes[i]; if (node !== undefined) { let styleID: string | undefined; let regionID: string | undefined; // 1. the style is directly set on a "tts:" attribute if (node.nodeType === Node.ELEMENT_NODE) { const element = node as Element; for (let j = 0; j <= element.attributes.length - 1; j++) { const attribute = element.attributes[j]; const name = attribute.name; if (name === "style") { styleID = attribute.value; } else if (name === "region") { regionID = attribute.value; } else { const nameWithoutTTS = name.substring(4); if (arrayIncludes(leftAttributes, nameWithoutTTS)) { currentStyle[nameWithoutTTS] = attribute.value; leftAttributes.splice(j, 1); if (leftAttributes.length === 0) { return currentStyle; } } } } } // 2. the style is referenced on a "style" attribute if (isNonEmptyString(styleID)) { const style = arrayFind(styles, (x) => x.id === styleID); if (style !== undefined) { for (let j = 0; j <= leftAttributes.length - 1; j++) { const attribute = leftAttributes[j]; if (!isNonEmptyString(currentStyle[attribute])) { if (isNonEmptyString(style.style[attribute])) { currentStyle[attribute] = style.style[attribute]; leftAttributes.splice(j, 1); if (leftAttributes.length === 0) { return currentStyle; } j--; } } } } } // 3. the node reference a region (which can have a value for the // corresponding style) if (isNonEmptyString(regionID)) { const region = arrayFind(regions, (x: IStyleObject) => x.id === regionID); if (region !== undefined) { for (let j = 0; j <= leftAttributes.length - 1; j++) { const attribute = leftAttributes[j]; if (!isNonEmptyString(currentStyle[attribute])) { if (isNonEmptyString(region.style[attribute])) { currentStyle[attribute] = region.style[attribute]; leftAttributes.splice(j, 1); if (leftAttributes.length === 0) { return currentStyle; } j--; } } } } } } } return currentStyle; } /** * Returns the styling directly linked to an element. * @param {Node} node * @returns {Object} */ export function getStylingFromElement(node: Node): IStyleList { if (node.nodeType !== Node.ELEMENT_NODE) { return {}; } const element = node as Element; const currentStyle: IStyleList = {}; for (let i = 0; i <= element.attributes.length - 1; i++) { const styleAttribute = element.attributes[i]; if (startsWith(styleAttribute.name, "tts")) { const nameWithoutTTS = styleAttribute.name.substring(4); currentStyle[nameWithoutTTS] = styleAttribute.value; } } return currentStyle; }