tmortagne (SVN) wrote:
> Author: tmortagne
> Date: 2008-11-14 15:41:52 +0100 (Fri, 14 Nov 2008)
> New Revision: 14215
>
> Added:
> platform/core/trunk/xwiki-core/src/test/java/com/xpn/xwiki/XWikiContextTest.java
> Modified:
> platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/XWikiContext.java
> Log:
> XWIKI-2837: Class Cache in context is not database aware
> Applied patch from Denis Gervalle (just added the base class's wiki if exists)
>
> Modified: platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/XWikiContext.java
> ===================================================================
> --- platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/XWikiContext.java 2008-11-14 14:41:34 UTC (rev 14214)
> +++ platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/XWikiContext.java 2008-11-14 14:41:52 UTC (rev 14215)
> @@ -407,16 +407,47 @@
> put("mainxwiki", str);
> }
>
> - // Used to avoid recursive loading of documents if there are recursives usage of classes
> + /**
> + * Used to avoid recurrent loading of documents if there are recurrent usage of classes.
> + *
> + * @param bclass the class to cache.
> + */
> public void addBaseClass(BaseClass bclass)
> {
> - this.classCache.put(bclass.getName(), bclass);
> + String className = bclass.getName();
> + if (bclass.getWiki() != null) {
> + StringBuffer sb = new StringBuffer(bclass.getWiki());
> + sb.append(":");
> + sb.append(className);
> + className = sb.toString();
> + } else if (getDatabase() != null) {
> + StringBuffer sb = new StringBuffer(getDatabase());
> + sb.append(":");
> + sb.append(className);
> + className = sb.toString();
> + }
> +
> + this.classCache.put(className, bclass);
> }
>
> - // Used to avoid recursive loading of documents if there are recursives usage of classes
> + /**
> + * Used to avoid recurrent loading of documents if there are recurrent usage of classes.
> + *
> + * @param name the local name (without the wiki identifier) of the xclass. The wiki identifier is taken from
> + * {@link #getDatabase()}.
> + * @return the cached xclass or null if the cache does not contains any xclass.
> + */
> public BaseClass getBaseClass(String name)
> {
> - return this.classCache.get(name);
> + String classname = name;
> + if (getDatabase() != null) {
> + StringBuffer sb = new StringBuffer(getDatabase());
> + sb.append(":");
> + sb.append(name);
> + classname = sb.toString();
> + }
> +
> + return this.classCache.get(classname);
> }
>
> // Used to avoid recursive loading of documents if there are recursives usage of classes
>
Unfortunately this has a bad side effect:
org.hibernate.NonUniqueObjectException: a different object with the same
identifier value was already associated with the session:
[com.xpn.xwiki.doc.XWikiDocument#-34276813]
Lots of errors were displayed when starting the server, caused by
http://jira.xwiki.org/jira/browse/XWIKI-2842 and the fact that although
the class cache sees XWiki.Tags and xwiki:XWiki.Tags as different
entities, in Hibernate they represent the same entity.
--
Sergiu Dumitriu
http://purl.org/net/sergiu/
Hi devs,
The first proposal is about introducing two $xwiki.countDocuments
methods, one that accepts a simple hql query, and one that accepts a
parametrized query and a list of parameter values. These work like
searchDocuments, but instead of prefixing the query fragment with
'select doc.fullName from XWikiDocument as doc', it will prefix it with
'select count(*) from XWikiDOcument as doc'.
This will allow to count documents without using a programming-protected
query, and without retrieving all the documents and count the results.
Such a method is needed for paging results, for example.
The second proposal is a temporary hack for hiding documents. The idea
is to add a new field in the XWikiDocument class, 'hidden', which will
be automatically used in searchDocuments and countDocuments to filter
out special documents. This is a workaround until we will be able to tag
special documents or spaces, and will allow to create special documents
needed for an application inside the main application's space, instead
of the generic XWiki space. Such hidden pages won't appear in normal
search results, the index page or the navigation panel.
To show these documents (for admins, for example) we could add another
searchDocuments method which accepts a boolean parameter that enables or
disables the filter on the 'hidden' property.
--
Sergiu Dumitriu
http://purl.org/net/sergiu/
Hello XWikiers,
I am trying to sketch a best scenario for the update of our curriki
derivative.
As is common in most xwiki-based sites, i2geo is based on a
distribution that builds from a multi-module source-directory into a
web-archive and an xwiki-archive.
What's in the xwiki archive and in the web-archive is tuned by
installers. These tunes need to be brought back to source: for webapp
changes it's often easy, for wiki-pages changes it is a matter of xar
export and expansion in principle.
Now comes the time to update because curriki has released anew.
How can I do it?
Ideally simply run svn update on the source which has been brought
back of all changes and rebuild and redeploy.
Generally there will be conflicts and they should be address
individually.
For the xwiki documents this is highly uncomfortable and this speaks
again in favour of detached source-files in xwiki sources: the svn
update should update the source code of documents as a source and
conflicts should be solved there.
Any advance in this direction?
paul
Hi devs, Asiri,
I finally found the time to apply Asiri's patch to integrate the WebDAV
module in the default XE, and here are some comments/ideas:
- I like this new feature, combined with KDE. I was able to start
Konqueror, point it to localhost, and start editing wiki files in my
favorite editor, Kate.
- It seems to be much faster than the web view, which suggests that
indeed most of the time is spent on rendering.
- I wasn't able to create new wiki documents. Is there something special
I should do? Is it not supported yet? Is Konqueror alone guilty?
- Also, the error I get doesn't seem right (File already exists), since
the file I want to create definitely doesn't exist.
- Since it uses Basic authentication, we should advertise that
authentication is not secure, thus it should only be used inside trusted
intranets, over VLANs or over SSL.
Code related:
- Looking a bit over the code, I noticed that we're using only a bit
from the jackrabit-jcr-server library, and I was wondering if it would
be possible to refactor all the code that needs it to use something
else, so that we have one dependency in minus.
- Also, I noticed that you're using slf4j as the logging framework,
which doesn't fit with the rest of the XWiki code, since we're using
commons-logging. Still, this is also the framework used by jackrabbit,
so we can't get rid of it completely. Asiri, could you update the code
to use commons-logging?
- Although there are integration tests, some unit tests would be great.
I know it's hard for the moment to do proper unit testing, since most of
the code works closely with the old core, which doesn't contribute to a
good testing scenario.
Congratulations for the good work, Asiri!
--
Sergiu Dumitriu
http://purl.org/net/sergiu/
On Fri, Nov 14, 2008 at 6:46 AM, Sergiu Dumitriu (JIRA) <jira(a)xwiki.org>wrote:
>
> [
> http://jira.xwiki.org/jira/browse/XWIKI-2771?page=com.atlassian.jira.plugin…]
>
> Sergiu Dumitriu closed XWIKI-2771.
> ----------------------------------
>
> Tests: [Integration]
> Fix Version/s: 1.7 M3
> Resolution: Fixed
>
> Done. Thanks for the good work, Asiri.
>
You are welcome. And many thanks for reviewing the patch.
I have another patch for webdav xwiki-ui integration, need to dig it up now
;)
- Asiri
Hi devs,
Until now, filesystem resources were not forced to a specific encoding
(except ResourceBundle translation resources, which are forced by the
spec to contain only ISO-8859-1 characters and unicode escapes). And the
number of files not being ASCII was kept to 0, thus a policy wasn't
needed. However, it is better to set a rule, in case third party
developers need to place non-ascii characters in source files, such as
JavaScript or CSS extensions and skin files. So, here are some proposed
rules we should make public on our dev site, and follow ourselves.
1. All Java source files must contain only ASCII chars, unicode escapes
inside strings when needed, and xml entities in javadocs. Since we don't
use @author tags, this should not be a problem.
2. All translation files contain only ASCII chars and unicode escapes
(stronger than the spec).
3. All wiki documents sources must be stored in UTF-8.
4. Other XML files should always specify their encoding in the <?xml
header, and it should be as often as possible UTF-8.
5. All other textual resources must be stored in UTF-8, minimizing the
use of non-ASCII chars.
The changes are that:
1: This is the practice we were already using, but we didn't have a
written rule on this.
2: This is the practice we were already using, but we didn't have a
written rule on this, except in the "Contributing" page.
3: Wiki sources are currently in ISO-8859-1 because our default package
ships with that encoding, and XML exports are usually done from the
default package. This is not really a problem, since the XML reader can
detect and use the encoding specified inside the document itself.
4: Not a strong requirement, but a suggestion only. Most of our XMLs are
currently using ISO-8859-1, but since they only contain ASCII chars, it
doesn't really make a difference.
5: There was no rule on this, and the resources were always read using
the system encoding, which means that our package is not 100% portable
now, unless we force people to set a specific JVM encoding. I'd like to
force UTF-8 as the encoding for this kind of resources since it is hard
to represent all the characters in 8bit encodings.
WDYT?
--
Sergiu Dumitriu
http://purl.org/net/sergiu/
Hi devs,
Currently in xwiki syntax 2.0 we are using
|| title cell 1 || title cell2
| cell 1 | cell 2
for table syntax.
The problem is that with this grammar it's impossible to have empty
cells because you can't use || as it mean title cell.
But we have an alternative grammar for table which is
!! title cell 1 !! title cell2
:: cell 1 :: cell 2
which can represnet empty cell with ::::
So I propose to use !! :: instead of || | by default for xwiki syntax rendering.
WDYT ?
I'm +1 for it
Now there is another problem: it seems ampty cells are not permitted
in xhtml and have to contains at least
If we render empty cells as <td> </td> and reparse it we will get
a space in wiki syntax in place of empty cell.
There is the solution of saying, it's a limitation and a cell should
not be empty in xwiki syntax or we will have to use to tricky comment
in xhtml renderer...
Does someone has a good idea about that ?
Thanks
--
Thomas Mortagne
The XWiki development team is pleased to announce the release of XWiki
Enterprise 1.7 Milestone 2. Second milestone of the XWiki Enterprise
1.7 version.
Go grab it at http://www.xwiki.org/xwiki/bin/view/Main/Download
Main changes:
* Work in progress on the new XWiki Syntax v2.0.
* Work in progress on the new WYSIWYG editor.
* Added a ROOT webapp to the standalone distribution.
Important bug fixes:
* SMTP server address is not re-read when it's changed in global preferences
* Watchlist update sent by email does not contain the full path to a
changed attachment
Note that general goals for XWiki Enterprise 1.7 are:
* Working and usable (i.e. users can use them for their day to day
work instead of the old Syntax and old WYSIWYG editor) versions of new
rendering and new WYSIWYG editor.
* Working JCR (can be used for day to day work instead of Hibernate).
* French XE
* Blog revamping
* Webdav integration
For more information see the Release notes at:
http://www.xwiki.org/xwiki/bin/view/Main/ReleaseNotesXWikiEnterprise17M2
Thanks,
The XWiki dev team
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:john@doe.com-->
> + // <span class="wikiexternallink">
> + // <a href="mailto:john@doe.com">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
> notifications(a)xwiki.org
> http://lists.xwiki.org/mailman/listinfo/notifications