001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.bean.html5; 018 019import static org.apache.juneau.marshall.xml.XmlFormat.*; 020import static org.apache.juneau.commons.utils.Shorts.*; 021 022import java.util.*; 023 024import org.apache.juneau.commons.bean.*; 025import org.apache.juneau.commons.conversion.*; 026import org.apache.juneau.marshall.*; 027import org.apache.juneau.marshall.xml.*; 028 029/** 030 * A subclass of HTML elements that contain only other elements, not text. 031 * 032 * <h5 class='section'>See Also:</h5><ul> 033 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanHtml5">juneau-bean-html5</a> 034 * </ul> 035 * 036 * @param <SELF> The self type for fluent setters. 037 */ 038@SuppressWarnings({ 039 "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name. 040}) 041public abstract class HtmlElementContainer<SELF extends HtmlElementContainer<SELF>> extends HtmlElement<SELF> { 042 043 private List<Object> children; 044 045 /** 046 * Adds a child element to this element. 047 * 048 * @param value The child to add as a child element. Can be <jk>null</jk> (a <jk>null</jk> entry is added to the children list). 049 * @return This object. 050 */ 051 public SELF child(Object value) { 052 if (this.children == null) 053 this.children = new LinkedList<>(); 054 this.children.add(value); 055 return self(); 056 } 057 058 /** 059 * Adds one or more child elements to this element. 060 * 061 * @param value The children to add as child elements. Must not be <jk>null</jk>. 062 * @return This object. 063 */ 064 public SELF children(Object...value) { 065 if (value.length > 0) { 066 if (this.children == null) 067 this.children = new LinkedList<>(); 068 for (var c : value) 069 this.children.add(c); 070 } 071 return self(); 072 } 073 074 /** 075 * Returns the child node at the specified index. 076 * 077 * @param <T> The class type of the node. 078 * @param type The class type of the node. 079 * @param index The index of the node in the list of children. 080 * @return The child node, or <jk>null</jk> if it doesn't exist. 081 * @throws InvalidConversionException If node is not the expected type. 082 */ 083 public <T> T getChild(Class<T> type, int index) { 084 return (children == null || children.size() <= index || index < 0 ? null : BasicConverter.INSTANCE.to(children.get(index), type)); 085 } 086 087 /** 088 * Returns the child node at the specified index. 089 * 090 * @param index The index of the node in the list of children. 091 * @return The child node, or <jk>null</jk> if it doesn't exist. 092 */ 093 public Object getChild(int index) { 094 return (children == null || children.size() <= index || index < 0 ? null : children.get(index)); 095 } 096 097 /** 098 * Returns the child node at the specified address. 099 * 100 * <p> 101 * Indexes are zero-indexed. 102 * 103 * <p> 104 * For example, calling <c>getChild(1,2,3);</c> will return the 4th child of the 3rd child of the 2nd child. 105 * 106 * @param index The child indexes. 107 * @return The child node, or <jk>null</jk> if it doesn't point to a valid child. 108 */ 109 public Object getChild(int...index) { 110 if (index.length == 0) 111 return null; 112 if (index.length == 1) 113 return getChild(index[0]); 114 Object c = this; 115 for (var element : index) { 116 if (c instanceof HtmlElementMixed<?> c2) 117 c = c2.getChild(element); 118 else if (c instanceof HtmlElementContainer<?> c2) 119 c = c2.getChild(element); 120 else 121 return null; 122 } 123 return c; 124 } 125 126 /** 127 * The children of this element. 128 * 129 * @return The children of this element, or <jk>null</jk> if no children are set. 130 */ 131 @Xml(format = FREEFORM) 132 @BeanProp(name="c") @MarshalledProp(dictionary=HtmlBeanDictionary.class) 133 public List<Object> getChildren() { return u(children); } 134 135 /** 136 * Sets the children for this container. 137 * 138 * @param children The new children for this container. Can be <jk>null</jk> to clear all children. 139 * @return This object. 140 */ 141 @BeanProp("c") 142 public SELF setChildren(List<Object> children) { 143 this.children = children; 144 return self(); 145 } 146}