/**
* 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.clipboard;
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.Text;
import org.waveprotocol.wave.client.common.util.DomHelper;
import org.waveprotocol.wave.client.editor.selection.html.NativeSelectionUtil;
import org.waveprotocol.wave.model.document.util.Point;
/**
* Safari implementation of the paste buffer. In Safari, we need to have the
* paste occur inside of a text node in order to consistently get the
* leading and trailing inline text. If that is not present, we sometimes
* cannot tell the difference between a new paragraph or inline text.
*
*/
class PasteBufferImplSafari extends PasteBufferImpl {
private boolean markersStripped = false;
private static final char MARKER_CHAR = '\u007F';
private static final String MARKER_NODE_STRING = String.valueOf(MARKER_CHAR) + MARKER_CHAR;
/**
* Use this to get the paste contents (from innerHTML). Note, this
* implementation will strip the extra markers injected for Safari.
*
* @return The pasted contents.
*/
@Override
public Element getPasteContainer() {
stripMarkers();
return element;
}
@Override
public void prepareForPaste() {
element.setInnerHTML("");
element.appendChild(Document.get().createTextNode(MARKER_NODE_STRING));
NativeSelectionUtil.setCaret(Point.inText(element.getFirstChild(), 1));
markersStripped = false;
}
private void stripMarkers() {
if (markersStripped) {
return;
}
// Remove the leading and trailing markers.
maybeStripMarker(element.getFirstChild(), element, true);
maybeStripMarker(element.getLastChild(), element, false);
markersStripped = true;
}
// TODO(user): Remove this when we can confirm this no longer happens.
private void logEndNotFound(String detail) {
Clipboard.LOG.error().log("end not found: " + detail);
}
private void maybeStripMarker(Node node, Element parent, boolean leading) {
if (node == null) {
logEndNotFound("node is null");
return;
}
if (DomHelper.isTextNode(node)) {
Text textNode = node.cast();
String text = textNode.getData();
if (!text.isEmpty()) {
if (leading) {
if (text.charAt(0) == MARKER_CHAR) {
textNode.setData(text.substring(1));
}
} else {
if (text.charAt(text.length() - 1) == MARKER_CHAR) {
textNode.setData(text.substring(0, text.length() - 1));
} else {
logEndNotFound("last character is not marker");
}
}
} else {
logEndNotFound("text node is empty");
}
if (textNode.getData().isEmpty()) {
parent.removeChild(textNode);
}
} else {
// In some cases, Safari will put the marker inside of a div, so this
// traverses down the left or right side of the tree to find it.
// For example: x<div><span>pasted</span>x</div>
maybeStripMarker(leading ? node.getFirstChild() : node.getLastChild(), node.<Element> cast(),
leading);
}
}
}