Text marked as deleted keeps the style properties of the source text.
diff --git a/src/org/waveprotocol/wave/client/editor/content/DiffHighlightingFilter.java b/src/org/waveprotocol/wave/client/editor/content/DiffHighlightingFilter.java
index 30b4af2..cbf4a2f 100644
--- a/src/org/waveprotocol/wave/client/editor/content/DiffHighlightingFilter.java
+++ b/src/org/waveprotocol/wave/client/editor/content/DiffHighlightingFilter.java
@@ -22,17 +22,21 @@
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Node;
+import com.google.gwt.dom.client.Style;
import org.waveprotocol.wave.client.common.util.DomHelper;
+import org.waveprotocol.wave.client.editor.content.misc.StyleAnnotationHandler;
import org.waveprotocol.wave.client.editor.content.paragraph.LineRendering;
import org.waveprotocol.wave.client.editor.impl.DiffManager;
import org.waveprotocol.wave.client.editor.impl.DiffManager.DiffType;
+
+import org.waveprotocol.wave.model.conversation.AnnotationConstants;
+import org.waveprotocol.wave.model.document.AnnotationInterval;
import org.waveprotocol.wave.model.document.MutableAnnotationSet;
import org.waveprotocol.wave.model.document.operation.AnnotationBoundaryMap;
import org.waveprotocol.wave.model.document.operation.Attributes;
import org.waveprotocol.wave.model.document.operation.AttributesUpdate;
import org.waveprotocol.wave.model.document.operation.DocOp;
-import org.waveprotocol.wave.model.document.operation.DocOpComponentType;
import org.waveprotocol.wave.model.document.operation.DocOpCursor;
import org.waveprotocol.wave.model.document.operation.ModifiableDocument;
import org.waveprotocol.wave.model.document.util.Annotations;
@@ -40,9 +44,13 @@
import org.waveprotocol.wave.model.util.CollectionUtils;
import org.waveprotocol.wave.model.util.IntMap;
import org.waveprotocol.wave.model.util.Preconditions;
-import org.waveprotocol.wave.model.util.ReadableIntMap.ProcV;
+import org.waveprotocol.wave.model.util.ReadableIntMap;
+import org.waveprotocol.wave.model.util.ReadableStringMap;
+import org.waveprotocol.wave.model.util.ReadableStringSet;
+import org.waveprotocol.wave.model.util.StringMap;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
/**
@@ -51,6 +59,7 @@
* Operations applied will be rendered as diffs.
*
* @author danilatos@google.com (Daniel Danilatos)
+ * @author dyukon@gmail.com (Denis Konovalchik)
*/
public class DiffHighlightingFilter implements ModifiableDocument {
@@ -151,7 +160,7 @@
final int size = inner.size();
- deleteInfos.each(new ProcV<Object>() {
+ deleteInfos.each(new ReadableIntMap.ProcV<Object>() {
public void apply(int location, Object _item) {
assert location <= size;
@@ -255,6 +264,7 @@
currentDeleteLocation = currentLocation;
}
+ @Override
public void deleteElementStart(String type, Attributes attrs) {
if (diffDepth == 0 && isOutsideInsertionAnnotation()) {
ContentElement currentElement = (ContentElement) inner.getCurrentNode();
@@ -314,18 +324,17 @@
}
}
+ @Override
public void deleteCharacters(String text) {
if (diffDepth == 0 && isOutsideInsertionAnnotation()) {
- int location = currentLocation;
- int endLocation = location + text.length();
+ int endLocation = currentLocation + text.length();
updateDeleteInfo();
- int scanLocation = location;
+ int scanLocation = currentLocation;
int nextScanLocation;
do {
-
DeleteInfo surroundedInfo = (DeleteInfo) inner.getAnnotation(scanLocation,
DIFF_DELETE_KEY);
nextScanLocation = inner.firstAnnotationChange(scanLocation, endLocation,
@@ -334,14 +343,8 @@
nextScanLocation = endLocation;
}
- int index = scanLocation - location;
- int nextIndex = nextScanLocation - location;
+ saveDeletedText(text, currentLocation, scanLocation, nextScanLocation);
- Element e = Document.get().createSpanElement();
- DiffManager.styleElement(e, DiffType.DELETE);
- e.setInnerText(text.substring(index, nextIndex));
-
- currentDeleteInfo.htmlElements.add(e);
if (surroundedInfo != null) {
currentDeleteInfo.htmlElements.addAll(surroundedInfo.htmlElements);
}
@@ -354,25 +357,89 @@
target.deleteCharacters(text);
}
+ @Override
public void annotationBoundary(AnnotationBoundaryMap map) {
target.annotationBoundary(map);
}
+ @Override
public void replaceAttributes(Attributes oldAttrs, Attributes newAttrs) {
currentLocation++;
target.replaceAttributes(oldAttrs, newAttrs);
}
+ @Override
public void retain(int itemCount) {
currentLocation += itemCount;
target.retain(itemCount);
}
+ @Override
public void updateAttributes(AttributesUpdate attrUpdate) {
currentLocation++;
target.updateAttributes(attrUpdate);
}
+ /**
+ * Creates text spans reflecting every combination of text formatting annotation values.
+ *
+ * @param text text to be saved
+ * @param textLocation location of the text beginning in the document
+ * @param startLocation start location of the deleted block
+ * @param finishLocation finish location of the deleted block
+ */
+ private void saveDeletedText(String text, int textLocation, int startLocation, int finishLocation) {
+ // TODO(dyukon): This solution supports only text styles (weight, decoration, font etc.)
+ // which can be applied to text SPANs.
+ // It's necessary to add support for paragraph styles (headers ordered/numbered lists,
+ // indents) which cannot be kept in text SPANs.
+ Iterator<AnnotationInterval<Object>> aiIterator = inner.annotationIntervals(
+ startLocation, finishLocation, AnnotationConstants.DELETED_STYLE_KEYS).iterator();
+ if (aiIterator.hasNext()) { // Some annotations are changed throughout deleted text
+ while (aiIterator.hasNext()) {
+ AnnotationInterval<Object> ai = aiIterator.next();
+ createDeleteElement(text.substring(ai.start() - textLocation, ai.end() - textLocation),
+ ai.annotations());
+ }
+ } else { // No annotations are changed throughout deleted text
+ createDeleteElement(text.substring(startLocation - textLocation, finishLocation - textLocation),
+ findDeletedStyleAnnotations(startLocation));
+ }
+ }
+
+ private ReadableStringMap<Object> findDeletedStyleAnnotations(final int location) {
+ final StringMap<Object> annotations = CollectionUtils.createStringMap();
+ AnnotationConstants.DELETED_STYLE_KEYS.each(new ReadableStringSet.Proc() {
+ @Override
+ public void apply(String key) {
+ annotations.put(key, inner.getAnnotation(location, key));
+ }
+ });
+ return annotations;
+ }
+
+ private void createDeleteElement(String innerText, ReadableStringMap<Object> annotations) {
+ Element element = Document.get().createSpanElement();
+ applyAnnotationsToElement(element, annotations);
+ DiffManager.styleElement(element, DiffType.DELETE);
+ element.setInnerText(innerText);
+ currentDeleteInfo.htmlElements.add(element);
+ }
+
+ private void applyAnnotationsToElement(Element element, ReadableStringMap<Object> annotations) {
+ final Style style = element.getStyle();
+ annotations.each(new ReadableStringMap.ProcV<Object>() {
+ @Override
+ public void apply(String key, Object value) {
+ if (value != null && value instanceof String) {
+ String styleValue = (String) value;
+ if (!styleValue.isEmpty()) {
+ style.setProperty(StyleAnnotationHandler.suffix(key), styleValue);
+ }
+ }
+ }
+ });
+ }
};
/**
diff --git a/src/org/waveprotocol/wave/client/editor/content/misc/StyleAnnotationHandler.java b/src/org/waveprotocol/wave/client/editor/content/misc/StyleAnnotationHandler.java
index f0a68f8..52bc016 100644
--- a/src/org/waveprotocol/wave/client/editor/content/misc/StyleAnnotationHandler.java
+++ b/src/org/waveprotocol/wave/client/editor/content/misc/StyleAnnotationHandler.java
@@ -29,8 +29,6 @@
import org.waveprotocol.wave.model.document.AnnotationBehaviour.DefaultAnnotationBehaviour;
import org.waveprotocol.wave.model.document.AnnotationMutationHandler;
import org.waveprotocol.wave.model.document.util.DocumentContext;
-import org.waveprotocol.wave.model.util.CollectionUtils;
-import org.waveprotocol.wave.model.util.ReadableStringSet;
import java.util.HashMap;
import java.util.Map;
@@ -49,7 +47,7 @@
* @param key
* @return style suffix
*/
- private static final String suffix(String key) {
+ public static final String suffix(String key) {
return key.substring(AnnotationConstants.STYLE_PREFIX.length() + 1);
}
@@ -74,12 +72,13 @@
registries.getAnnotationHandlerRegistry().registerHandler(AnnotationConstants.STYLE_PREFIX, handler);
registries.getAnnotationHandlerRegistry().registerBehaviour(AnnotationConstants.STYLE_PREFIX,
new DefaultAnnotationBehaviour(AnnotationFamily.CONTENT));
- painterRegistry.registerPaintFunction(KEYS, renderFunc);
+ painterRegistry.registerPaintFunction(AnnotationConstants.STYLE_KEYS, renderFunc);
}
private final AnnotationPainter painter;
private static final PaintFunction renderFunc = new PaintFunction() {
+ @Override
public Map<String, String> apply(Map<String, Object> from, boolean isEditing) {
Map<String, String> map = new HashMap<String, String>();
for (Map.Entry<String, Object> entry : from.entrySet()) {
@@ -91,17 +90,6 @@
}
};
- public static final ReadableStringSet KEYS = CollectionUtils.newStringSet(
- AnnotationConstants.STYLE_BG_COLOR,
- AnnotationConstants.STYLE_COLOR,
- AnnotationConstants.STYLE_FONT_FAMILY,
- AnnotationConstants.STYLE_FONT_SIZE,
- AnnotationConstants.STYLE_FONT_STYLE,
- AnnotationConstants.STYLE_FONT_WEIGHT,
- AnnotationConstants.STYLE_TEXT_DECORATION,
- AnnotationConstants.STYLE_VERTICAL_ALIGN
- );
-
/**
* @param painter painter to use for rendering
*/
diff --git a/src/org/waveprotocol/wave/model/conversation/AnnotationConstants.java b/src/org/waveprotocol/wave/model/conversation/AnnotationConstants.java
index 3fe9284..dbceaf5 100644
--- a/src/org/waveprotocol/wave/model/conversation/AnnotationConstants.java
+++ b/src/org/waveprotocol/wave/model/conversation/AnnotationConstants.java
@@ -19,6 +19,9 @@
package org.waveprotocol.wave.model.conversation;
+import org.waveprotocol.wave.model.util.CollectionUtils;
+import org.waveprotocol.wave.model.util.ReadableStringSet;
+
/**
* Constants useful for annotations
* Refer to the conversation specification for more detailed information.
@@ -45,6 +48,26 @@
public static final String STYLE_VERTICAL_ALIGN = STYLE_PREFIX + "/verticalAlign";
+ public static final ReadableStringSet STYLE_KEYS = CollectionUtils.newStringSet(
+ AnnotationConstants.STYLE_BG_COLOR,
+ AnnotationConstants.STYLE_COLOR,
+ AnnotationConstants.STYLE_FONT_FAMILY,
+ AnnotationConstants.STYLE_FONT_SIZE,
+ AnnotationConstants.STYLE_FONT_STYLE,
+ AnnotationConstants.STYLE_FONT_WEIGHT,
+ AnnotationConstants.STYLE_TEXT_DECORATION,
+ AnnotationConstants.STYLE_VERTICAL_ALIGN
+ );
+
+ public static final ReadableStringSet DELETED_STYLE_KEYS = CollectionUtils.newStringSet(
+ AnnotationConstants.STYLE_COLOR,
+ AnnotationConstants.STYLE_FONT_FAMILY,
+ AnnotationConstants.STYLE_FONT_SIZE,
+ AnnotationConstants.STYLE_FONT_STYLE,
+ AnnotationConstants.STYLE_FONT_WEIGHT,
+ AnnotationConstants.STYLE_VERTICAL_ALIGN
+ );
+
// User
/** Prefix for user annotations. */