/** * 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.doodad.form.events; import org.waveprotocol.wave.client.editor.ElementHandlerRegistry; import org.waveprotocol.wave.client.editor.NodeEventHandlerImpl; import org.waveprotocol.wave.client.editor.NodeMutationHandlerImpl; import org.waveprotocol.wave.client.editor.content.ContentElement; import org.waveprotocol.wave.client.editor.content.ContentNode; import org.waveprotocol.wave.client.editor.content.NullRenderer; import org.waveprotocol.wave.client.editor.event.EditorEvent; import org.waveprotocol.wave.client.editor.util.EditorDocHelper; import org.waveprotocol.wave.model.document.util.Point; import org.waveprotocol.wave.model.document.util.XmlStringBuilder; /** Useful document elements for representing user events inside the document. */ public final class ContentEvents { private static final String TAGNAME = "events"; /** Register all behaviours for the events elements. */ public static void register(ElementHandlerRegistry handlerRegistry) { handlerRegistry.registerRenderer(TAGNAME, NullRenderer.INSTANCE); handlerRegistry.registerEventHandler(TAGNAME, ContentEventsNodeHandler.getInstance()); handlerRegistry.registerMutationHandler(TAGNAME, ContentEventsNodeMutationHandler.getInstance()); // Register all {@link Event} subclasses here Click.register(handlerRegistry); } /** * @return A content xml string containing an empty events list */ public static XmlStringBuilder constructXml() { return XmlStringBuilder.createEmpty().wrap(TAGNAME); } private ContentEvents() { } private static class ContentEventsNodeHandler extends NodeEventHandlerImpl { private static ContentEventsNodeHandler instance; /** */ public static ContentEventsNodeHandler getInstance() { if (instance == null) { instance = new ContentEventsNodeHandler(); } return instance; } /** * Records a click inside this events node if clicks are enabled */ @Override public boolean handleClick(ContentElement element, EditorEvent event) { if (isClickingEnabled(element)) { recordClick(element); return true; } else { // TODO(user): For now let an additional click clear all events clearEvents(element); return true; } } /** * Records a click event inside the events node */ private void recordClick(ContentElement element) { element.getMutableDoc().insertXml( Point.<ContentNode>end(element), Click.constructXml()); } /** * Clears all events */ private void clearEvents(ContentElement element) { element.getMutableDoc().emptyElement(element); } } /** * Returns true iff node is a ContentEvents element. * @param node */ public static boolean isContentEvents(ContentNode node) { return EditorDocHelper.isNamedElement(node, TAGNAME); } /** * @return true if events node will record another click; currently * true when no other click events are presents * * TODO(user): construct attributes for the <w:events> node that gives control * over which events are recorded, e.g., one per clicker vs. one overall, * only when editor is displaying and so on... */ public static boolean isClickingEnabled(ContentElement element) { for (ContentNode child = element.getFirstChild(); child != null; child = child.getNextSibling()) { if (Click.isClick(child)) { return false; } } return true; } private static class ContentEventsNodeMutationHandler extends NodeMutationHandlerImpl<ContentNode, ContentElement> { private static ContentEventsNodeMutationHandler instance; /** */ public static ContentEventsNodeMutationHandler getInstance() { if (instance == null) { instance = new ContentEventsNodeMutationHandler(); } return instance; } @Override public void onAddedToParent(ContentElement element, ContentElement oldParent) { onContentEventsChanged(element); super.onAddedToParent(element, oldParent); } @Override public void onDescendantsMutated(ContentElement element) { onContentEventsChanged(element); super.onDescendantsMutated(element); } /** * Notifies parent that this events node has changed, if parent implements */ private void onContentEventsChanged(ContentElement element) { ContentElement parent = element.getParentElement(); // TODO(user): Notify parent if parent cares. } } }