/** * Copyright 2010 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.wavepanel.view.dom; import com.google.common.base.Preconditions; import com.google.gwt.dom.client.Element; /** * DOM implementation of an anchor view. * */ public final class AnchorDomImpl implements DomView { private final Element self; private AnchorDomImpl(Element e) { this.self = e; } public static AnchorDomImpl of(Element e) { return new AnchorDomImpl(e); } @Override public Element getElement() { return self; } @Override public String getId() { return self.getId(); } public void setChild(Element e) { Preconditions.checkArgument(e != null); Preconditions.checkArgument(e.getParentElement() == null); Preconditions.checkState(self.getFirstChildElement() == null); self.appendChild(e); } public void removeChild(Element e) { Preconditions.checkArgument(e != null && e.getParentElement() == self); e.removeFromParent(); } public Element getChild() { // Do not cache this. return self.getFirstChildElement(); } // // Anchors are somewhat special, because if they are placed inline in editor // content then they can be removed from the DOM without their consent. Since // removing an anchor may require a consequent update to some state in the // containing view (e.g., the blip-meta's inline-locator list), a // post-detachment notification is too late to use the usual mechanism of // locating a view's containing view (DOM traversal). Therefore, when // attaching an anchor to a containing view, its DOM id is preserved, so that // after involuntary detachment, the appropriate notification can be sent to // the containing view without needing DOM traversal. // /** * Sets the DOM id of this anchor's containing view. This id is still * available, via {@link #getParentId()}, even after this anchor has been * detached from the DOM. * * @param id parent id, or {@code null} to clear * @throws IllegalArgumentException if the nullity of {@code id} and the * nullity of an existing parent id are equal. */ public void setParentId(String id) { // Only null -> non-null and non-null -> null transitions are permitted. // Other transitions are signs of bugs. if (self.hasAttribute("pid")) { Preconditions.checkArgument(id == null); self.removeAttribute("pid"); } else { Preconditions.checkArgument(id != null && !id.isEmpty()); self.setAttribute("pid", id); } } /** * @return the value previously recorded by {@link #setParentId(String)}, or * {@code null} if no value has been recorded. */ public String getParentId() { return self.hasAttribute("pid") ? self.getAttribute("pid") : null; } }