/** * Copyright 2009 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 org.waveprotocol.wave.client.editor.NodeEventHandlerImpl; import org.waveprotocol.wave.client.editor.content.ContentElement; import org.waveprotocol.wave.client.editor.content.ContentNode; import org.waveprotocol.wave.client.editor.content.ContentPoint; import org.waveprotocol.wave.client.editor.event.EditorEvent; import org.waveprotocol.wave.model.document.util.Point; /** * Default user event handler for paragraphs * * @author danilatos@google.com (Daniel Danilatos) */ public class ParagraphEventHandler extends NodeEventHandlerImpl { /** * Handles an enter from inside the paragraph, by splitting the * paragraph in two, the second with a <p> tag. * * {@inheritDoc} */ @Override public boolean handleEnter(ContentElement p, EditorEvent event) { maybeSplitForNewline(p, event.getCaret()); return true; } /** * @see #maybeSplitForNewline(ContentElement, Point) */ protected Point<ContentNode> maybeSplitForNewline(ContentElement p, ContentPoint splitAt) { return maybeSplitForNewline(p, splitAt.asPoint()); } /** * Helper method that does the work with mutable document * @param splitAt * @return the point where the split occurred */ protected Point<ContentNode> maybeSplitForNewline(ContentElement p, Point<ContentNode> splitAt) { throw new UnsupportedOperationException("No more paragraphs"); } /** * Determine whether a particular key/value attribute combination should be copied * to the newly created paragraph when a newline is triggered. * * @param key Key of the attribute * @param value Value for the attribute * @return Whether the attribute should be kept */ static boolean attributeKeptOnNewline(String key, String value) { // TODO(patcoleman): clean up to keep whitelisted combos in a set / map? // don't keep anything but bullet points if (Paragraph.SUBTYPE_ATTR.equals(key)) { if (Paragraph.LIST_TYPE.equals(value)) { return true; } return false; } return true; } /** * @return true if the two given nodes may join as paragraphs */ protected boolean canJoin(ContentNode first, ContentNode second) { return LineRendering.isLocalParagraph(first) && LineRendering.isLocalParagraph(second); } /** * Compute maximum join level of two adjacent elements by asking * the relevant ContentNode.canJoin questions * * @param left * @param right * @return maximum legal join level of first and second * */ private int maxJoinLevels(ContentNode left, ContentNode right) { int level = 0; while (left != null && right != null && canJoin(left, right)) { level++; right = left.getMutableDoc().getFirstChild(right); left = left.getMutableDoc().getLastChild(left); } return level; } static void indent(ContentElement p, int delta) { int indent = Math.max(0, Paragraph.getIndent(p) + delta); p.getMutableDoc().setElementAttribute(p, Paragraph.INDENT_ATTR, indent == 0 ? null : indent + ""); } /** * Joins this with previousSibling if appropriate after a backspace at beginning * * {@inheritDoc} */ @Override public boolean handleBackspaceAtBeginning(ContentElement p, EditorEvent event) { throw new UnsupportedOperationException("No more paragraphs"); } /** * Joins this with nextSibling if appropriate after a delete at end * * {@inheritDoc} */ @Override public boolean handleDeleteAtEnd(ContentElement p, EditorEvent event) { throw new UnsupportedOperationException("No more paragraphs"); } /** * @return Behaviour of this "paragraph" */ static ParagraphBehaviour getBehaviour(ContentElement p) { return ParagraphBehaviour.of(p.getAttribute(Paragraph.SUBTYPE_ATTR)); } }