Re: [xwiki-devs] [xwiki-notifications] r14184 - in platform/web/trunk/wysiwyg/src/main: java/com/xpn/xwiki/wysiwyg/client/editor java/com/xpn/xwiki/wysiwyg/client/plugin/link java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui java/com/xpn/xwiki/wysiwyg/client/syntax/internal java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal resources/com/xpn/xwiki/wysiwyg/client/editor resources/com/xpn/xwiki/wysiwyg/public
This patch was partially provided by Marcela Mihai, I changed it where needed and completed it. Sorry I forgot to mention it in the svn comment, as appropriate. Happy coding, Anca Luca lucaa (SVN) wrote:
Author: lucaa Date: 2008-11-12 23:17:54 +0100 (Wed, 12 Nov 2008) New Revision: 14184
Added: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/LinkGenerator.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/AbstractHasLinkTab.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/EnterListener.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/HasLink.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkDialog.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkToEmailAddressTab.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkToWebPageTab.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/CreateLinkExecutable.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/UnlinkExecutable.java Modified: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/editor/Strings.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/editor/WysiwygEditorFactory.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/LinkPlugin.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/syntax/internal/DefaultSyntaxValidator.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/Command.java platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/DefaultCommandManager.java platform/web/trunk/wysiwyg/src/main/resources/com/xpn/xwiki/wysiwyg/client/editor/Strings.properties platform/web/trunk/wysiwyg/src/main/resources/com/xpn/xwiki/wysiwyg/public/Wysiwyg.css Log: XWIKI-2826: Create links to external addresses * Created the link plugin with link and unlink features. * Added command to create a wikilink and remove a wiklink from the wysiwyg html * Added the link plugin ui: dialogs to get links information from the user, just for external addresses ftm * Added a link generator class, to generate the wikilink html from the user data
Modified: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/editor/Strings.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/editor/Strings.java 2008-11-12 19:52:43 UTC (rev 14183) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/editor/Strings.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -82,8 +82,6 @@
String justifyRight();
- String link(); - String macro();
String normal(); @@ -114,5 +112,29 @@
String undo();
+ String link(); + String unlink(); + + String linkCreateLinkButon(); + + String linkEmailTab(); + + String linkWebPageTab(); + + String linkLabelLabel(); + + String linkWebPageLabel(); + + String linkEmailLabel(); + + String linkEmailAddressTextBox(); + + String linkWebPageTextBox(); + + String linkEmailAddressError(); + + String linkWebPageAddressError(); + + String linkNoLabelError(); }
Modified: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/editor/WysiwygEditorFactory.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/editor/WysiwygEditorFactory.java 2008-11-12 19:52:43 UTC (rev 14183) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/editor/WysiwygEditorFactory.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -27,6 +27,7 @@ import com.xpn.xwiki.wysiwyg.client.plugin.indent.IndentPluginFactory; import com.xpn.xwiki.wysiwyg.client.plugin.internal.DefaultPluginFactoryManager; import com.xpn.xwiki.wysiwyg.client.plugin.justify.JustifyPluginFactory; +import com.xpn.xwiki.wysiwyg.client.plugin.link.LinkPluginFactory; import com.xpn.xwiki.wysiwyg.client.plugin.list.ListPluginFactory; import com.xpn.xwiki.wysiwyg.client.plugin.separator.SeparatorPluginFactory; import com.xpn.xwiki.wysiwyg.client.plugin.symbol.SymbolPluginFactory; @@ -69,6 +70,7 @@ pfm.addPluginFactory(ColorPluginFactory.getInstance()); pfm.addPluginFactory(SyncPluginFactory.getInstance()); pfm.addPluginFactory(SymbolPluginFactory.getInstance()); + pfm.addPluginFactory(LinkPluginFactory.getInstance()); pfm.addPluginFactory(TablePluginFactory.getInstance()); // add additional PluginFactory for other plug-ins }
Added: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/LinkGenerator.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/LinkGenerator.java (rev 0) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/LinkGenerator.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -0,0 +1,74 @@ +/* + * 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 com.xpn.xwiki.wysiwyg.client.plugin.link; + +/** + * Generates html link blocks for all types of links. + * @version $Id$ + */ +public final class LinkGenerator +{ + /** + * The singleton instance of this class. + */ + private static LinkGenerator instance; + + /** + * Class constructor, private so that the class is a singleton. + */ + private LinkGenerator() + { + } + + /** + * @return the instance of this class. + */ + public static synchronized LinkGenerator getInstance() + { + if (instance == null) { + instance = new LinkGenerator(); + } + return instance; + } + + /** + * Generates link to an external url (web page or email address). + * + * @param label link label + * @param externalURL external url to link to + * @return the html link block. + */ + public String getExternalLink(String label, String externalURL) + { + // <!--startwikilink:http://xwiki.org--> + // <span class="wikiexternallink"> + // <a href="http://xwiki.org">label</a> + // </span> + // <!--stopwikilink--> + + // <!--startwikilink:mailto:[email protected]> + // <span class="wikiexternallink"> + // <a href="mailto:[email protected]">label</a> + // </span> + // <!--stopwikilink--> + return "<!--startwikilink:" + externalURL + "--><span class=\"wikiexternallink\"><a href=\"" + externalURL + + "\">" + label + "</a></span><!--stopwikilink-->"; + } +}
Modified: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/LinkPlugin.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/LinkPlugin.java 2008-11-12 19:52:43 UTC (rev 14183) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/LinkPlugin.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -27,15 +27,45 @@ import com.xpn.xwiki.wysiwyg.client.editor.Strings; import com.xpn.xwiki.wysiwyg.client.plugin.internal.AbstractPlugin; import com.xpn.xwiki.wysiwyg.client.plugin.internal.FocusWidgetUIExtension; +import com.xpn.xwiki.wysiwyg.client.plugin.link.ui.LinkDialog; import com.xpn.xwiki.wysiwyg.client.util.Config; +import com.xpn.xwiki.wysiwyg.client.widget.PopupListener; +import com.xpn.xwiki.wysiwyg.client.widget.SourcesPopupEvents; import com.xpn.xwiki.wysiwyg.client.widget.rta.RichTextArea; +import com.xpn.xwiki.wysiwyg.client.widget.rta.SelectionPreserver; +import com.xpn.xwiki.wysiwyg.client.widget.rta.cmd.Command;
-public class LinkPlugin extends AbstractPlugin implements ClickListener +/** + * Rich text editor plug-in for inserting links, using a dialog to get link settings from the user. It installs two + * buttons in the toolbar, for its two actions: link and unlink. + * + * @version $Id$ + */ +public class LinkPlugin extends AbstractPlugin implements ClickListener, PopupListener { + /** + * The button from the toolbar for create a link. + */ private PushButton link;
+ /** + * The button from the toolbar for destroy a link. + */ private PushButton unlink;
+ /** + * The dialog for create a link. + */ + private LinkDialog linkDialog; + + /** + * Selection preserver to store the selection before and after the dialog showing. + */ + private SelectionPreserver selectionPreserver; + + /** + * The toolbar extension used to add the link buttons to the toolbar. + */ private final FocusWidgetUIExtension toolBarExtension = new FocusWidgetUIExtension("toolbar");
/** @@ -47,15 +77,23 @@ { super.init(wysiwyg, textArea, config);
- link = new PushButton(Images.INSTANCE.link().createImage(), this); - link.setTitle(Strings.INSTANCE.link()); - toolBarExtension.addFeature("link", link); + if (getTextArea().getCommandManager().isSupported(Command.CREATE_LINK)) { + link = new PushButton(Images.INSTANCE.link().createImage(), this); + link.setTitle(Strings.INSTANCE.link()); + toolBarExtension.addFeature("link", link); + }
- unlink = new PushButton(Images.INSTANCE.unlink().createImage(), this); - unlink.setTitle(Strings.INSTANCE.unlink()); - toolBarExtension.addFeature("unlink", unlink); + if (getTextArea().getCommandManager().isSupported(Command.UNLINK)) { + unlink = new PushButton(Images.INSTANCE.unlink().createImage(), this); + unlink.setTitle(Strings.INSTANCE.unlink()); + toolBarExtension.addFeature("unlink", unlink); + }
- getUIExtensionList().add(toolBarExtension); + if (toolBarExtension.getFeatures().length > 0) { + getTextArea().addClickListener(this); + getUIExtensionList().add(toolBarExtension); + selectionPreserver = new SelectionPreserver(textArea); + } }
/** @@ -65,16 +103,29 @@ */ public void destroy() { - link.removeFromParent(); - link.removeClickListener(this); - link = null; + if (link != null) { + link.removeFromParent(); + link.removeClickListener(this); + link = null;
- unlink.removeFromParent(); - unlink.removeClickListener(this); - unlink = null; + if (linkDialog != null) { + linkDialog.hide(); + linkDialog.removeFromParent(); + linkDialog.removePopupListener(this); + linkDialog = null; + } + }
- toolBarExtension.clearFeatures(); + if (unlink != null) { + unlink.removeFromParent(); + unlink.removeClickListener(this); + unlink = null; + }
+ if (toolBarExtension.getFeatures().length > 0) { + getTextArea().removeClickListener(this); + toolBarExtension.clearFeatures(); + } super.destroy(); }
@@ -86,19 +137,76 @@ public void onClick(Widget sender) { if (sender == link) { - onLink(); + onLink(true); } else if (sender == unlink) { onUnlink(); } }
- public void onLink() + /** + * Depending on the passed parameter, the link dialog is displayed for the user to create a link or the created link + * is inserted in the document. + * + * @param show true if the link dialog must be shown, false otherwise + */ + public void onLink(boolean show) { - // TODO + if (show) { + // save the selection + selectionPreserver.saveSelection(); + // setup the dialog data + // use only the first range in the user selection + getLinkDialog().setLabel(getTextArea().getDocument().getSelection().getRangeAt(0).toHTML(), + getTextArea().getDocument().getSelection().getRangeAt(0).toString()); + // show the dialog + getLinkDialog().center(); + } else { + // restore selection, to be sure to execute the command on the right selection + selectionPreserver.restoreSelection(); + String url = getLinkDialog().getLink(); + if (url != null) { + getTextArea().getCommandManager().execute(Command.CREATE_LINK, url); + // restore the selection once again to select the inserted text + selectionPreserver.restoreSelection(); + } else { + // We get here if the link dialog has been closed by clicking the close button. + // In this case we return the focus to the text area. + getTextArea().setFocus(true); + } + } }
+ /** + * Executed when the unlink button is clicked. + */ public void onUnlink() { - // TODO + getTextArea().getCommandManager().execute(Command.UNLINK); } + + /** + * {@inheritDoc} + * + * @see PopupListener#onPopupClosed(PopupPanel, boolean) + */ + public void onPopupClosed(SourcesPopupEvents sender, boolean autoHide) + { + if (sender == getLinkDialog() && !autoHide) { + onLink(false); + } + } + + /** + * Lazy creation of the link dialog, to optimize editor loading time. + * + * @return the link dialog to be used for inserting the link. + */ + private LinkDialog getLinkDialog() + { + if (linkDialog == null) { + linkDialog = new LinkDialog(); + linkDialog.addPopupListener(this); + } + return linkDialog; + } }
Added: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/AbstractHasLinkTab.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/AbstractHasLinkTab.java (rev 0) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/AbstractHasLinkTab.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -0,0 +1,200 @@ +/* + * 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 com.xpn.xwiki.wysiwyg.client.plugin.link.ui; + +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.ClickListener; +import com.google.gwt.user.client.ui.ClickListenerCollection; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.TextBox; +import com.xpn.xwiki.wysiwyg.client.editor.Strings; + +/** + * Abstract class to use as the superclass for the link generating tabs. Implements basic functionality for the link + * tabs and stores basic data. + * + * @version $Id$ + */ +public abstract class AbstractHasLinkTab extends Composite implements HasLink +{ + /** + * Click listeners for this click events source. + */ + private final ClickListenerCollection clickListeners = new ClickListenerCollection(); + + /** + * The result link string. + */ + private String link; + + /** + * The HTML string for the label of the link to be created. + */ + private String labelHTML; + + /** + * The text for the label of the link to be created (stripped of potential HTML tags). + */ + private String labelText; + + /** + * The text box where the user will insert the text of the link to create (if any). + */ + private TextBox labelTextBox = new TextBox(); + + /** + * @return the labelTextBox + */ + protected TextBox getLabelTextBox() + { + return labelTextBox; + } + + /** + * @param labelTextBox the labelTextBox to set + */ + protected void setLabelTextBox(TextBox labelTextBox) + { + this.labelTextBox = labelTextBox; + } + + /** + * Setter for the HTML link string generated by this widget. + * + * @param link the link to set to this widget. + */ + protected void setLink(String link) + { + this.link = link; + } + + /** + * @return the click listener collection of this click events source. + */ + protected ClickListenerCollection getClickListeners() + { + return clickListeners; + } + + /** + * Setter for value of field <i>labelHTML</i>. + * + * @param label the new value for <i>labelHTML</i> + */ + protected void setLabelHTML(String label) + { + this.labelHTML = label; + } + + /** + * @return the HTML of the label of the link to be generated by this widget. + */ + protected String getLabelHTML() + { + return labelHTML; + } + + /** + * @return the labelText + */ + protected String getLabelText() + { + return labelText; + } + + /** + * @param labelText the labelText to set + */ + protected void setLabelText(String labelText) + { + this.labelText = labelText; + if (labelTextBox != null) { + labelTextBox.setText(labelText); + } + } + + /** + * Sets the label for which this {@link HasLink} will generate the link HTML. + * + * @param labelHTML the label's HTML value + * @param labelText the label's text value + */ + public void setLabel(String labelHTML, String labelText) { + setLabelHTML(labelHTML); + setLabelText(labelText); + } + + /** + * {@inheritDoc} + * + * @see SourcesClickEvents#addClickListener(ClickListener) + */ + public void addClickListener(ClickListener listener) + { + clickListeners.add(listener); + } + + /** + * {@inheritDoc} + * + * @see SourcesClickEvents#removeClickListener(ClickListener) + */ + public void removeClickListener(ClickListener listener) + { + clickListeners.remove(listener); + } + + /** + * @return the url give by user. + */ + public String getLink() + { + return link; + } + + /** + * Get the label for the link to generate. If the label text was modified, use that one, otherwise use the HTML + * label. + * + * @return the label for the link to generate. + */ + protected String getLinkLabel() + { + if (this.labelTextBox.getText().trim().equals(this.getLabelText())) { + return getLabelHTML(); + } else { + return this.labelTextBox.getText().trim(); + } + } + + /** + * {@inheritDoc} + */ + public boolean validateUserInput() + { + // the label cannot be void, for the moment + // TODO: find a way to allow void labels to be set and get the automatically generated labels. + if (this.labelTextBox.getText().trim().length() == 0) { + Window.alert(Strings.INSTANCE.linkNoLabelError()); + return false; + } + return true; + } +}
Added: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/EnterListener.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/EnterListener.java (rev 0) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/EnterListener.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -0,0 +1,62 @@ +/* + * 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 com.xpn.xwiki.wysiwyg.client.plugin.link.ui; + +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.KeyboardListenerAdapter; +import com.google.gwt.user.client.ui.Widget; + +/** + * Keyboard listener adapter to be able to automatically click a button when the enter key is pressed inside a + * {@link SourcesKeyboardEvents}. + * + * @version $Id$ + */ +public class EnterListener extends KeyboardListenerAdapter +{ + /** + * The button which will be click when enter key will be press. + */ + private Button button; + + /** + * Class constructor. + * + * @param button which will be click when enter key will be press. + */ + public EnterListener(Button button) + { + this.button = button; + } + + /** + * {@inheritDoc} + * + * @see KeyboardListenerAdapter#onKeyPress(Widget, char, int) + */ + public void onKeyPress(Widget sender, char c, int i) + { + super.onKeyPress(sender, c, i); + // Check if it's the enter key that has been pressed + if (c == 13) { + button.click(); + } + } +}
Added: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/HasLink.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/HasLink.java (rev 0) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/HasLink.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -0,0 +1,49 @@ +/* + * 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 com.xpn.xwiki.wysiwyg.client.plugin.link.ui; + +import com.google.gwt.user.client.ui.SourcesClickEvents; + +/** + * Interface for widgets that return a link html block from user input and are clickable. + * + * @version $Id$ + */ +public interface HasLink extends SourcesClickEvents +{ + /** + * Returns the link html block to use with the <i>create_link</i> command. + * + * @return the link html block + */ + String getLink(); + + /** + * Some setup need for the moment when the widget will be display. + */ + void initialize(); + + /** + * Validates the user input for this widget, to be used for validation before the link is created / returned. + * + * @return true if the user input for this widget is valid, false otherwise. + */ + boolean validateUserInput(); +}
Added: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkDialog.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkDialog.java (rev 0) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkDialog.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -0,0 +1,205 @@ +/* + * 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 com.xpn.xwiki.wysiwyg.client.plugin.link.ui; + +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.DeferredCommand; +import com.google.gwt.user.client.ui.ClickListener; +import com.google.gwt.user.client.ui.SourcesTabEvents; +import com.google.gwt.user.client.ui.TabListener; +import com.google.gwt.user.client.ui.TabPanel; +import com.google.gwt.user.client.ui.Widget; +import com.xpn.xwiki.wysiwyg.client.editor.Strings; +import com.xpn.xwiki.wysiwyg.client.widget.CompositeDialogBox; + +/** + * Extends {@link com.xpn.xwiki.wysiwyg.client.widget.CompositeDialogBox}. + * + * @version $Id$ + */ +public class LinkDialog extends CompositeDialogBox implements ClickListener, TabListener +{ + /** + * Helper command to set the selection in this dialog to the stored selected. + */ + private class SelectCommand implements Command + { + /** + * {@inheritDoc} + */ + public void execute() + { + tabs.selectTab(selectedTabIndex); + } + } + + /** + * Tabs to add to this dialog. + */ + private final TabPanel tabs; + + /** + * The tab to get the link to a web page. + */ + private final LinkToWebPageTab linkToWebPageTab; + + /** + * The tab to get the link to an email address. + */ + private final LinkToEmailAddressTab linkToEmailAddressTab; + + /** + * This variable contains the index of the selected tab. + */ + private int selectedTabIndex; + + /** + * True if the dialog is close by the close button, and false if the dialog is close by <i>Create link</i> button. + */ + private boolean closeByCreateLink; + + /** + * Default constructor. + */ + public LinkDialog() + { + super(false, true); + linkToWebPageTab = new LinkToWebPageTab(); + linkToEmailAddressTab = new LinkToEmailAddressTab(); + + tabs = new TabPanel(); + tabs.addTabListener(this); + + addTab(linkToWebPageTab, Strings.INSTANCE.linkWebPageTab()); + addTab(linkToEmailAddressTab, Strings.INSTANCE.linkEmailTab()); + tabs.selectTab(0); + selectedTabIndex = 0; + + getDialog().setText(Strings.INSTANCE.link()); + getDialog().setAnimationEnabled(false); + getDialog().addStyleName("linkDialog"); + + initWidget(tabs); + + // set the initial label HTML to void string, as if no selection was made. + setLabel("", ""); + } + + /** + * Sets the label for the link created by this dialog. This label has an HTML form and a text form, the stripped + * version of the HTML version. If the text form is edited by the user, that label will be used, otherwise the HTML + * version, with formatting. + * + * @param labelHTML the HTML of the label for the created link. + * @param labelText the text of the label for the created link (stripped of HTML tags) + */ + public void setLabel(String labelHTML, String labelText) + { + if (linkToWebPageTab != null) { + linkToWebPageTab.setLabel(labelHTML, labelText); + } + if (linkToEmailAddressTab != null) { + linkToEmailAddressTab.setLabel(labelHTML, labelText); + } + } + + /** + * @param content Widget that would be add in tab. + * @param tabName The name of the tab. + */ + private void addTab(Widget content, String tabName) + { + if (content instanceof HasLink) { + tabs.add(content, tabName); + ((HasLink) content).addClickListener(this); + } + } + + /** + * {@inheritDoc} + * + * @see ClickListener#onClick(Widget) + */ + public void onClick(Widget sender) + { + if (sender instanceof HasLink) { + closeByCreateLink = true; + hide(); + } + } + + /** + * @return the url from the selected tab. + */ + public String getLink() + { + if (closeByCreateLink) { + closeByCreateLink = false; + return getSelectedTab().getLink(); + } else { + return null; + } + } + + /** + * {@inheritDoc} + * + * @see TabListener#onBeforeTabSelected(SourcesTabEvents, int) + */ + public boolean onBeforeTabSelected(SourcesTabEvents sender, int tabIndex) + { + return true; + } + + /** + * {@inheritDoc} + * + * @see TabListener#onTabSelected(SourcesTabEvents, int) + */ + public void onTabSelected(SourcesTabEvents sender, int tabIndex) + { + if (sender == tabs) { + selectedTabIndex = tabIndex; + getSelectedTab().initialize(); + } + } + + /** + * Gets the widget from the tab corresponding with the selected index. + * + * @return the widget from the current tab. + */ + private HasLink getSelectedTab() + { + return (HasLink) tabs.getWidget(selectedTabIndex); + } + + /** + * {@inheritDoc} + * + * @see CompositeDialog#center() + */ + public void center() + { + super.center(); + DeferredCommand.addCommand(new SelectCommand()); + } +}
Added: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkToEmailAddressTab.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkToEmailAddressTab.java (rev 0) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkToEmailAddressTab.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -0,0 +1,154 @@ +/* + * 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 com.xpn.xwiki.wysiwyg.client.plugin.link.ui; + +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.ClickListener; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; +import com.xpn.xwiki.wysiwyg.client.editor.Strings; +import com.xpn.xwiki.wysiwyg.client.plugin.link.LinkGenerator; + +/** + * Tab to add to the link dialog to get user data and produce an URL to an email address. + * + * @version $Id$ + */ +public class LinkToEmailAddressTab extends AbstractHasLinkTab implements ClickListener +{ + /** + * URL protocol constant. + */ + private static final String MAILTO = "mailto:"; + + /** + * The text box where the user will insert the address of the web page. + */ + private final TextBox emailTextBox; + + /** + * The link creation button. + */ + private final Button createLinkButton; + + /** + * Default constructor. + */ + public LinkToEmailAddressTab() + { + Label emailLabel = new Label(Strings.INSTANCE.linkEmailLabel()); + Label labelLabel = new Label(Strings.INSTANCE.linkLabelLabel()); + createLinkButton = new Button(Strings.INSTANCE.linkCreateLinkButon()); + createLinkButton.addClickListener(this); + + EnterListener enterListener = new EnterListener(createLinkButton); + emailTextBox = new TextBox(); + emailTextBox.setText(Strings.INSTANCE.linkEmailAddressTextBox()); + emailTextBox.addClickListener(this); + emailTextBox.addKeyboardListener(enterListener); + + getLabelTextBox().addKeyboardListener(enterListener); + + FlowPanel mainPanel = new FlowPanel(); + mainPanel.addStyleName("xLinkToUrl"); + FlowPanel labelPanel = new FlowPanel(); + labelPanel.addStyleName("label"); + labelPanel.add(labelLabel); + labelPanel.add(getLabelTextBox()); + FlowPanel emailPanel = new FlowPanel(); + emailPanel.addStyleName("url"); + emailPanel.add(emailLabel); + emailPanel.add(emailTextBox); + + mainPanel.add(labelPanel); + mainPanel.add(emailPanel); + mainPanel.add(createLinkButton); + + initWidget(mainPanel); + } + + /** + * {@inheritDoc} + * + * @see ClickListener#onClick(Widget) + */ + public void onClick(Widget sender) + { + if (sender == createLinkButton) { + // try to create the link and close the dialog. Fail if the input does not validate + String url; + String emailAddress = emailTextBox.getText(); + if (!validateUserInput()) { + url = null; + } else { + if (emailAddress.startsWith(MAILTO)) { + url = emailAddress; + } else { + url = MAILTO + emailAddress; + } + setLink(LinkGenerator.getInstance().getExternalLink(getLinkLabel(), url)); + getClickListeners().fireClick(this); + } + } + if (sender == emailTextBox) { + emailTextBox.selectAll(); + } + } + + /** + * {@inheritDoc} + * + * @see HasLink#initialize() + */ + public void initialize() + { + emailTextBox.setText(Strings.INSTANCE.linkEmailAddressTextBox()); + // If there is label to set, set focus in the label field + if (getLabelTextBox().getText().trim().length() == 0) { + getLabelTextBox().setFocus(true); + } else { + emailTextBox.setFocus(true); + } + emailTextBox.selectAll(); + } + + /** + * {@inheritDoc} + * + * @see HasLink#validateUserInput() + */ + public boolean validateUserInput() + { + // Check the super class validation result + if (!super.validateUserInput()) { + return false; + } + // the email address must not be void. Check if this happens + if (this.emailTextBox.getText().trim().length() == 0 + || this.emailTextBox.getText().equals(Strings.INSTANCE.linkEmailAddressTextBox())) { + Window.alert(Strings.INSTANCE.linkEmailAddressError()); + return false; + } + return true; + } +}
Added: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkToWebPageTab.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkToWebPageTab.java (rev 0) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/plugin/link/ui/LinkToWebPageTab.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -0,0 +1,149 @@ +/* + * 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 com.xpn.xwiki.wysiwyg.client.plugin.link.ui; + +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.ClickListener; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; +import com.xpn.xwiki.wysiwyg.client.editor.Strings; +import com.xpn.xwiki.wysiwyg.client.plugin.link.LinkGenerator; + +/** + * Tab to add to the link dialog to get user data and produce a link to an external web page. + * + * @version $Id$ + */ +public class LinkToWebPageTab extends AbstractHasLinkTab implements ClickListener +{ + /** + * The text box where the user will insert the address of the web page. + */ + private final TextBox urlTextBox; + + /** + * The link creation button. + */ + private final Button createLinkButton; + + /** + * Class constructor. + */ + public LinkToWebPageTab() + { + Label urlLabel = new Label(Strings.INSTANCE.linkWebPageLabel()); + Label labelLabel = new Label(Strings.INSTANCE.linkLabelLabel()); + createLinkButton = new Button(Strings.INSTANCE.linkCreateLinkButon()); + createLinkButton.addClickListener(this); + + EnterListener enterListener = new EnterListener(createLinkButton); + urlTextBox = new TextBox(); + urlTextBox.setText(Strings.INSTANCE.linkWebPageTextBox()); + urlTextBox.addClickListener(this); + urlTextBox.addKeyboardListener(enterListener); + + getLabelTextBox().addKeyboardListener(enterListener); + + FlowPanel mainPanel = new FlowPanel(); + mainPanel.addStyleName("xLinkToUrl"); + FlowPanel labelPanel = new FlowPanel(); + labelPanel.addStyleName("label"); + labelPanel.add(labelLabel); + labelPanel.add(getLabelTextBox()); + FlowPanel urlPanel = new FlowPanel(); + urlPanel.addStyleName("url"); + urlPanel.add(urlLabel); + urlPanel.add(urlTextBox); + + mainPanel.add(labelPanel); + mainPanel.add(urlPanel); + mainPanel.add(createLinkButton); + + initWidget(mainPanel); + } + + /** + * {@inheritDoc} + * + * @see ClickListener#onClick(Widget) + */ + public void onClick(Widget sender) + { + if (sender == createLinkButton) { + String url; + String webPageAddress = urlTextBox.getText(); + if (!validateUserInput()) { + url = null; + } else { + // check if any protocol is use + if (webPageAddress.contains("://")) { + url = webPageAddress; + } else { + url = "http://" + webPageAddress; + } + setLink(LinkGenerator.getInstance().getExternalLink(getLinkLabel(), url)); + getClickListeners().fireClick(this); + } + } + if (sender == urlTextBox) { + urlTextBox.selectAll(); + } + } + + /** + * {@inheritDoc} + * + * @see HasLink#initialize() + */ + public void initialize() + { + urlTextBox.setText(Strings.INSTANCE.linkWebPageTextBox()); + if (getLabelTextBox().getText().trim().length() == 0) { + getLabelTextBox().setFocus(true); + } else { + urlTextBox.setFocus(true); + } + urlTextBox.selectAll(); + } + + /** + * {@inheritDoc} + * + * @see HasLink#validateUserInput() + */ + public boolean validateUserInput() + { + // Check the super class validation result + if (!super.validateUserInput()) { + return false; + } + // The url inserted by the user must not be void. Check that + if (this.urlTextBox.getText().trim().length() == 0 + || this.urlTextBox.getText().equals(Strings.INSTANCE.linkWebPageTextBox())) { + Window.alert(Strings.INSTANCE.linkWebPageAddressError()); + return false; + } + return true; + } +}
Modified: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/syntax/internal/DefaultSyntaxValidator.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/syntax/internal/DefaultSyntaxValidator.java 2008-11-12 19:52:43 UTC (rev 14183) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/syntax/internal/DefaultSyntaxValidator.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -64,7 +64,8 @@ addValidationRule(new DefaultValidationRule("fontsize", Command.FONT_SIZE)); addValidationRule(new DefaultValidationRule("forecolor", Command.FORE_COLOR)); addValidationRule(new DefaultValidationRule("backcolor", Command.BACK_COLOR)); - + addValidationRule(new DefaultValidationRule("link", Command.CREATE_LINK)); + addValidationRule(new DefaultValidationRule("unlink", Command.UNLINK)); // FIXME : implement this in the table plugin when possible addValidationRule(new DefaultValidationRule("deletecol", new Command("deletecol"))); addValidationRule(new DefaultValidationRule("deleterow", new Command("deleterow")));
Modified: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/Command.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/Command.java 2008-11-12 19:52:43 UTC (rev 14183) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/Command.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -41,6 +41,12 @@ public static final Command BOLD = new Command("bold");
/** + * This command will insert a link in place of the current selection, either if it is a collapsed selection or an + * expanded one. It is based on the insert HTML command, and it will insert the link HTML received as a parameter. + */ + public static final Command CREATE_LINK = new Command("createlink"); + + /** * This command will set the font face for a selection or at the insertion point if there is no selection.<br/> * The given string is such as would be used in the "name" attribute of the font tag. */ @@ -205,6 +211,12 @@ public static final Command UNDO = new Command("undo");
/** + * If the insertion point is within a link or if the current selection contains a link, the link will be removed and + * the text will remain. + */ + public static final Command UNLINK = new Command("unlink"); + + /** * The name of the command. For predefined commands (supported by the built-in rich text editor, the one offered by * the browser) this is the name of the command execute with the native API. For the rest (custom commands) this is * just a string identifier.
Added: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/CreateLinkExecutable.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/CreateLinkExecutable.java (rev 0) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/CreateLinkExecutable.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -0,0 +1,103 @@ +/* + * 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 com.xpn.xwiki.wysiwyg.client.widget.rta.cmd.internal; + +import com.google.gwt.core.client.GWT; +import com.xpn.xwiki.wysiwyg.client.dom.DOMUtils; +import com.xpn.xwiki.wysiwyg.client.dom.Range; +import com.xpn.xwiki.wysiwyg.client.widget.rta.RichTextArea; +import com.xpn.xwiki.wysiwyg.client.widget.rta.cmd.Executable; + +/** + * Creates a link by inserting the link xhtml. + * + * @version $Id$ + */ +public class CreateLinkExecutable implements Executable +{ + /** + * Insert HTML executable to use for the insertion of the links. Cannot extend it because we need to get it in a + * cross browser manner. + */ + private Executable insertHTMLExecutable; + + /** + * Default constructor, creating a {@link DefaultExecutable} for the <code>inserthtml</code> command. + */ + public CreateLinkExecutable() + { + // Create the InsertHTML cross-browser executable + insertHTMLExecutable = GWT.create(InsertHTMLExecutable.class); + } + + /** + * {@inheritDoc} + */ + public boolean execute(RichTextArea rta, String parameter) + { + return insertHTMLExecutable.execute(rta, parameter); + } + + /** + * {@inheritDoc} + * + * @see DefaultExecutable#isEnabled(RichTextArea) + */ + public boolean isEnabled(RichTextArea rta) + { + String anchorTagName = "a"; + // This option is enabled only if we're not in another or the selection does not touch an anchor + Range range = DOMUtils.getInstance().getTextRange(rta.getDocument().getSelection().getRangeAt(0)); + //Check the parent first, for it's shorter + if (DOMUtils.getInstance().getFirstAncestor(range.getCommonAncestorContainer(), anchorTagName) != null) { + return false; + } + // if no anchor on ancestor, test all the nodes touched by the selection to not contain an anchor + return DOMUtils.getInstance().getFirstDescendant(range.cloneContents(), anchorTagName) == null; + } + + /** + * {@inheritDoc} + * + * @see DefaultExecutable#isExecuted(RichTextArea) + */ + public boolean isExecuted(RichTextArea rta) + { + // Although we should also check the parents of the anchor we are in + return !isEnabled(rta); + } + + /** + * {@inheritDoc} + */ + public boolean isSupported(RichTextArea rta) + { + return insertHTMLExecutable.isSupported(rta); + } + + /** + * {@inheritDoc} + */ + public String getParameter(RichTextArea rta) + { + // TODO Auto-generated method stub + return null; + } +}
Modified: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/DefaultCommandManager.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/DefaultCommandManager.java 2008-11-12 19:52:43 UTC (rev 14183) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/DefaultCommandManager.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -57,6 +57,7 @@ EXECUTABLES = new HashMap<Command, Executable>(); EXECUTABLES.put(Command.BACK_COLOR, (Executable) GWT.create(BackColorExecutable.class)); EXECUTABLES.put(Command.BOLD, new BoldExecutable()); + EXECUTABLES.put(Command.CREATE_LINK, new CreateLinkExecutable()); EXECUTABLES.put(Command.FONT_NAME, new DefaultExecutable(Command.FONT_NAME.toString())); EXECUTABLES.put(Command.FONT_SIZE, new DefaultExecutable(Command.FONT_SIZE.toString())); EXECUTABLES.put(Command.FORE_COLOR, new DefaultExecutable(Command.FORE_COLOR.toString())); @@ -87,6 +88,7 @@ EXECUTABLES.put(Command.TELETYPE, new StyleExecutable("tt", null, Style.FONT_FAMILY, "monospace", true, true)); EXECUTABLES.put(Command.UNDERLINE, new StyleExecutable("ins", null, Style.TEXT_DECORATION, Style.TextDecoration.UNDERLINE, false, true)); + EXECUTABLES.put(Command.UNLINK, new UnlinkExecutable()); EXECUTABLES.put(Command.UNDO, new UndoExecutable()); }
Added: platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/UnlinkExecutable.java =================================================================== --- platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/UnlinkExecutable.java (rev 0) +++ platform/web/trunk/wysiwyg/src/main/java/com/xpn/xwiki/wysiwyg/client/widget/rta/cmd/internal/UnlinkExecutable.java 2008-11-12 22:17:54 UTC (rev 14184) @@ -0,0 +1,222 @@ +/* + * 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 com.xpn.xwiki.wysiwyg.client.widget.rta.cmd.internal; + +import com.google.gwt.dom.client.Node; +import com.xpn.xwiki.wysiwyg.client.dom.DOMUtils; +import com.xpn.xwiki.wysiwyg.client.dom.Document; +import com.xpn.xwiki.wysiwyg.client.dom.Element; +import com.xpn.xwiki.wysiwyg.client.dom.Range; +import com.xpn.xwiki.wysiwyg.client.dom.Selection; +import com.xpn.xwiki.wysiwyg.client.widget.rta.RichTextArea; +import com.xpn.xwiki.wysiwyg.client.widget.rta.cmd.Executable; + +/** + * Executable for the unlink command, to remove a link in the wiki document. The following rules apply: + * <ul> + * <li>if there is no selection and the cursor is inside a wikilink, remove the enclosing link</li> + * <li>if there is a selection which is fully inside or equal to a wikilink, remove the enclosing link</li> + * <li>the command is not enabled in any other situation</li> + * </ul> + * + * @version $Id$ + */ +public class UnlinkExecutable implements Executable +{ + /** + * Hold the name of the anchor tag. + */ + private static final String ANCHOR = "a"; + + /** + * Constant for the comment node type. + */ + private static final short NODE_TYPE_COMMENT = 8; + + /** + * {@inheritDoc} + */ + public boolean execute(RichTextArea rta, String param) + { + // Get the wrapping anchor + Range range = DOMUtils.getInstance().getTextRange(rta.getDocument().getSelection().getRangeAt(0)); + Node anchor = DOMUtils.getInstance().getFirstAncestor(range.getCommonAncestorContainer(), ANCHOR); + if (anchor == null) { + return false; + } + // check its parent, if it's a span + Node wrappingSpan = anchor.getParentNode(); + if (wrappingSpan == null || wrappingSpan.getNodeType() != Node.ELEMENT_NODE + || !wrappingSpan.getNodeName().equalsIgnoreCase("span")) { + // we have no span wrapping the anchor, is not a wikilink + boolean result = removeAnchor(Element.as(anchor), rta, range); + } + // check the span class + String spanClass = Element.as(wrappingSpan).getClassName(); + if (!spanClass.equalsIgnoreCase("wikilink") && !spanClass.equalsIgnoreCase("wikiexternallink") + && !spanClass.equalsIgnoreCase("wikicreatelink")) { + // we haven't the expected class on the span + return removeAnchor(Element.as(anchor), rta, range); + } + // check the comments before and after + Node nodeBefore = wrappingSpan.getPreviousSibling(); + Node nodeAfter = wrappingSpan.getNextSibling(); + if (nodeBefore == null || nodeAfter == null || nodeBefore.getNodeType() != NODE_TYPE_COMMENT + || nodeAfter.getNodeType() != NODE_TYPE_COMMENT) { + // missing or wrong sibling nodes for the wikilink span + return removeAnchor(Element.as(anchor), rta, range); + } + if (nodeBefore.getNodeValue().startsWith("startwikilink:") + && nodeAfter.getNodeValue().equalsIgnoreCase("stopwikilink")) { + // WOUHOU! found wikilink, remove it + return removeWikiLink(nodeBefore, Element.as(anchor), rta, range); + } + return removeAnchor(Element.as(anchor), rta, range); + } + + /** + * Removes an anchor by replacing it with all its children. + * + * @param anchor the anchor to remove + * @param rta the rich text area to remove the anchor from + * @param textRange the text area's original selection text range. Passed here just for cache purposes. + * @return the result of this operation + */ + private boolean removeAnchor(Element anchor, RichTextArea rta, Range textRange) + { + // Store the current selection + Node startNode = textRange.getStartContainer(); + int startOffset = textRange.getStartOffset(); + Node endNode = textRange.getEndContainer(); + int endOffset = textRange.getEndOffset(); + // Remove all children from the anchor and insert them before the anchor. + Node currentNode = anchor.getFirstChild(); + while (currentNode != null) { + anchor.removeChild(currentNode); + anchor.getParentNode().insertBefore(currentNode, anchor); + currentNode = anchor.getFirstChild(); + } + // remove the anchor from its parent + anchor.getParentElement().removeChild(anchor); + // restore the selection of the rta to the original text range + Range newRange = rta.getDocument().createRange(); + newRange.setStart(startNode, startOffset); + newRange.setEnd(endNode, endOffset); + rta.getDocument().getSelection().removeAllRanges(); + rta.getDocument().getSelection().addRange(newRange); + return true; + } + + /** + * Removes a wikilink by replacing it with the contents of the passed anchor. The wikilink is given by the + * startComment, considering that, along with the next 2 nodes, it represents the wikilink. + * + * @param startComment the start comment of this wikilink + * @param anchor the anchor enclosed by this wikilink + * @param rta the rich text area to remove the wikilink from + * @param textRange the text area's original selection text range. Passed here just for cache purposes. + * @return the result of the replacement + */ + private boolean removeWikiLink(Node startComment, Element anchor, RichTextArea rta, Range textRange) + { + // Store the current selection + Node startNode = textRange.getStartContainer(); + int startOffset = textRange.getStartOffset(); + Node endNode = textRange.getEndContainer(); + int endOffset = textRange.getEndOffset(); + Node currentNode = anchor.getFirstChild(); + Node spanNode = startComment.getNextSibling(); + if (spanNode == null) { + return false; + } + Node endComment = spanNode.getNextSibling(); + if (endComment == null) { + return false; + } + while (currentNode != null) { + anchor.removeChild(currentNode); + startComment.getParentNode().insertBefore(currentNode, startComment); + currentNode = anchor.getFirstChild(); + } + // Done, remove the comments & spans from the parent + startComment.getParentNode().removeChild(startComment); + spanNode.getParentNode().removeChild(spanNode); + endComment.getParentNode().removeChild(endComment); + // restore the selection of the rta to the original text range + Range newRange = rta.getDocument().createRange(); + newRange.setStart(startNode, startOffset); + newRange.setEnd(endNode, endOffset); + rta.getDocument().getSelection().removeAllRanges(); + rta.getDocument().getSelection().addRange(newRange); + return true; + } + + /** + * Restores the current selection to the passed text range. To be used after the DOM operations to restore the + * selection in the text area. The selection will be set to the passed <code>textRange</code> to be sure that we are + * not trying to set the selection inside a removed element. We use just a range for the original selection since we + * use only the first range of the selection anyway. + * + * @param rta the {@link RichTextArea} for which the selection restore is done + * @param textRange text range to set the first range of the selection to + */ + private void restoreSelection(RichTextArea rta, Range textRange) + { + + Document doc = rta.getDocument(); + Selection selection = doc.getSelection(); + selection.removeAllRanges(); + selection.addRange(textRange); + } + + /** + * {@inheritDoc} + */ + public String getParameter(RichTextArea rta) + { + return null; + } + + /** + * {@inheritDoc} + */ + public boolean isEnabled(RichTextArea rta) + { + // Check the selection, to be either void or inside a link. + Range range = DOMUtils.getInstance().getTextRange(rta.getDocument().getSelection().getRangeAt(0)); + return DOMUtils.getInstance().getFirstAncestor(range.getCommonAncestorContainer(), ANCHOR) != null; + } + + /** + * {@inheritDoc} + */ + public boolean isExecuted(RichTextArea rta) + { + return !isEnabled(rta); + } + + /** + * {@inheritDoc} + */ + public boolean isSupported(RichTextArea rta) + { + return true; + } +}
Modified: platform/web/trunk/wysiwyg/src/main/resources/com/xpn/xwiki/wysiwyg/client/editor/Strings.properties =================================================================== --- platform/web/trunk/wysiwyg/src/main/resources/com/xpn/xwiki/wysiwyg/client/editor/Strings.properties 2008-11-12 19:52:43 UTC (rev 14183) +++ platform/web/trunk/wysiwyg/src/main/resources/com/xpn/xwiki/wysiwyg/client/editor/Strings.properties 2008-11-12 22:17:54 UTC (rev 14184) @@ -29,7 +29,6 @@ justifyFull=Align full justifyLeft=Align left justifyRight=Align right -link=Insert/edit link ol=Ordered list outdent=Outdent paste=Paste @@ -50,4 +49,16 @@ insertTable=Inserts a new table underline=Underline (CTRL+U) undo=Undo (CTRL+Z) -unlink=Unlink \ No newline at end of file +link=Insert link +unlink=Unlink +linkCreateLinkButon=Create Link +linkEmailTab=Email address +linkWebPageTab=Web page +linkLabelLabel=Label: +linkWebPageLabel=Webpage address: +linkEmailLabel=Email address: +linkEmailAddressTextBox=Type here the email address you want to link to... +linkWebPageTextBox=Type here the address of the webpage you want to link to... +linkEmailAddressError=The email address wasn't set! +linkWebPageAddressError=The web page address wasn't set! +linkNoLabelError=The label of the link cannot be void! \ No newline at end of file
Modified: platform/web/trunk/wysiwyg/src/main/resources/com/xpn/xwiki/wysiwyg/public/Wysiwyg.css =================================================================== --- platform/web/trunk/wysiwyg/src/main/resources/com/xpn/xwiki/wysiwyg/public/Wysiwyg.css 2008-11-12 19:52:43 UTC (rev 14183) +++ platform/web/trunk/wysiwyg/src/main/resources/com/xpn/xwiki/wysiwyg/public/Wysiwyg.css 2008-11-12 22:17:54 UTC (rev 14184) @@ -179,6 +179,7 @@ background-color:#FFA500; white-space:nowrap; line-height:16px; + height: 16px; cursor:move; }
@@ -215,3 +216,54 @@ /* IE6 */ width: 1px; } +/********styles for link********/ +.gwt-TabBar { +} +.gwt-TabBar .gwt-TabBarFirst { + width: 5px; /* first tab distance from the left */ +} +.gwt-TabBar .gwt-TabBarRest { +} +.gwt-TabBar .gwt-TabBarItem { + margin-left: 6px; + padding: 3px 6px 3px 6px; + cursor: pointer; + cursor: hand; + color: black; + font-weight: bold; + text-align: center; + background: #d0e4f6; +} +.gwt-TabBar .gwt-TabBarItem-selected { + cursor: default; + background: #92c1f0; +} +.gwt-TabPanel { + padding: 6px; +} +.gwt-TabPanelBottom { + border-color: #92c1f0; + border-style: solid; + border-width: 3px 2px 2px; + overflow: hidden; + padding: 6px; +} +.gwt-PopupPanel { + background: white; +} + +.xLinkToUrl .gwt-Label{ + font-weight: bold; + width: 300px; + padding: 5px; + +} +.xLinkToUrl .gwt-TextBox{ + font-size: x-small; + margin: 0 5px; + width: 300px; +} +.xLinkToUrl .gwt-Button{ + font-size: x-small; + margin: 8px; +} \ No newline at end of file
_______________________________________________ notifications mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/notifications
participants (1)
-
Anca Paula Luca