/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.gwt.wysiwyg.client.plugin.link.exec;
import org.xwiki.gwt.dom.client.Range;
import org.xwiki.gwt.user.client.ui.rta.RichTextArea;
import org.xwiki.gwt.user.client.ui.rta.cmd.internal.AbstractInsertElementExecutable;
import org.xwiki.gwt.wysiwyg.client.plugin.link.LinkConfig;
import org.xwiki.gwt.wysiwyg.client.plugin.link.LinkConfigDOMReader;
import org.xwiki.gwt.wysiwyg.client.plugin.link.LinkConfigDOMWriter;
import org.xwiki.gwt.wysiwyg.client.plugin.link.LinkConfigJSONParser;
import org.xwiki.gwt.wysiwyg.client.plugin.link.LinkConfigJSONSerializer;
import com.google.gwt.dom.client.AnchorElement;
import com.google.gwt.dom.client.Node;
/**
* Creates a link by inserting the link XHTML.
*
* @version $Id: 87d7089d1eb3fb6eba464114928ca6291ae913b2 $
*/
public class CreateLinkExecutable extends AbstractInsertElementExecutable<LinkConfig, AnchorElement>
{
/**
* Creates a new executable that can be used to insert links in the specified rich text area.
*
* @param rta the execution target
*/
public CreateLinkExecutable(RichTextArea rta)
{
super(rta);
configDOMReader = new LinkConfigDOMReader();
configDOMWriter = new LinkConfigDOMWriter();
configJSONParser = new LinkConfigJSONParser();
configJSONSerializer = new LinkConfigJSONSerializer();
}
@Override
public boolean isEnabled()
{
if (!super.isEnabled()) {
return false;
}
// Create link executable is enabled either for creating a new link or for editing an existing link. Check if
// we're editing a link.
if (getSelectedElement() != null) {
return true;
}
// If no anchor on ancestor, test all the nodes touched by the selection to not contain an anchor.
Range range = rta.getDocument().getSelection().getRangeAt(0);
if (domUtils.getFirstDescendant(range.cloneContents(), LinkExecutableUtils.ANCHOR_TAG_NAME) != null) {
return false;
}
// Check if the selection does not contain any block elements.
Node commonAncestor = range.getCommonAncestorContainer();
if (!domUtils.isInline(commonAncestor)) {
// The selection may contain a block element, check if it actually does.
Node leaf = domUtils.getFirstLeaf(range);
Node lastLeaf = domUtils.getLastLeaf(range);
while (true) {
if (leaf != null) {
// Check if it has any non-in-line parents up to the commonAncestor.
Node parentNode = leaf;
while (parentNode != commonAncestor) {
if (!domUtils.isInline(parentNode)) {
// Found a non-in-line parent, return false.
return false;
}
parentNode = parentNode.getParentNode();
}
}
// Go to next leaf, if any are left.
if (leaf == lastLeaf) {
break;
} else {
leaf = domUtils.getNextLeaf(leaf);
}
}
}
return true;
}
@Override
protected String getCacheKeyPrefix()
{
return CreateLinkExecutable.class.getName();
}
@Override
protected AnchorElement getSelectedElement()
{
return LinkExecutableUtils.getSelectedAnchor(rta);
}
@Override
protected AnchorElement newElement()
{
AnchorElement anchor = rta.getDocument().createAnchorElement();
// Firefox 9 doesn't allow us to insert an empty anchor (no reference and no label) in an empty editable body
// element. The call emptyEditableBody.appendChild(emptyAnchor) is simply ignored. I know that, following the
// strict DTD, the body element can contain only block-level elements, but in this case inserting an empty image
// or a text node works fine. So Firefox 9 has something against inserting an empty anchor in an empty editable
// body. As a workaround we set the anchor reference and label to some default values. Note that these values
// will be overwritten later because the insert link wizard doesn't accept an empty reference or label.
anchor.setHref("http://www.xwiki.org");
anchor.setInnerText("XWiki");
return anchor;
}
}