/* * Copyright 2011 Google Inc. * * 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. */ package com.google.gwt.dom.builder.client; import com.google.gwt.dom.builder.shared.ElementBuilderBase; import com.google.gwt.dom.builder.shared.ElementBuilderImpl; import com.google.gwt.dom.builder.shared.InputBuilder; import com.google.gwt.dom.builder.shared.StylesBuilder; import com.google.gwt.dom.client.ButtonElement; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.InputElement; import com.google.gwt.dom.client.QuoteElement; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.TableColElement; import com.google.gwt.dom.client.TableSectionElement; import com.google.gwt.safehtml.shared.SafeHtml; /** * Implementation of methods in * {@link com.google.gwt.dom.builder.shared.ElementBuilderBase} used to render * Elements using DOM manipulation. */ class DomBuilderImpl extends ElementBuilderImpl { /* * Common element builders are created on initialization to avoid null checks. * Less common element builders are created lazily to avoid unnecessary object * creation. */ private DomAnchorBuilder anchorBuilder; private DomAreaBuilder areaBuilder; private DomAudioBuilder audioBuilder; private DomBaseBuilder baseBuilder; private DomBodyBuilder bodyBuilder; private DomBRBuilder brBuilder; private DomButtonBuilder buttonBuilder; private DomCanvasBuilder canvasBuilder; private final DomDivBuilder divBuilder = new DomDivBuilder(this); private DomDListBuilder dListBuilder; private final DomElementBuilder elementBuilder = new DomElementBuilder(this); private DomFieldSetBuilder fieldSetBuilder; private DomFormBuilder formBuilder; private DomFrameBuilder frameBuilder; private DomFrameSetBuilder frameSetBuilder; private DomHeadBuilder headBuilder; private DomHeadingBuilder headingBuilder; private DomHRBuilder hrBuilder; private DomIFrameBuilder iFrameBuilder; private DomImageBuilder imageBuilder; private final DomInputBuilder inputBuilder = new DomInputBuilder(this); private DomLabelBuilder labelBuilder; private DomLegendBuilder legendBuilder; private final DomLIBuilder liBuilder = new DomLIBuilder(this); private DomLinkBuilder linkBuilder; private DomMapBuilder mapBuilder; private DomMetaBuilder metaBuilder; private DomOListBuilder oListBuilder; private final DomOptionBuilder optionBuilder = new DomOptionBuilder(this); private DomOptGroupBuilder optGroupBuilder; private DomParagraphBuilder paragraphBuilder; private DomParamBuilder paramBuilder; private DomPreBuilder preBuilder; private DomQuoteBuilder quoteBuilder; private DomScriptBuilder scriptBuilder; private DomSelectBuilder selectBuilder; private DomSourceBuilder sourceBuilder; private final DomSpanBuilder spanBuilder = new DomSpanBuilder(this); private final StylesBuilder stylesBuilder = new DomStylesBuilder(this); private DomStyleBuilder styleBuilder; private DomTableBuilder tableBuilder; private final DomTableCellBuilder tableCellBuilder = new DomTableCellBuilder(this); private DomTableCaptionBuilder tableCaptionBuilder; private DomTableColBuilder tableColBuilder; private final DomTableRowBuilder tableRowBuilder = new DomTableRowBuilder(this); private DomTableSectionBuilder tableSectionBuilder; private DomTextAreaBuilder textAreaBuilder; private DomUListBuilder uListBuilder; private DomVideoBuilder videoBuilder; /** * The root element of the DOM structure being built. */ private Element rootElement; /** * The element at the top of the stack. We use DOM manipulation to move up and * down the stack. */ private Element currentElement; public DomAnchorBuilder startAnchor() { if (anchorBuilder == null) { anchorBuilder = new DomAnchorBuilder(this); } start(Document.get().createAnchorElement(), anchorBuilder); return anchorBuilder; } public DomAreaBuilder startArea() { if (areaBuilder == null) { areaBuilder = new DomAreaBuilder(this); } start(Document.get().createAreaElement(), areaBuilder); return areaBuilder; } public DomAudioBuilder startAudio() { if (audioBuilder == null) { audioBuilder = new DomAudioBuilder(this); } start(Document.get().createAudioElement(), audioBuilder); return audioBuilder; } public DomBaseBuilder startBase() { if (baseBuilder == null) { baseBuilder = new DomBaseBuilder(this); } start(Document.get().createBaseElement(), baseBuilder); return baseBuilder; } public DomQuoteBuilder startBlockQuote() { return startQuote(Document.get().createBlockQuoteElement()); } public DomBodyBuilder startBody() { if (bodyBuilder == null) { bodyBuilder = new DomBodyBuilder(this); } start(Document.get().createElement("body"), bodyBuilder); return bodyBuilder; } public DomBRBuilder startBR() { if (brBuilder == null) { brBuilder = new DomBRBuilder(this); } start(Document.get().createBRElement(), brBuilder); return brBuilder; } public InputBuilder startButtonInput() { return startInput(Document.get().createButtonInputElement()); } public DomCanvasBuilder startCanvas() { if (canvasBuilder == null) { canvasBuilder = new DomCanvasBuilder(this); } start(Document.get().createCanvasElement(), canvasBuilder); return canvasBuilder; } public InputBuilder startCheckboxInput() { return startInput(Document.get().createCheckInputElement()); } public DomTableColBuilder startCol() { return startTableCol(Document.get().createColElement()); } public DomTableColBuilder startColGroup() { return startTableCol(Document.get().createColGroupElement()); } public DomDivBuilder startDiv() { start(Document.get().createDivElement(), divBuilder); return divBuilder; } public DomDListBuilder startDList() { if (dListBuilder == null) { dListBuilder = new DomDListBuilder(this); } start(Document.get().createDLElement(), dListBuilder); return dListBuilder; } public DomFieldSetBuilder startFieldSet() { if (fieldSetBuilder == null) { fieldSetBuilder = new DomFieldSetBuilder(this); } start(Document.get().createFieldSetElement(), fieldSetBuilder); return fieldSetBuilder; } public InputBuilder startFileInput() { return startInput(Document.get().createFileInputElement()); } public DomFormBuilder startForm() { if (formBuilder == null) { formBuilder = new DomFormBuilder(this); } start(Document.get().createFormElement(), formBuilder); return formBuilder; } public DomFrameBuilder startFrame() { if (frameBuilder == null) { frameBuilder = new DomFrameBuilder(this); } start(Document.get().createFrameElement(), frameBuilder); return frameBuilder; } public DomFrameSetBuilder startFrameSet() { if (frameSetBuilder == null) { frameSetBuilder = new DomFrameSetBuilder(this); } start(Document.get().createFrameSetElement(), frameSetBuilder); return frameSetBuilder; } public DomHeadingBuilder startH1() { return startHeading(1); } public DomHeadingBuilder startH2() { return startHeading(2); } public DomHeadingBuilder startH3() { return startHeading(3); } public DomHeadingBuilder startH4() { return startHeading(4); } public DomHeadingBuilder startH5() { return startHeading(5); } public DomHeadingBuilder startH6() { return startHeading(6); } public DomHeadBuilder startHead() { if (headBuilder == null) { headBuilder = new DomHeadBuilder(this); } start(Document.get().createHeadElement(), headBuilder); return headBuilder; } public InputBuilder startHiddenInput() { return startInput(Document.get().createHiddenInputElement()); } public DomHRBuilder startHR() { if (hrBuilder == null) { hrBuilder = new DomHRBuilder(this); } start(Document.get().createHRElement(), hrBuilder); return hrBuilder; } public DomIFrameBuilder startIFrame() { if (iFrameBuilder == null) { iFrameBuilder = new DomIFrameBuilder(this); } start(Document.get().createIFrameElement(), iFrameBuilder); return iFrameBuilder; } public DomImageBuilder startImage() { if (imageBuilder == null) { imageBuilder = new DomImageBuilder(this); } start(Document.get().createImageElement(), imageBuilder); return imageBuilder; } public InputBuilder startImageInput() { return startInput(Document.get().createImageInputElement()); } /** * Start an input using the specified InputElement. */ public DomInputBuilder startInput(InputElement input) { start(input, inputBuilder); return inputBuilder; } public DomLabelBuilder startLabel() { if (labelBuilder == null) { labelBuilder = new DomLabelBuilder(this); } start(Document.get().createLabelElement(), labelBuilder); return labelBuilder; } public DomLegendBuilder startLegend() { if (legendBuilder == null) { legendBuilder = new DomLegendBuilder(this); } start(Document.get().createLegendElement(), legendBuilder); return legendBuilder; } public DomLIBuilder startLI() { start(Document.get().createLIElement(), liBuilder); return liBuilder; } public DomLinkBuilder startLink() { if (linkBuilder == null) { linkBuilder = new DomLinkBuilder(this); } start(Document.get().createLinkElement(), linkBuilder); return linkBuilder; } public DomMapBuilder startMap() { if (mapBuilder == null) { mapBuilder = new DomMapBuilder(this); } start(Document.get().createMapElement(), mapBuilder); return mapBuilder; } public DomMetaBuilder startMeta() { if (metaBuilder == null) { metaBuilder = new DomMetaBuilder(this); } start(Document.get().createMetaElement(), metaBuilder); return metaBuilder; } public DomOListBuilder startOList() { if (oListBuilder == null) { oListBuilder = new DomOListBuilder(this); } start(Document.get().createOLElement(), oListBuilder); return oListBuilder; } public DomOptGroupBuilder startOptGroup() { if (optGroupBuilder == null) { optGroupBuilder = new DomOptGroupBuilder(this); } start(Document.get().createOptGroupElement(), optGroupBuilder); return optGroupBuilder; } public DomOptionBuilder startOption() { start(Document.get().createOptionElement(), optionBuilder); return optionBuilder; } public DomParagraphBuilder startParagraph() { if (paragraphBuilder == null) { paragraphBuilder = new DomParagraphBuilder(this); } start(Document.get().createPElement(), paragraphBuilder); return paragraphBuilder; } public DomParamBuilder startParam() { if (paramBuilder == null) { paramBuilder = new DomParamBuilder(this); } start(Document.get().createParamElement(), paramBuilder); return paramBuilder; } public InputBuilder startPasswordInput() { return startInput(Document.get().createPasswordInputElement()); } public DomPreBuilder startPre() { if (preBuilder == null) { preBuilder = new DomPreBuilder(this); } start(Document.get().createPreElement(), preBuilder); return preBuilder; } public DomButtonBuilder startPushButton() { return startButton(Document.get().createPushButtonElement()); } public DomQuoteBuilder startQuote() { return startQuote(Document.get().createQElement()); } public InputBuilder startRadioInput(String name) { return startInput(Document.get().createRadioInputElement(name)); } public DomButtonBuilder startResetButton() { return startButton(Document.get().createResetButtonElement()); } public InputBuilder startResetInput() { return startInput(Document.get().createSubmitInputElement()); } public DomScriptBuilder startScript() { if (scriptBuilder == null) { scriptBuilder = new DomScriptBuilder(this); } start(Document.get().createScriptElement(), scriptBuilder); return scriptBuilder; } public DomSelectBuilder startSelect() { if (selectBuilder == null) { selectBuilder = new DomSelectBuilder(this); } start(Document.get().createSelectElement(), selectBuilder); return selectBuilder; } public DomSourceBuilder startSource() { if (sourceBuilder == null) { sourceBuilder = new DomSourceBuilder(this); } start(Document.get().createSourceElement(), sourceBuilder); return sourceBuilder; } public DomSpanBuilder startSpan() { start(Document.get().createSpanElement(), spanBuilder); return spanBuilder; } public DomStyleBuilder startStyle() { if (styleBuilder == null) { styleBuilder = new DomStyleBuilder(this); } start(Document.get().createStyleElement(), styleBuilder); return styleBuilder; } public DomButtonBuilder startSubmitButton() { return startButton(Document.get().createSubmitButtonElement()); } public InputBuilder startSubmitInput() { return startInput(Document.get().createSubmitInputElement()); } public DomTableBuilder startTable() { if (tableBuilder == null) { tableBuilder = new DomTableBuilder(this); } start(Document.get().createTableElement(), tableBuilder); return tableBuilder; } public DomTableCaptionBuilder startTableCaption() { if (tableCaptionBuilder == null) { tableCaptionBuilder = new DomTableCaptionBuilder(this); } start(Document.get().createCaptionElement(), tableCaptionBuilder); return tableCaptionBuilder; } public DomTableSectionBuilder startTBody() { return startTableSection(Document.get().createTBodyElement()); } public DomTableCellBuilder startTD() { start(Document.get().createTDElement(), tableCellBuilder); return tableCellBuilder; } public DomTextAreaBuilder startTextArea() { if (textAreaBuilder == null) { textAreaBuilder = new DomTextAreaBuilder(this); } start(Document.get().createTextAreaElement(), textAreaBuilder); return textAreaBuilder; } public DomTableSectionBuilder startTFoot() { return startTableSection(Document.get().createTFootElement()); } public DomTableCellBuilder startTH() { start(Document.get().createTHElement(), tableCellBuilder); return tableCellBuilder; } public DomTableSectionBuilder startTHead() { return startTableSection(Document.get().createTHeadElement()); } public DomTableRowBuilder startTR() { start(Document.get().createTRElement(), tableRowBuilder); return tableRowBuilder; } public DomUListBuilder startUList() { if (uListBuilder == null) { uListBuilder = new DomUListBuilder(this); } start(Document.get().createULElement(), uListBuilder); return uListBuilder; } public DomVideoBuilder startVideo() { if (videoBuilder == null) { videoBuilder = new DomVideoBuilder(this); } start(Document.get().createVideoElement(), videoBuilder); return videoBuilder; } @Override public StylesBuilder style() { return stylesBuilder; } public DomElementBuilder trustedStart(String tagName) { /* * Validate the tag before trying to create the element, or the browser may * throw a JS error and prevent us from triggering an * IllegalArgumentException. */ assertValidTagName(tagName); start(Document.get().createElement(tagName), elementBuilder); return elementBuilder; } @Override protected void doCloseStartTagImpl() { // No-op. } @Override protected void doCloseStyleAttributeImpl() { // No-op. } @Override protected void doEndStartTagImpl() { popElement(); } @Override protected void doEndTagImpl(String tagName) { popElement(); } @Override protected Element doFinishImpl() { return rootElement; } @Override protected void doHtmlImpl(SafeHtml html) { getCurrentElement().setInnerHTML(html.asString()); } @Override protected void doOpenStyleImpl() { // No-op. } @Override protected void doTextImpl(String text) { getCurrentElement().setInnerText(text); } @Override protected void lockCurrentElement() { // Overridden for visibility. super.lockCurrentElement(); } /** * Assert that the builder is in a state where an attribute can be added. * * @return the element on which the attribute can be set * @throw {@link IllegalStateException} if the start tag is closed */ Element assertCanAddAttribute() { assertCanAddAttributeImpl(); return getCurrentElement(); } /** * Assert that the builder is in a state where a style property can be added. * * @return the {@link Style} on which the property can be set * @throw {@link IllegalStateException} if the style is not accessible */ Style assertCanAddStyleProperty() { assertCanAddStylePropertyImpl(); return getCurrentElement().getStyle(); } /** * Get the element current being built. */ Element getCurrentElement() { if (currentElement == null) { throw new IllegalStateException("There are no elements on the stack."); } return currentElement; } InputBuilder startTextInput() { return startInput(Document.get().createTextInputElement()); } /** * Pop to the previous element in the stack. */ private void popElement() { currentElement = getCurrentElement().getParentElement(); } /** * Start a child element. * * @param element the element to start * @param builder the builder used to builder the new element */ private void start(Element element, ElementBuilderBase<?> builder) { onStart(element.getTagName(), builder); // Set the root element. if (rootElement == null) { // This is the new root element. rootElement = element; } else { // Appending to the current element. getCurrentElement().appendChild(element); } // Add the element to the stack. currentElement = element; } /** * Start a button using the specified {@link ButtonElement}. */ private DomButtonBuilder startButton(ButtonElement button) { if (buttonBuilder == null) { buttonBuilder = new DomButtonBuilder(this); } start(button, buttonBuilder); return buttonBuilder; } /** * Start one of the many headers. */ private DomHeadingBuilder startHeading(int level) { if (headingBuilder == null) { headingBuilder = new DomHeadingBuilder(this); } start(Document.get().createHElement(level), headingBuilder); return headingBuilder; } /** * Start a quote or blockquote. */ private DomQuoteBuilder startQuote(QuoteElement quote) { if (quoteBuilder == null) { quoteBuilder = new DomQuoteBuilder(this); } start(quote, quoteBuilder); return quoteBuilder; } /** * Start a table col or colgroup. */ private DomTableColBuilder startTableCol(TableColElement element) { if (tableColBuilder == null) { tableColBuilder = new DomTableColBuilder(this); } start(element, tableColBuilder); return tableColBuilder; } /** * Start a table section using the specified {@link TableSectionElement}. */ private DomTableSectionBuilder startTableSection(TableSectionElement section) { if (tableSectionBuilder == null) { tableSectionBuilder = new DomTableSectionBuilder(this); } start(section, tableSectionBuilder); return tableSectionBuilder; } }