001/* 002 * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Alexandre Russel 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.ecm.platform.annotations.gwt.client.view.annotater; 023 024import org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController; 025import org.nuxeo.ecm.platform.annotations.gwt.client.model.Annotation; 026import org.nuxeo.ecm.platform.annotations.gwt.client.model.Container; 027import org.nuxeo.ecm.platform.annotations.gwt.client.util.Range; 028import org.nuxeo.ecm.platform.annotations.gwt.client.util.Utils; 029import org.nuxeo.ecm.platform.annotations.gwt.client.util.XPathUtil; 030import org.nuxeo.ecm.platform.annotations.gwt.client.view.NewAnnotationPopup; 031 032import com.allen_sauer.gwt.log.client.Log; 033import com.google.gwt.dom.client.Document; 034import com.google.gwt.dom.client.Element; 035import com.google.gwt.dom.client.Node; 036import com.google.gwt.dom.client.Text; 037import com.google.gwt.user.client.Event; 038 039/** 040 * @author <a href="mailto:arussel@nuxeo.com">Alexandre Russel</a> 041 */ 042public class TextAnnotater extends AbstractAnnotater { 043 044 private final XPathUtil xpathUtil = new XPathUtil(); 045 046 public TextAnnotater(AnnotationController controller) { 047 super(controller, false); 048 } 049 050 @Override 051 public void onMouseUp(Event event) { 052 Log.debug("TextAnnotater#onMouseUp; eventId= " + event.getType() + "; source: " + event.getCurrentTarget()); 053 Range currentRange = Utils.getCurrentRange(Document.get()); 054 if (currentRange != null && currentRange.getSelectedText().length() != 0) { 055 Element startElement = Element.as(currentRange.getStartContainer()); 056 String pointer = xpathUtil.getSelectionXPointer(currentRange); 057 controller.createNewAnnotation(pointer); 058 059 Container startContainer = getStartContainer(currentRange); 060 Container endContainer = getEndContainer(currentRange); 061 062 Annotation annotation = controller.getNewAnnotation(); 063 annotation.setStartContainer(startContainer); 064 annotation.setEndContainer(endContainer); 065 066 NewAnnotationPopup popup = new NewAnnotationPopup(startElement, controller, false, "local"); 067 controller.setNewAnnotationPopup(popup); 068 addAnnotationPopup(); 069 } else { 070 controller.setNewAnnotationPopup(null); 071 } 072 073 super.onMouseUp(event); 074 } 075 076 private Container getStartContainer(Range range) { 077 Node startNode = range.getStartContainer(); 078 int startOffset = range.getStartOffset(); 079 // Window.alert("startOffset: " + startOffset); 080 startOffset = computeNewOffset(startNode, startOffset); 081 // Window.alert("startOffset after compute: " + startOffset); 082 083 if (startNode.getNodeType() == Node.TEXT_NODE) { 084 return getCustomContainer(startNode, startOffset); 085 } 086 return new Container(xpathUtil.getXPath(startNode), startOffset); 087 } 088 089 private Container getCustomContainer(Node node, int currentOffset) { 090 int offset = 0; 091 Node n = node.getPreviousSibling(); 092 while (n != null) { 093 if (n.getNodeType() == Node.TEXT_NODE) { 094 Text text = (Text) n; 095 offset += text.getLength(); 096 } else if (n.getNodeType() == Node.ELEMENT_NODE) { 097 Element ele = (Element) n; 098 offset += ele.getInnerText().length(); 099 } 100 n = n.getPreviousSibling(); 101 } 102 node = node.getParentNode(); 103 currentOffset += offset; 104 return new Container(xpathUtil.getXPath(node), currentOffset); 105 } 106 107 private static int computeNewOffset(Node node, int currentOffset) { 108 if (currentOffset <= 0) { 109 return currentOffset; 110 } 111 int difference = 0; 112 String text = node.getNodeValue(); 113 if (text != null) { 114 text = text.substring(0, currentOffset); 115 String processedText = Utils.removeWhitespaces(text, node, true); 116 difference = text.length() - processedText.length(); 117 } 118 return currentOffset - difference; 119 } 120 121 private Container getEndContainer(Range range) { 122 Node endNode = range.getEndContainer(); 123 int endOffset = range.getEndOffset(); 124 endOffset = computeNewOffset(endNode, endOffset); 125 126 if (endNode.getNodeType() == Node.TEXT_NODE) { 127 return getCustomContainer(endNode, endOffset); 128 } 129 130 return new Container(xpathUtil.getXPath(endNode), endOffset); 131 } 132 133}