/** * Copyright 2008 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 org.waveprotocol.wave.client.editor.content.paragraph; import com.google.gwt.dom.client.BRElement; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Node; import org.waveprotocol.wave.client.common.util.DomHelper; import org.waveprotocol.wave.client.editor.content.ContentElement; import org.waveprotocol.wave.client.editor.impl.NodeManager; import org.waveprotocol.wave.model.document.util.FilteredView.Skip; /** * Shared {@link ParagraphHelper} code for browsers using <br/> elements * as spacers. Note that the exact behaviour of the spacers once added * is determined by further deferred binding of this class for Safari vs. * Firefox. * */ public class ParagraphHelperBr extends ParagraphHelper { private static final String BR_REF = NodeManager.getNextMarkerName("br"); /** * @param n Node to test, or null * @return true if n is a spacer <br/>, WHETHER OR NOT we created it * or the browser's native editor created it */ protected boolean isSpacer(Node n) { if (n == null) { return false; } if (DomHelper.isTextNode(n)) { return false; } Element e = n.cast(); return e.getTagName().toLowerCase().equals("br") && !NodeManager.hasBackReference(e); } @Override public Node getEndingNodelet(Element paragraph) { Node maybeSpacer = paragraph.getLastChild(); return isSpacer(maybeSpacer) ? maybeSpacer : null; } /** * {@inheritDoc} */ @Override public void onEmpty(Element paragraph) { appendSpacer(paragraph); } /** * Appends a spacer <br sp='t'/> element to paragraph * Each paragraph owns a spacer which gets reused, so it * is safe to call this method multiple times. * * @param paragraph */ protected void appendSpacer(Element paragraph) { Element spacer = getSpacer(paragraph); paragraph.appendChild(spacer); } /** * Get the spacer for the given paragraph. * Lazily creates & registers one if not present. * If there's one that the browser created, registers it as our own. * If the browser put a different one in to the one that we were already * using, replace ours with the browser's. * @param paragraph * @return The spacer */ protected BRElement getSpacer(Element paragraph) { Node last = paragraph.getLastChild(); BRElement spacer = paragraph.getPropertyJSO(BR_REF).cast(); if (spacer == null) { // Register our spacer, using one the browser put in if present spacer = isSpacer(last) ? last.<BRElement>cast() : Document.get().createBRElement(); setupSpacer(paragraph, spacer); } else if (isSpacer(last) && last != spacer) { // The browser put a different one in by itself, so let's use that one if (spacer.hasParentElement()) { spacer.removeFromParent(); } spacer = last.<BRElement>cast(); setupSpacer(paragraph, spacer); } return spacer; } /** * Setup the given br element as the paragraph's spacer * @param paragraph * @param spacer */ private void setupSpacer(Element paragraph, BRElement spacer) { NodeManager.setTransparency(spacer, Skip.DEEP); paragraph.setPropertyJSO(BR_REF, spacer); } /** * {@inheritDoc} */ @Override public void assertHealthy(ContentElement paragraph) { //TODO(danilatos): Bring this check back. Something doesn't look right about it atm, //need to think about it. // if (paragraph.getImplNodelet().getChildCount() == 0) { // Element nodelet = paragraph.getImplNodelet(); // Assert.assertTrue( // "Empty Paragraph must have <br/> spacer", // isSpacer(nodelet.getFirstChild())); // Assert.assertTrue( // "Empty Paragraph must have only <br/> spacer", // nodelet.getChildCount() == 1); // } super.assertHealthy(paragraph); } }