package org.swellrt.beta.client.js.editor.annotation; import org.swellrt.beta.client.js.editor.SEditorHelper; import org.waveprotocol.wave.client.doodad.annotation.GeneralAnnotationHandler; import org.waveprotocol.wave.client.editor.content.CMutableDocument; import org.waveprotocol.wave.client.editor.content.ContentElement; import org.waveprotocol.wave.client.editor.content.ContentNode; import org.waveprotocol.wave.client.editor.content.misc.AnnotationPaint; import org.waveprotocol.wave.client.editor.content.misc.CaretAnnotations; import org.waveprotocol.wave.client.editor.util.EditorAnnotationUtil; import org.waveprotocol.wave.model.document.MutableAnnotationSet; import org.waveprotocol.wave.model.document.indexed.LocationMapper; import org.waveprotocol.wave.model.document.util.Annotations; import org.waveprotocol.wave.model.document.util.Range; import org.waveprotocol.wave.model.util.CollectionUtils; import org.waveprotocol.wave.model.util.ReadableStringSet; import org.waveprotocol.wave.model.util.ReadableStringSet.Proc; import org.waveprotocol.wave.model.util.StringSet; import com.google.gwt.user.client.Event; /** * Convenience wrapper of (non-paragraph) annotations. * <p> * More info at {@link GeneralAnnotationHandler} and {@link AnnotationPaint} * * @author pablojan@gmail.com (Pablo Ojanguren) * */ public class TextAnnotation implements Annotation, Annotation.Listenable, AnnotationPaint.EventHandler, AnnotationPaint.MutationHandler { public static void clearRange(MutableAnnotationSet<String> doc, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, ReadableStringSet keys, int start, int end) { StringSet nonLocalKeys = CollectionUtils.newStringSet(); keys.each(new Proc(){ @Override public void apply(String key) { if (Annotations.isLocal(key)) localAnnotations.setAnnotation(start, end, key, null); else nonLocalKeys.add(key); } }); EditorAnnotationUtil.clearAnnotationsOverRange(doc, caret, nonLocalKeys, start, end); } private final String name; private AnnotationInstance.Handler handler; private final String contentNodeAttributeName; public TextAnnotation(String name) { super(); this.name = name; this.contentNodeAttributeName = AnnotationPaint.VALUE_ATTR_PREFIX + GeneralAnnotationHandler.getSafeKey(name); } public String getName() { return name; } @Override public void set(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range, String value) { if (Annotation.isLocal(name)) { localAnnotations.setAnnotation(range.getStart(), range.getEnd(), name, value); } else { EditorAnnotationUtil.setAnnotationOverRange(doc, caret, name, value, range.getStart(), range.getEnd()); } } @Override public void reset(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range) { if (Annotation.isLocal(name)) { localAnnotations.setAnnotation(range.getStart(), range.getEnd(), name, null); } else { EditorAnnotationUtil.clearAnnotationsOverRange(doc, caret, new String[]{ name }, range.getStart(), range.getEnd()); } } @Override public void update(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range, String value) { set(doc, mapper, localAnnotations, caret, range, value); } @Override public Range mutate(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range, String text, String value) { reset(doc, mapper, localAnnotations, caret, range); Range mutatedRange = SEditorHelper.replaceText(doc, range, text); set(doc, mapper, localAnnotations, caret, mutatedRange, value); return mutatedRange; } @Override public void setHandler(AnnotationInstance.Handler h) { this.handler = h; if (handler != null) { AnnotationPaint.registerEventHandler(name, this); AnnotationPaint.setMutationHandler(name, this); } else { // clear event handler? AnnotationPaint.clearMutationHandler(name); } } @Override public void onAdded(ContentElement node) { if (handler != null && !AnnotationRegistry.muteHandlers) { String value = node.getAttribute(this.contentNodeAttributeName); handler.exec(AnnotationInstance.EVENT_ADDED, AnnotationInstance.create(name, value, node), null); } } @Override public void onMutation(ContentElement node) { if (handler != null && !AnnotationRegistry.muteHandlers) { String value = node.getAttribute(this.contentNodeAttributeName); handler.exec(AnnotationInstance.EVENT_MUTATED, AnnotationInstance.create(name, value, node), null); } } @Override public void onRemoved(ContentElement node) { if (handler != null && !AnnotationRegistry.muteHandlers) { String value = node.getAttribute(this.contentNodeAttributeName); handler.exec(AnnotationInstance.EVENT_REMOVED, AnnotationInstance.create(name, value, node), null); } } @Override public void onEvent(ContentElement node, Event event) { if (handler != null && !AnnotationRegistry.muteHandlers) { String value = node.getAttribute(this.contentNodeAttributeName); handler.exec(AnnotationInstance.EVENT_MOUSE, AnnotationInstance.create(name, value, node), event); } } }