001package Torello.HTML; 002 003import java.util.Vector; 004import java.util.NoSuchElementException; 005 006import Torello.Java.UnreachableError; 007import Torello.HTML.NodeSearch.*; // Used for JavaDoc Comment Links 008 009/** 010 * The class {@link ReplaceNodes} offers a great <B><I>efficiency-improvement</I></B> optimization 011 * for modifying vectorized-HTML. HTML Pages can be very long, and the insertion or removal of a 012 * piece or snippet of HMTL may result in the shifting of hundreds (or even thousands!) of 013 * {@code HTMLNode's}. This can incur a non-trivial performance cost if many there are many 014 * updates and changes to be made to a page. 015 * 016 * <BR /><BR /><HR><BR /> 017 * 018 * <B CLASS=JDDescLabel>Exceprt from {@link #currentNodes()}:</B> 019 * 020 * <BR />{@code Replaceable's} are, sort-of, <B STYLE='color: red'>the exact opposite</B> of Java's 021 * {@code List} method {@code 'subList'}. According to the Sun / Oracle Documentation for 022 * {@code java.util.List.subList(int fromIndex, int toIndex)}, any changes ffinamade to an instance of a 023 * {@code 'subList'} are immediately reflected back into the original {@code List} from where they 024 * were created. 025 * 026 * <BR /><BR />The {@code List.subList} operation has the advantage of being extremely easy to 027 * work with - however, an HTML-Page {@code Vector} has the potential of being hundreds of 028 * nodes long. Any operations that involve insertion or deletion will likely be terribly 029 * inefficient. 030 * 031 * <BR /><BR /><B STYLE='color: red'><I>When the HTML inside of a {@code Replaceable} is 032 * modified - nothing happens to the original {@code Vector} whatsoever!</I></B>. Until a user 033 * requests that the original HTML-{@code Vector} be updated to reflect all changes that he or 034 * she has made, the original HTML remains untouched. When an update request is finally 035 * issued, all changes are made all at once, and at the same time! 036 * 037 * <BR /><BR />Again - see {@link ReplaceNodes#r(Vector, Iterable, boolean)} to understand 038 * how quick updates on HTML-Pages is done using the {@code Replaceable} interface. 039 * 040 * <BR /><BR /><HR><BR /> 041 * 042 * <B CLASS=JDDescLabel>Utilizing class {@link ReplaceNodes}:</B> 043 * 044 * <BR />Class {@link ReplaceNodes} offers three methods for performing these optimized replacement 045 * methods. These methods are listed below. The optimization that is utilized there is to first 046 * calculate the size / length of the updated {@code Vector}, and then do the entire update all at 047 * once. This eliminates to do any shifting and only performs a single resizing of the 048 * {@code Vector}. 049 * 050 * <BR /><BR />These methods will work in lock-step with interface {@code 'Replaceable'} to 051 * actually perform the update after all Vectorized-HTML has been changed, sufficiently as deemed 052 * by the programmer: 053 * 054 * <BR /><BR /><UL CLASS=JDUL> 055 * <LI><B>{@link ReplaceNodes#r(Vector, Iterable, boolean)}</B></LI> 056 * <LI><B>{@link ReplaceNodes#listLI(Vector, DotPair, ObjIntConsumer)}</B></LI> 057 * <LI><B>{@link ReplaceNodes#tableTR(Vector, DotPair, ObjIntConsumer)}</B></LI> 058 * </UL> 059 * 060 * <BR /><BR />The Java Doc Upgrader Tool in this JAR Library heavily relies on using instances of 061 * {@code Replaceable} to update and modify Java Doc HTML in a fast, simple & efficient manner. 062 * 063 * <BR /><BR />Though this class may look somewhat complicated to understand, in all reality it is 064 * actually very simple. Load a web-page from disk (or download one from the Internet) and run it 065 * through the parser (class {@link HTMLPage}) to make a Vectorized-HTML Page. Next, build a few 066 * instances of {@link SubSection} which hold <B><I>both</I></B> the location of an HTML snippet 067 * <B><I>and</I></B> HTML itself. 068 * 069 * <BR /><Br />Finallly, make whatever modifications you want to those HTML snippets, and call the 070 * <B>{@code ReplaceNodes}</B> method listed first in the list above! The page should be updated 071 * quickly with little cost overhead. 072 * 073 * <BR /><BR /><HR><BR /> 074 * 075 * <B CLASS=JDDescLabel>Peek Operation Replaceables</B> 076 * 077 * <BR />The class {@link InnerTagPeekInclusive} and {@link TagNodePeekInclusive} will always 078 * generate properly ordered / sorted <B STYLE='color: red;'><I>references that implement the 079 * {@code Replaceable} interface!</I></B> Furthermore, these instances will be ones that are 080 * sorted and do not overlap. 081 * 082 * <BR /><BR />This means that if a set or collection of {@code Replaceable's} were created using 083 * the {@code NodeSearch 'Peek'} Search-Classes, the 084 * {@link ReplaceNodes#r(Vector, Iterable, boolean)} requirements that the {@code Replaceable's} be 085 * ordered, sorted and non-overlapping would be automatically met. 086 * 087 * <BR /><BR />This interface is implemented by all return-values for the {@code NodeSearch} <B>Peek</B> 088 * operations. 089 * 090 * <BR /><BR /><UL CLASS=JDUL> 091 * <LI>{@link TextNodePeek}</LI> 092 * <LI>{@link CommentNodePeek}</LI> 093 * <LI>{@link TagNodePeek}</LI> 094 * <LI>{@link TagNodePeekInclusive}</LI> 095 * <LI>{@link InnerTagPeek}</LI> 096 * <LI>{@link InnerTagPeekInclusive}</LI> 097 * </UL> 098 */ 099public interface Replaceable extends Comparable<Replaceable> 100{ 101 // ******************************************************************************************** 102 // ******************************************************************************************** 103 // basic interface stuff 104 // ******************************************************************************************** 105 // ******************************************************************************************** 106 107 108 /** 109 * Java's {@code Comparable} interface requirements. 110 * 111 * @return An integer based on comparing the starting locations for two {@code Replaceable} 112 * instances. 113 */ 114 public default int compareTo(Replaceable other) 115 { return this.originalLocationStart() - other.originalLocationStart(); } 116 117 /** 118 * Supplies a hash-code 119 * 120 * @return The value returned by {@link #originalLocationStart()}, which must be unique among 121 * any list of {@code Replaceable's}. 122 */ 123 // It say this isn't allowed 124 // public default int hashCode() 125 // { return originalLocationStart(); } 126 127 128 // ******************************************************************************************** 129 // ******************************************************************************************** 130 // The 'addAll' - used by class ReplaceNodes 131 // ******************************************************************************************** 132 // ******************************************************************************************** 133 134 135 /** 136 * Reports how many nodes were copied into {@code this} instance. 137 * For implementing classes that inherit {@link NodeIndex}, this value will always be one. 138 * For others, it should report exactly how many {@code HTMLNode's} were copied. 139 * 140 * @return Number of nodes originally contained by {@code this} instance. 141 * 142 * <A ID=NOTE1> <!-- NOTE --> </A> 143 * 144 * <BR /><BR />The purpose of {@code Replaceable's} is to allow a user to modify HTML using 145 * a smaller sub-list, without having to operate on the entire HTML-{@code Vector} since adding 146 * & removing nodes is one variant of {@code Vector}-modification, the <I>original-size</I> 147 * may often differ from the <I>current-size</I>. 148 * 149 * <BR /><BR />When modifying HTML, if a web-page is broken into smaller-pieces, and changes 150 * are restricted to those smaller sub-lists (and the original page is rebuilt, <I>all at 151 * once</I>, after all changes have been made) then those modifications should require far-fewer 152 * time-consuming list-shift operations, tremendously improving the performance of the code. 153 */ 154 public int originalSize(); 155 156 /** 157 * Returns how many nodes are currently in {@code this} instance. 158 * 159 * @return Number of nodes. See explanation of the <B STYLE='color: red;'>original</B> size, 160 * versus the <B STYLE='color: red;'>current</B> size 161 * <B><CODE><A HREF='#NOTE1'>here</A></CODE></B> 162 */ 163 public int currentSize(); 164 165 /** 166 * Returns the <B STYLE='color: red;'>start</B>-location within the original 167 * page-{@code Vector} from whence the HTML contents of {@code this} instance were retrieved. 168 * 169 * <BR /><BR /><B CLASS=JDDescLabel>Start is Inclusive:</B> 170 * 171 * <BR />The returned value is <B STYLE='color: red;'><I>inclusive</I></B> of the actual, 172 * original-range of {@code this} instance. This means the first {@code HTMLNode} copied into 173 * {@code this} instance' internal data-structure was at {@code originalLocationStart()}. 174 * 175 * <BR /><BR /><B CLASS=JDDescLabel>Implementations of Replaceable:</B> 176 * 177 * <BR />The two concrete implementatons of this interface ({@link NodeIndex} and 178 * {@link SubSection}) - both enforce the {@code 'final'} modifier on their location-fields. 179 * (See: {@link NodeIndex#index} and {@link SubSection#location}). 180 * 181 * @return The {@code Vector} <B STYLE='color: red;'>start</B>-index from whence this HTML was 182 * copied. 183 */ 184 public int originalLocationStart(); 185 186 /** 187 * Returns the <B STYLE='color: red;'>end</B>-location within the original 188 * page-{@code Vector} from whence the HTML contents of {@code this} instance were retrieved. 189 * 190 * <BR /><BR /><B CLASS=JDDescLabel>Start is Exclusive:</B> 191 * 192 * <BR />The returned value is <B STYLE='color: red;'><I>exclusive</I></B> of the actual, 193 * original-range of {@code this} instance. This means the last {@code HTMLNode} copied into 194 * {@code this} instance' internal data-structure was at {@code originalLocationEnd() - 1} 195 * 196 * <BR /><BR /><B CLASS=JDDescLabel>Implementations of Replaceable:</B> 197 * 198 * <BR />The two concrete implementatons of this interface ({@link NodeIndex} and 199 * {@link SubSection}) - both enforce the {@code 'final'} modifier on their location-fields. 200 * (See: {@link NodeIndex#index} and {@link SubSection#location}). 201 * 202 * @return The {@code Vector} <B STYLE='color: red;'>end</B>-index from whence this HTML was 203 * copied. 204 */ 205 public int originalLocationEnd(); 206 207 208 /** 209 * All nodes currently contained by this {@code Replaceable}. The concrete-classes which 210 * implement {@code Replaceable} ({@link SubSection} & {@link TagNodeIndex}) allow for the 211 * html they hold to be modified. The modification to a {@code Replaceable} happens 212 * independently from the original HTML Page out of which it was copied. 213 * 214 * <BR /><BR />{@code Replaceable's} are, sort-of, <B STYLE='color: red'>the exact opposite</B> 215 * of Java's {@code List} method {@code 'subList'}. According to the Sun / Oracle 216 * Documentation for {@code java.util.List.subList(int fromIndex, int toIndex)}, any changes 217 * made to an instance of a {@code 'subList'} are immediately reflected back into the original 218 * {@code List} from where they were created. 219 * 220 * <BR /><BR />The {@code List.subList} operation has the advantage of being extremely easy to 221 * work with - however, an HTML-Page {@code Vector} has the potential of being hundreds of 222 * nodes long. Any operations that involve insertion or deletion will likely be terribly 223 * inefficient. 224 * 225 * <BR /><BR /><B STYLE='color: red'><I>When the HTML inside of a {@code Replaceable} is 226 * modified - nothing happens to the original {@code Vector} whatsoever!</I></B>. Until a user 227 * requests that the original HTML-{@code Vector} be updated to reflect all changes that he or 228 * she has made, the original HTML remains untouched. When an update request is finally 229 * issued, all changes are made all at once, and at the same time! 230 * 231 * <BR /><BR />Again - see {@link ReplaceNodes#r(Vector, Iterable, boolean)} to understand 232 * how quick updates on HTML-Pages is done using the {@code Replaceable} interface. 233 * 234 * @return An HTML-{@code Vector} of the nodes. 235 */ 236 public Vector<HTMLNode> currentNodes(); 237 238 /** 239 * The first node <B STYLE='color: red;'>currently</B> contained by this {@code Replaceable} 240 * @return The First Node 241 */ 242 public HTMLNode firstCurrentNode(); 243 244 /** 245 * The last node <B STYLE='color: red;'>currently</B> contained by this {@code Replaceable} 246 * @return The last node 247 */ 248 public HTMLNode lastCurrentNode(); 249 250 251 // ******************************************************************************************** 252 // ******************************************************************************************** 253 // The 'addAll' - used by class ReplaceNodes 254 // ******************************************************************************************** 255 // ******************************************************************************************** 256 257 258 /** 259 * Add all nodes currently retained in {@code this} instance into the HTML-{@code Vector} 260 * parameter {@code html}. The nodes are appended to the end of {@code 'html'}. Implementing 261 * classes {@link NodeIndex} and {@link SubSection} simply use the Java {@code Vector} method's 262 * {@code add} (for {@code NodeIndex}) and {@code addAll} (for {@code SubSection}). 263 * 264 * @param html The HTML-{@code Vector} into which the nodes will be appended (to the end of 265 * this {@code Vector}, using {@code Vector} methods {@code add} or {@code addAll} dependent 266 * upon whether one or more-than-one nodes are being inserted). 267 * 268 * @return The result of {@code Vector} method {@code add}, or method {@code allAll} 269 */ 270 public boolean addAllInto(Vector<HTMLNode> html); 271 272 /** 273 * Add all nodes currently retained in {@code this} instance into the HTML-{@code Vector} 274 * parameter {@code html}. 275 * 276 * @param index The {@code 'html'} parameter's {@code Vector}-index where these nodes are to 277 * be inserted 278 * 279 * @param html The HTML-{@code Vector} into which the nodes will be appended (to the end of 280 * this {@code Vector}, using {@code Vector} methods {@code add} or {@code addAll} dependent 281 * upon whether one or more-than-one nodes are being inserted). 282 * 283 * @return The result of {@code Vector} method {@code add}, or method {@code allAll} 284 */ 285 public boolean addAllInto(int index, Vector<HTMLNode> html); 286 287 288 // ******************************************************************************************** 289 // ******************************************************************************************** 290 // update - inefficient, unless only used for a single page-update 291 // ******************************************************************************************** 292 // ******************************************************************************************** 293 294 295 /** 296 * <EMBED CLASS='external-html' DATA-FILE-ID=REPL_UPDATE_DESC> 297 * 298 * @param originalHTML The original page-{@code Vector} where the nodes in {@code this} 299 * instance were retrieved 300 * 301 * @return The change in the size of the {@code Vector} 302 * 303 * @see ReplaceNodes#r(Vector, Iterable, boolean) 304 * 305 * @throws IndexOutOfBoundsException If {@link #originalLocationStart()} or 306 * {@link #originalLocationEnd()} are not within the bounds of the input html-page. 307 */ 308 public int update(Vector<HTMLNode> originalHTML); 309 310 311 // ******************************************************************************************** 312 // ******************************************************************************************** 313 // Building New Instance: Change the HTML of a Replaceable, **WITHOUT USING SUB-CLASS' FIELDS** 314 // ******************************************************************************************** 315 // ******************************************************************************************** 316 317 318 /** 319 * This method may be used for arbitrary replacements. An instance of {@code NodeIndex} 320 * (one of its sub-classes) only contains a single {@code HTMLNode}. To change that to a list, 321 * or to remove that node altogether, invoke this method, and a new instance of 322 * {@code Replaceable} will be automatically created, and returned. 323 * 324 * <BR /><BR />This may be a little tricky at first, but the primary reason for using this 325 * method is that size-changes that would make a <B STYLE='color: red;'>single-node</B> 326 * ({@link NodeIndex} instance) into a <B STYLE='color: red;'>list</B> ({@link SubSection} 327 * instance), or vice-versa, would require building a different type of {@code Replaceable} 328 * instance. This method will automatically build that instance into a {@code Replaceable} 329 * that retains its <I>original location</I>, but reflects its <I>new contents and size</I>. 330 * 331 * <BR /><BR />Once again, the primary impetus for this method is using it with an in-place 332 * page update having multiple-replacements, <I>vis-a-vis</I> a call to 333 * {@link ReplaceNodes#r(Vector, Iterable, boolean)}. 334 * 335 * @param newHTML The contents of {@code 'this'} replaceable will be assigned to the the html 336 * in this parameter. 337 * 338 * @return a new replaceable whose <I><B STYLE='color: red;'>location</B> has not changed</I>, 339 * but whose contents are the contents of {@code newHTML}. 340 */ 341 public default Replaceable setHTML(Vector<HTMLNode> newHTML) 342 { 343 final int oldSize = this.originalSize(); 344 final int newSize = newHTML.size(); 345 final int sPos = this.originalLocationStart(); 346 final int ePos = this.originalLocationEnd(); 347 348 // SubSection ==> SubSection 349 if ((oldSize > 1) && (newSize > 1)) 350 return new SubSection(new DotPair(sPos, ePos - 1), newHTML); 351 352 // NodeIndex ==> NodeIndex 353 if ((oldSize == 1) && (newSize == 1)) 354 return NodeIndex.newNodeIndex(sPos, newHTML.elementAt(0)); 355 356 // Empty ==> Empty 357 if ((oldSize == 0) && (newSize == 0)) 358 return empty(sPos); 359 360 return new ReplaceableAdapter(sPos, ePos, newHTML); 361 } 362 363 /** 364 * See the description in {@link #setHTML(Vector)} to understand when to use {@code setHTML}. 365 * This method is identical, but accepts a single {@link HTMLNode} instance, instead of an html 366 * list. 367 * 368 * @param newHTML The contents of {@code 'this'} replaceable will be assigned to the the html 369 * contained by {@code newHTML}. (The returned instance will have the same location values) 370 * 371 * @return a new replaceable whose <I><B STYLE='color: red;'>location</B> has not changed</I>, 372 * but whose contents are {@code newHTML}. 373 * 374 * @see #setHTML(Vector) 375 */ 376 public default Replaceable setHTML(HTMLNode newHTML) 377 { 378 // NodeIndex ==> NodeIndex 379 if (this.originalSize() == 1) 380 return NodeIndex.newNodeIndex(this.originalLocationStart(), newHTML); 381 382 Vector<HTMLNode> v = new Vector<>(); 383 v.add(newHTML); 384 385 return new ReplaceableAdapter 386 (this.originalLocationStart(), this.originalLocationEnd(), v); 387 } 388 389 /** 390 * Removes all HTML from this {@code Replaceable}, such that's {@link #currentNodes()} would 391 * return an empty HTML list. 392 * 393 * @return a new replaceable whose original <I><B STYLE='color: red;'>location</B> has not 394 * changed</I>, but whose contents are empty. 395 * 396 * @see #setHTML(Vector) 397 */ 398 public default Replaceable clearHTML() 399 { 400 if (currentSize() == 0) return Replaceable.empty(originalLocationStart()); 401 402 return new ReplaceableAdapter 403 (originalLocationStart(), originalLocationEnd(), new Vector<>()); 404 } 405 406 407 // ******************************************************************************************** 408 // ******************************************************************************************** 409 // Creating Replacebles, using the Adapter, avoiding the Concrete-Class' exception checks. 410 // ******************************************************************************************** 411 // ******************************************************************************************** 412 413 414 /** 415 * Provides a mechanism for creating a {@link SubSection} instance whose {@code html} does not 416 * match the size of the {@code location} where that {@code html} is to be placed. 417 * 418 * @param location The range in any HTML Page by which the new {@code html} will be replaced. 419 * 420 * @param html The html that will ultimately be used to replace the current-html, <I>on a 421 * web-page, at the specified {@code location}</I>. 422 * 423 * @return An instance of a {@code Replaceable}, that is, in-effect, a {@link SubSection}, but 424 * one whose location/bounds do not match the size of the new-{@code html}. 425 * 426 * <BR /><BR /><B STYLE='color: red;'>NOTE:</B> This method allows a user to bypass the 427 * exception-check that class {@code SubSection} performs when building an instance of that 428 * class. 429 */ 430 public static Replaceable create(DotPair location, Vector<HTMLNode> html) 431 { return new ReplaceableAdapter(location.start, location.end + 1, html); } 432 433 /** 434 * Creates a new {@code Replaceable} instance whose original-location is just a single-node, 435 * but whose new {@code html} may be an arbitrarily-sized html {@code Vector}. 436 * 437 * @param location The node in any HTML Page which shall be replaced by {@code 'html'} 438 * 439 * @param html The html that will replace the node on an HTML page located at 440 * {@code 'location'} 441 * 442 * @return An instance of a {@code Replaceable} that is, in effect, a {@link SubSection}, 443 * but one whose location/bounds are not (necessarily) a single page-index. 444 * 445 * <BR /><BR /><B STYLE='color: red;'>NOTE:</B> This method allows a user to bypass the 446 * requirement that a {@code NodeIndex} occupy only a single-node. 447 */ 448 public static Replaceable create(int location, Vector<HTMLNode> html) 449 { return new ReplaceableAdapter(location, location + 1, html); } 450 451 /** 452 * Creates a new {@code Replaceable} instance whose original-location had zero-length 453 * 454 * @param location The location in any HTML Page into which the {@code 'html'} shall be 455 * inserted 456 * 457 * @param html The html that will be inserted into an HTML Page at index {@code 'location'} 458 * 459 * @return An instance of a {@code Replaceable} - whose original-location had a zero-length 460 */ 461 public static Replaceable createInsertion(int location, Vector<HTMLNode> html) 462 { return new ReplaceableAdapter(location, location, html); } 463 464 465 // ******************************************************************************************** 466 // ******************************************************************************************** 467 // After updating an HTML-Page, this will incorporate the changed size & location 468 // ******************************************************************************************** 469 // ******************************************************************************************** 470 471 472 /** 473 * This method is mostly of internal-use, mainly by 474 * {@link ReplaceNodes#r(Vector, Iterable, boolean)} 475 * 476 * @param sPos The new location in an html page-{@code Vector} where the contents of this 477 * {@code Replaceable} are now located. 478 * 479 * @return A new instance, whose html-contents are identical, but is located at {@code 'sPos'} 480 * (and having an ending-location of {@code sPos + currentSize()}). 481 */ 482 public default Replaceable moveAndUpdate(int sPos) 483 { 484 // IMPORTANT: This method is extremely un-important! It looks kind of unreadable. 485 // All it is doing is REGISTERING the changes to his SubSection or NodeIndex 486 // by building a new SubSection or new NodeIndex. 487 // 488 // PRIMARILY: Since the *WHOLE POINT* is to make all of the changes to an HTML Page, first, 489 // before doing an update ... Having updated Replaceable's is mostly a waste. 490 // Specifically, after the page has been updated, keeping the sub-parts of the 491 // page would no longer be necessary! 492 // 493 // ReplaceNodes: This class offers the option to 'updateReplaceablesAfterBuild' in case 494 // (for whatever reason) the user has decided another round of page updates is 495 // needed. 496 497 final int size = currentSize(); 498 499 switch (size) 500 { 501 case 0: return Replaceable.empty(sPos); 502 case 1: return NodeIndex.newNodeIndex(sPos, firstCurrentNode()); 503 504 default: 505 return new SubSection( 506 // DotPair.end is inclusive, so subtract 1 507 new DotPair(sPos, sPos + size - 1), 508 509 // The current HTML Vector 510 currentNodes() 511 ); 512 } 513 } 514 515 516 // ******************************************************************************************** 517 // ******************************************************************************************** 518 // Creating an Empty Replaceable 519 // ******************************************************************************************** 520 // ******************************************************************************************** 521 522 523 /** 524 * Returns an empty {@code Replaceable} (an instance having 0 {@code HTMLNode's}) located at 525 * {@code sPos}. 526 * 527 * <BR /><BR /><B CLASS=JDDescLabel>NoSuchElementException:</B> 528 * 529 * <BR />Attempting to retrieve nodes from the returned-instance will generate a 530 * Java {@code NoSuchElementException}. 531 * 532 * @param sPos The location of this zero-element {@code Replaceable} 533 * @return The new instance. 534 */ 535 public static Replaceable empty(final int sPos) 536 { return new ReplaceableAdapter(sPos, sPos, new Vector<>()); } 537 538 539 // ******************************************************************************************** 540 // ******************************************************************************************** 541 // Synthetic 542 // ******************************************************************************************** 543 // ******************************************************************************************** 544 545 546 /** 547 * Identifies whether or not {@code 'this'} instance is an anonymous class, that was built from 548 * the (internal) {@code ReplaceableAdapter}. 549 * 550 * @return {@code TRUE} if {@code 'this'} is <B STYLE='color: red;'>neither</B> an instance 551 * that inherits {@code NodeIndex} <B STYLE='color: red;'>nor</B> inherits {@link SubSection}. 552 * Such instances are built from an internal {@code ReplaceableAdapter}, and are produced by 553 * the methods: {@link #setHTML(Vector)}, {@link #setHTML(HTMLNode)}, {@link #clearHTML()}, 554 * and {@link #empty(int)}. 555 */ 556 public default boolean isSynthetic() { return false; } 557}