/*
* DomUtilsStandardImpl.java
*
* Copyright (C) 2009-12 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/
package org.rstudio.core.client.dom.impl;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.dom.client.Text;
import org.rstudio.core.client.Rectangle;
import org.rstudio.core.client.dom.DomUtils;
import org.rstudio.core.client.dom.ElementEx;
import org.rstudio.core.client.dom.NativeWindow;
public class DomUtilsStandardImpl implements DomUtilsImpl
{
public void focus(Element element, boolean alwaysDriveSelection)
{
ElementEx el = (ElementEx)element ;
el.focus() ;
if (alwaysDriveSelection
|| (el.getContentEditable() &&
(el.getInnerText() == null || el.getInnerText() == "")))
{
Document doc = el.getOwnerDocument();
Range range = Range.create(doc) ;
range.selectNodeContents(el) ;
Selection sel = Selection.get(NativeWindow.get(doc)) ;
sel.setRange(range);
}
NativeWindow.get().focus();
}
public void collapseSelection(boolean toStart)
{
Selection sel = Selection.get() ;
if (sel == null || sel.getRangeCount() <= 0)
return ;
Range range = sel.getRangeAt(0) ;
range.collapse(toStart) ;
sel.removeAllRanges() ;
sel.addRange(range) ;
}
public boolean isSelectionCollapsed()
{
Selection sel = Selection.get() ;
return sel != null
&& sel.getRangeCount() == 1
&& sel.getRangeAt(0).isCollapsed() ;
}
public boolean isSelectionInElement(Element element)
{
Range rng = getSelectionRange(
NativeWindow.get(element.getOwnerDocument()), false) ;
if (rng == null)
return false ;
return DomUtils.contains(element, rng.getCommonAncestorContainer()) ;
}
public boolean selectionExists()
{
Selection sel = Selection.get() ;
if (sel == null || sel.getRangeCount() == 0)
return false ;
if (sel.getRangeCount() > 1)
return true ;
return !sel.getRangeAt(0).isCollapsed() ;
}
public Range getSelectionRange(NativeWindow window, boolean clone)
{
Selection sel = Selection.get(window) ;
if (sel.getRangeCount() != 1)
return null ;
Range result = sel.getRangeAt(0) ;
if (clone)
result = result.cloneRange() ;
return result ;
}
public Rectangle getCursorBounds(Document doc)
{
Selection sel = Selection.get(NativeWindow.get(doc));
Range selRng = sel.getRangeAt(0);
if (selRng == null)
return null;
sel.removeAllRanges();
SpanElement span = doc.createSpanElement() ;
Range rng = selRng.cloneRange();
rng.collapse(true);
rng.insertNode(span) ;
int x = span.getAbsoluteLeft() ;
int y = span.getAbsoluteTop() ;
int w = 0;
int h = span.getOffsetHeight() ;
Rectangle result = new Rectangle(x, y, w, h) ;
ElementEx parent = (ElementEx)span.getParentElement() ;
parent.removeChild(span) ;
parent.normalize() ;
sel.setRange(selRng);
return result;
}
public String replaceSelection(Document document, String text)
{
if (!isSelectionInElement(document.getBody()))
throw new IllegalStateException("Selection is not active");
Range rng = getSelectionRange(NativeWindow.get(document), true) ;
String orig = rng.toStringJs();
rng.deleteContents() ;
Text textNode = document.createTextNode(text) ;
rng.insertNode(textNode) ;
rng.selectNode(textNode);
Selection.get(NativeWindow.get(document)).setRange(rng);
return orig;
}
public String getSelectionText(Document document)
{
Range range = getSelectionRange(NativeWindow.get(document), false);
if (range == null || range.isCollapsed())
return null;
else
return range.toStringJs();
}
public int[] getSelectionOffsets(Element container)
{
Range rng = getSelectionRange(
NativeWindow.get(container.getOwnerDocument()),
false) ;
if (rng == null)
return null;
int start = NodeRelativePosition.toOffset(container,
new NodeRelativePosition(rng.getStartContainer(),
rng.getStartOffset())) ;
int end = NodeRelativePosition.toOffset(container,
new NodeRelativePosition(rng.getEndContainer(),
rng.getEndOffset())) ;
if (start >= 0 && end >= 0)
return new int[] {start, end};
else
return null ;
}
public void setSelectionOffsets(Element container, int start, int end)
{
NodeRelativePosition startp = NodeRelativePosition.toPosition(container, start);
NodeRelativePosition endp = NodeRelativePosition.toPosition(container, end);
Document doc = container.getOwnerDocument();
Range rng = Range.create(doc) ;
rng.setStart(startp.node, startp.offset) ;
rng.setEnd(endp.node, endp.offset) ;
Selection.get(NativeWindow.get(doc)).setRange(rng) ;
}
public boolean isSelectionAsynchronous()
{
return false;
}
@Override
public void selectElement(Element el)
{
Document doc = el.getOwnerDocument();
Range rng = Range.create(doc);
rng.selectNode(el);
Selection.get(NativeWindow.get(doc)).setRange(rng);
}
}