Index: typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js
===================================================================
--- typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js	(révision 7101)
+++ typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js	(copie de travail)
@@ -1405,6 +1405,424 @@
 	}
 });
 Ext.reg('htmlareaiframe', HTMLArea.Iframe);
+/*!
+ * Ext JS Library 3.1.1
+ * Copyright(c) 2006-2010 Ext JS, LLC
+ * licensing@extjs.com
+ * http://www.extjs.com/license
+ */
+/**
+ * @class Ext.ux.StatusBar
+ * <p>Basic status bar component that can be used as the bottom toolbar of any {@link Ext.Panel}.  In addition to
+ * supporting the standard {@link Ext.Toolbar} interface for adding buttons, menus and other items, the StatusBar
+ * provides a greedy status element that can be aligned to either side and has convenient methods for setting the
+ * status text and icon.  You can also indicate that something is processing using the {@link #showBusy} method.</p>
+ * <pre><code>
+new Ext.Panel({
+    title: 'StatusBar',
+    // etc.
+    bbar: new Ext.ux.StatusBar({
+        id: 'my-status',
+
+        // defaults to use when the status is cleared:
+        defaultText: 'Default status text',
+        defaultIconCls: 'default-icon',
+
+        // values to set initially:
+        text: 'Ready',
+        iconCls: 'ready-icon',
+
+        // any standard Toolbar items:
+        items: [{
+            text: 'A Button'
+        }, '-', 'Plain Text']
+    })
+});
+
+// Update the status bar later in code:
+var sb = Ext.getCmp('my-status');
+sb.setStatus({
+    text: 'OK',
+    iconCls: 'ok-icon',
+    clear: true // auto-clear after a set interval
+});
+
+// Set the status bar to show that something is processing:
+sb.showBusy();
+
+// processing....
+
+sb.clearStatus(); // once completeed
+</code></pre>
+ * @extends Ext.Toolbar
+ * @constructor
+ * Creates a new StatusBar
+ * @param {Object/Array} config A config object
+ */
+Ext.ux.StatusBar = Ext.extend(Ext.Toolbar, {
+    /**
+     * @cfg {String} statusAlign
+     * The alignment of the status element within the overall StatusBar layout.  When the StatusBar is rendered,
+     * it creates an internal div containing the status text and icon.  Any additional Toolbar items added in the
+     * StatusBar's {@link #items} config, or added via {@link #add} or any of the supported add* methods, will be
+     * rendered, in added order, to the opposite side.  The status element is greedy, so it will automatically
+     * expand to take up all sapce left over by any other items.  Example usage:
+     * <pre><code>
+// Create a left-aligned status bar containing a button,
+// separator and text item that will be right-aligned (default):
+new Ext.Panel({
+    title: 'StatusBar',
+    // etc.
+    bbar: new Ext.ux.StatusBar({
+        defaultText: 'Default status text',
+        id: 'status-id',
+        items: [{
+            text: 'A Button'
+        }, '-', 'Plain Text']
+    })
+});
+
+// By adding the statusAlign config, this will create the
+// exact same toolbar, except the status and toolbar item
+// layout will be reversed from the previous example:
+new Ext.Panel({
+    title: 'StatusBar',
+    // etc.
+    bbar: new Ext.ux.StatusBar({
+        defaultText: 'Default status text',
+        id: 'status-id',
+        statusAlign: 'right',
+        items: [{
+            text: 'A Button'
+        }, '-', 'Plain Text']
+    })
+});
+</code></pre>
+     */
+    /**
+     * @cfg {String} defaultText
+     * The default {@link #text} value.  This will be used anytime the status bar is cleared with the
+     * <tt>useDefaults:true</tt> option (defaults to '').
+     */
+    /**
+     * @cfg {String} defaultIconCls
+     * The default {@link #iconCls} value (see the iconCls docs for additional details about customizing the icon).
+     * This will be used anytime the status bar is cleared with the <tt>useDefaults:true</tt> option (defaults to '').
+     */
+    /**
+     * @cfg {String} text
+     * A string that will be <b>initially</b> set as the status message.  This string
+     * will be set as innerHTML (html tags are accepted) for the toolbar item.
+     * If not specified, the value set for <code>{@link #defaultText}</code>
+     * will be used.
+     */
+    /**
+     * @cfg {String} iconCls
+     * A CSS class that will be <b>initially</b> set as the status bar icon and is
+     * expected to provide a background image (defaults to '').
+     * Example usage:<pre><code>
+// Example CSS rule:
+.x-statusbar .x-status-custom {
+    padding-left: 25px;
+    background: transparent url(images/custom-icon.gif) no-repeat 3px 2px;
+}
+
+// Setting a default icon:
+var sb = new Ext.ux.StatusBar({
+    defaultIconCls: 'x-status-custom'
+});
+
+// Changing the icon:
+sb.setStatus({
+    text: 'New status',
+    iconCls: 'x-status-custom'
+});
+</code></pre>
+     */
+
+    /**
+     * @cfg {String} cls
+     * The base class applied to the containing element for this component on render (defaults to 'x-statusbar')
+     */
+    cls : 'x-statusbar',
+    /**
+     * @cfg {String} busyIconCls
+     * The default <code>{@link #iconCls}</code> applied when calling
+     * <code>{@link #showBusy}</code> (defaults to <tt>'x-status-busy'</tt>).
+     * It can be overridden at any time by passing the <code>iconCls</code>
+     * argument into <code>{@link #showBusy}</code>.
+     */
+    busyIconCls : 'x-status-busy',
+    /**
+     * @cfg {String} busyText
+     * The default <code>{@link #text}</code> applied when calling
+     * <code>{@link #showBusy}</code> (defaults to <tt>'Loading...'</tt>).
+     * It can be overridden at any time by passing the <code>text</code>
+     * argument into <code>{@link #showBusy}</code>.
+     */
+    busyText : 'Loading...',
+    /**
+     * @cfg {Number} autoClear
+     * The number of milliseconds to wait after setting the status via
+     * <code>{@link #setStatus}</code> before automatically clearing the status
+     * text and icon (defaults to <tt>5000</tt>).  Note that this only applies
+     * when passing the <tt>clear</tt> argument to <code>{@link #setStatus}</code>
+     * since that is the only way to defer clearing the status.  This can
+     * be overridden by specifying a different <tt>wait</tt> value in
+     * <code>{@link #setStatus}</code>. Calls to <code>{@link #clearStatus}</code>
+     * always clear the status bar immediately and ignore this value.
+     */
+    autoClear : 5000,
+
+    /**
+     * @cfg {String} emptyText
+     * The text string to use if no text has been set.  Defaults to
+     * <tt>'&nbsp;'</tt>).  If there are no other items in the toolbar using
+     * an empty string (<tt>''</tt>) for this value would end up in the toolbar
+     * height collapsing since the empty string will not maintain the toolbar
+     * height.  Use <tt>''</tt> if the toolbar should collapse in height
+     * vertically when no text is specified and there are no other items in
+     * the toolbar.
+     */
+    emptyText : '&nbsp;',
+
+    // private
+    activeThreadId : 0,
+
+    // private
+    initComponent : function(){
+        if(this.statusAlign=='right'){
+            this.cls += ' x-status-right';
+        }
+        Ext.ux.StatusBar.superclass.initComponent.call(this);
+    },
+
+    // private
+    afterRender : function(){
+        Ext.ux.StatusBar.superclass.afterRender.call(this);
+
+        var right = this.statusAlign == 'right';
+        this.currIconCls = this.iconCls || this.defaultIconCls;
+        this.statusEl = new Ext.Toolbar.TextItem({
+            cls: 'x-status-text ' + (this.currIconCls || ''),
+            text: this.text || this.defaultText || ''
+        });
+
+        if(right){
+            this.add('->');
+            this.add(this.statusEl);
+        }else{
+            this.insert(0, this.statusEl);
+            this.insert(1, '->');
+        }
+        this.doLayout();
+    },
+
+    /**
+     * Sets the status {@link #text} and/or {@link #iconCls}. Also supports automatically clearing the
+     * status that was set after a specified interval.
+     * @param {Object/String} config A config object specifying what status to set, or a string assumed
+     * to be the status text (and all other options are defaulted as explained below). A config
+     * object containing any or all of the following properties can be passed:<ul>
+     * <li><tt>text</tt> {String} : (optional) The status text to display.  If not specified, any current
+     * status text will remain unchanged.</li>
+     * <li><tt>iconCls</tt> {String} : (optional) The CSS class used to customize the status icon (see
+     * {@link #iconCls} for details). If not specified, any current iconCls will remain unchanged.</li>
+     * <li><tt>clear</tt> {Boolean/Number/Object} : (optional) Allows you to set an internal callback that will
+     * automatically clear the status text and iconCls after a specified amount of time has passed. If clear is not
+     * specified, the new status will not be auto-cleared and will stay until updated again or cleared using
+     * {@link #clearStatus}. If <tt>true</tt> is passed, the status will be cleared using {@link #autoClear},
+     * {@link #defaultText} and {@link #defaultIconCls} via a fade out animation. If a numeric value is passed,
+     * it will be used as the callback interval (in milliseconds), overriding the {@link #autoClear} value.
+     * All other options will be defaulted as with the boolean option.  To customize any other options,
+     * you can pass an object in the format:<ul>
+     *    <li><tt>wait</tt> {Number} : (optional) The number of milliseconds to wait before clearing
+     *    (defaults to {@link #autoClear}).</li>
+     *    <li><tt>anim</tt> {Number} : (optional) False to clear the status immediately once the callback
+     *    executes (defaults to true which fades the status out).</li>
+     *    <li><tt>useDefaults</tt> {Number} : (optional) False to completely clear the status text and iconCls
+     *    (defaults to true which uses {@link #defaultText} and {@link #defaultIconCls}).</li>
+     * </ul></li></ul>
+     * Example usage:<pre><code>
+// Simple call to update the text
+statusBar.setStatus('New status');
+
+// Set the status and icon, auto-clearing with default options:
+statusBar.setStatus({
+    text: 'New status',
+    iconCls: 'x-status-custom',
+    clear: true
+});
+
+// Auto-clear with custom options:
+statusBar.setStatus({
+    text: 'New status',
+    iconCls: 'x-status-custom',
+    clear: {
+        wait: 8000,
+        anim: false,
+        useDefaults: false
+    }
+});
+</code></pre>
+     * @return {Ext.ux.StatusBar} this
+     */
+    setStatus : function(o){
+        o = o || {};
+
+        if(typeof o == 'string'){
+            o = {text:o};
+        }
+        if(o.text !== undefined){
+            this.setText(o.text);
+        }
+        if(o.iconCls !== undefined){
+            this.setIcon(o.iconCls);
+        }
+
+        if(o.clear){
+            var c = o.clear,
+                wait = this.autoClear,
+                defaults = {useDefaults: true, anim: true};
+
+            if(typeof c == 'object'){
+                c = Ext.applyIf(c, defaults);
+                if(c.wait){
+                    wait = c.wait;
+                }
+            }else if(typeof c == 'number'){
+                wait = c;
+                c = defaults;
+            }else if(typeof c == 'boolean'){
+                c = defaults;
+            }
+
+            c.threadId = this.activeThreadId;
+            this.clearStatus.defer(wait, this, [c]);
+        }
+        return this;
+    },
+
+    /**
+     * Clears the status {@link #text} and {@link #iconCls}. Also supports clearing via an optional fade out animation.
+     * @param {Object} config (optional) A config object containing any or all of the following properties.  If this
+     * object is not specified the status will be cleared using the defaults below:<ul>
+     * <li><tt>anim</tt> {Boolean} : (optional) True to clear the status by fading out the status element (defaults
+     * to false which clears immediately).</li>
+     * <li><tt>useDefaults</tt> {Boolean} : (optional) True to reset the text and icon using {@link #defaultText} and
+     * {@link #defaultIconCls} (defaults to false which sets the text to '' and removes any existing icon class).</li>
+     * </ul>
+     * @return {Ext.ux.StatusBar} this
+     */
+    clearStatus : function(o){
+        o = o || {};
+
+        if(o.threadId && o.threadId !== this.activeThreadId){
+            // this means the current call was made internally, but a newer
+            // thread has set a message since this call was deferred.  Since
+            // we don't want to overwrite a newer message just ignore.
+            return this;
+        }
+
+        var text = o.useDefaults ? this.defaultText : this.emptyText,
+            iconCls = o.useDefaults ? (this.defaultIconCls ? this.defaultIconCls : '') : '';
+
+        if(o.anim){
+            // animate the statusEl Ext.Element
+            this.statusEl.el.fadeOut({
+                remove: false,
+                useDisplay: true,
+                scope: this,
+                callback: function(){
+                    this.setStatus({
+	                    text: text,
+	                    iconCls: iconCls
+	                });
+
+                    this.statusEl.el.show();
+                }
+            });
+        }else{
+            // hide/show the el to avoid jumpy text or icon
+            this.statusEl.hide();
+	        this.setStatus({
+	            text: text,
+	            iconCls: iconCls
+	        });
+            this.statusEl.show();
+        }
+        return this;
+    },
+
+    /**
+     * Convenience method for setting the status text directly.  For more flexible options see {@link #setStatus}.
+     * @param {String} text (optional) The text to set (defaults to '')
+     * @return {Ext.ux.StatusBar} this
+     */
+    setText : function(text){
+        this.activeThreadId++;
+        this.text = text || '';
+        if(this.rendered){
+            this.statusEl.setText(this.text);
+        }
+        return this;
+    },
+
+    /**
+     * Returns the current status text.
+     * @return {String} The status text
+     */
+    getText : function(){
+        return this.text;
+    },
+
+    /**
+     * Convenience method for setting the status icon directly.  For more flexible options see {@link #setStatus}.
+     * See {@link #iconCls} for complete details about customizing the icon.
+     * @param {String} iconCls (optional) The icon class to set (defaults to '', and any current icon class is removed)
+     * @return {Ext.ux.StatusBar} this
+     */
+    setIcon : function(cls){
+        this.activeThreadId++;
+        cls = cls || '';
+
+        if(this.rendered){
+	        if(this.currIconCls){
+	            this.statusEl.removeClass(this.currIconCls);
+	            this.currIconCls = null;
+	        }
+	        if(cls.length > 0){
+	            this.statusEl.addClass(cls);
+	            this.currIconCls = cls;
+	        }
+        }else{
+            this.currIconCls = cls;
+        }
+        return this;
+    },
+
+    /**
+     * Convenience method for setting the status text and icon to special values that are pre-configured to indicate
+     * a "busy" state, usually for loading or processing activities.
+     * @param {Object/String} config (optional) A config object in the same format supported by {@link #setStatus}, or a
+     * string to use as the status text (in which case all other options for setStatus will be defaulted).  Use the
+     * <tt>text</tt> and/or <tt>iconCls</tt> properties on the config to override the default {@link #busyText}
+     * and {@link #busyIconCls} settings. If the config argument is not specified, {@link #busyText} and
+     * {@link #busyIconCls} will be used in conjunction with all of the default options for {@link #setStatus}.
+     * @return {Ext.ux.StatusBar} this
+     */
+    showBusy : function(o){
+        if(typeof o == 'string'){
+            o = {text:o};
+        }
+        o = Ext.applyIf(o || {}, {
+            text: this.busyText,
+            iconCls: this.busyIconCls
+        });
+        return this.setStatus(o);
+    }
+});
+Ext.reg('statusbar', Ext.ux.StatusBar);
 /*
  * HTMLArea.StatusBar extends Ext.Container
  */
@@ -4006,6 +4424,7 @@
 	 * Dialogue window onClose handler
 	 */
 	onClose: function () {
+		this.editor.focus();
 		this.restoreSelection();
 	 	this.editor.updateToolbar();
 	},
@@ -4014,6 +4433,7 @@
 	 */
 	onCancel: function () {
 		this.dialog.close();
+		this.editor.focus();
 	},
 	/*
 	 * Save selection
Index: typo3/sysext/rtehtmlarea/htmlarea/locallang_dialogs.xml
===================================================================
--- typo3/sysext/rtehtmlarea/htmlarea/locallang_dialogs.xml	(révision 7101)
+++ typo3/sysext/rtehtmlarea/htmlarea/locallang_dialogs.xml	(copie de travail)
@@ -112,6 +112,7 @@
 			<label index="No language mark">No language</label>
 			<label index="Remove language mark">Remove language</label>
 			<label index="statusBarStyle">Style</label>
+			<label index="statusBarReady">Ready</label>
 		</languageKey>
 	</data>
 	<orig_hash type="array">
Index: typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/locallang.xml
===================================================================
--- typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/locallang.xml	(révision 7101)
+++ typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/locallang.xml	(copie de travail)
@@ -23,6 +23,7 @@
 			<label index="HTMLArea Spell Checker">HTMLArea Spell Checker</label>
 			<label index="QUIT_CONFIRMATION">This will drop changes and quit spell checker.  Please confirm.</label>
 			<label index="Re-check">Re-check</label>
+			<label index="Replacement">Replacement</label>
 			<label index="Replace all">Replace all</label>
 			<label index="Replace with">Replace with</label>
 			<label index="Replace">Replace</label>
@@ -36,6 +37,7 @@
 			<label index="of the word">of the word</label>
 			<label index="was found.">was found.</label>
 			<label index="were found.">were found.</label>
+			<label index="Info">Info</label>
 			<label index="Document information">Document information</label>
 			<label index="No information available">No information available</label>
 			<label index="Total words">Total words</label>
Index: typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui-iso-8859-1.html
===================================================================
--- typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui-iso-8859-1.html	(révision 7101)
+++ typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui-iso-8859-1.html	(copie de travail)
@@ -1,101 +0,0 @@
-<!DOCTYPE html
-     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<?xml version="1.0" encoding="iso-8859-1"?>
-<html>
-<!--
-/***************************************************************
-*  Copyright notice
-*
-*  (c) 2003 dynarch.com. Authored by Mihai Bazon, sponsored by www.americanbible.org.
-*  (c) 2004-2008 Stanislas Rolland <typo3(arobas)sjbr.ca>
-*  All rights reserved
-*
-*  This script is part of the TYPO3 project. The TYPO3 project is
-*  free software; you can redistribute it and/or modify
-*  it under the terms of the GNU General Public License as published by
-*  the Free Software Foundation; either version 2 of the License, or
-*  (at your option) any later version.
-*
-*  The GNU General Public License can be found at
-*  http://www.gnu.org/copyleft/gpl.html.
-*  A copy is found in the textfile GPL.txt and important notices to the license
-*  from the author is found in LICENSE.txt distributed with these scripts.
-*
-*
-*  This script 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 General Public License for more details.
-*
-*  This script is a modified version of a script published under the htmlArea License.
-*  A copy of the htmlArea License may be found in the textfile HTMLAREA_LICENSE.txt.
-*
-*  This copyright notice MUST APPEAR in all copies of the script!
-***************************************************************/
-/*
- * Spell Checker Plugin for TYPO3 htmlArea RTE
- *
- * TYPO3 SVN ID: $Id$
- */
--->
-<head>
-	<title>Spell Checker</title>
-	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
-	<script type="text/javascript" src="../spell-check-ui.js"></script>
-</head>
-<body class="popupwin htmlarea-spell-check" onload="initDocument();">
-<div id="content">
-	<form id="spellcheck_form" style="display: none;" action="" method="post" target="framecontent" accept-charset="ISO-8859-1">
-		<input type="hidden" name="content" id="f_content" />
-		<input type="hidden" name="dictionary" id="f_dictionary" />
-		<input type="hidden" name="pspell_charset" id="f_charset" />
-		<input type="hidden" name="pspell_mode" id="f_pspell_mode" />
-		<input type="hidden" name="userUid" id="f_user_uid" />
-		<input type="hidden" name="enablePersonalDicts" id="f_personal_dicts" />
-		<input type="hidden" name="showDictionaries" id="f_show_dictionaries" />
-		<input type="hidden" name="restrictToDictionaries" id="f_restrict_to_dictionaries" />
-		<input type="hidden" name="init" id="f_init" value="1" />
-	</form>
-	<div class="title">Spell Checker</div>
-	<div class="dictionaries">
-		<label for="v_dictionaries">Dictionary</label>
-		<select id="v_dictionaries" name="v_dictionaries"></select>
-		<button id="b_recheck">Re-check</button>
-	</div>
-	<div class="status" id="status">Please wait. Calling spell checker.</div>
-	<div class="controls">
-		<div class="sectitle">Original word</div>
-		<div class="secbody" id="v_currentWord">pliz weit ;-)</div>
-		<div class="secbody">
-			<button id="b_revert" class="long-button">Revert</button>
-		</div>
-		<div class="sectitle"><label for="v_replacement">Replace with</label></div>
-		<div class="secbody">
-			<input type="text" id="v_replacement" name="v_replacement"/>
-			<button id="b_replace" class="long-button">Replace</button>
-			<button id="b_replall" class="long-button">Replace all</button>
-			<button id="b_ignore" class="long-button">Ignore</button>
-			<button id="b_ignall" class="long-button">Ignore all</button>
-			<button id="b_learn" class="long-button">Learn</button>
-		</div>
-		<div class="sectitle"><label for="v_suggestions">Suggestions</label></div>
-		<div class="secbody">
-			<select size="11" id="v_suggestions"></select>
-		</div>
-		<div class="secbody">
-			<button id="b_info">Info</button>
-		</div>
-	</div>
-	<div class="contentframe">
-		<iframe src="../../../popups/blank.html" id="i_framecontent" name="framecontent"></iframe>
-	</div>
-	<div id="statusbar" class="occurrences-found">&nbsp;</div>
-	<div class="space"></div>
-	<div class="buttons">
-		<button type="button" id="b_ok">OK</button>
-		<button type="button" id="b_cancel">Cancel</button>
-	</div>
-</div>
-</body>
-</html>
Index: typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui.html
===================================================================
--- typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui.html	(révision 7101)
+++ typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui.html	(copie de travail)
@@ -1,101 +0,0 @@
-<!DOCTYPE html
-     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<?xml version="1.0" encoding="utf-8"?>
-<html>
-<!--
-/***************************************************************
-*  Copyright notice
-*
-*  (c) 2003 dynarch.com. Authored by Mihai Bazon, sponsored by www.americanbible.org.
-*  (c) 2004-2008 Stanislas Rolland <typo3(arobas)sjbr.ca>
-*  All rights reserved
-*
-*  This script is part of the TYPO3 project. The TYPO3 project is
-*  free software; you can redistribute it and/or modify
-*  it under the terms of the GNU General Public License as published by
-*  the Free Software Foundation; either version 2 of the License, or
-*  (at your option) any later version.
-*
-*  The GNU General Public License can be found at
-*  http://www.gnu.org/copyleft/gpl.html.
-*  A copy is found in the textfile GPL.txt and important notices to the license
-*  from the author is found in LICENSE.txt distributed with these scripts.
-*
-*
-*  This script 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 General Public License for more details.
-*
-*  This script is a modified version of a script published under the htmlArea License.
-*  A copy of the htmlArea License may be found in the textfile HTMLAREA_LICENSE.txt.
-*
-*  This copyright notice MUST APPEAR in all copies of the script!
-***************************************************************/
-/*
- * Spell Checker Plugin for TYPO3 htmlArea RTE
- *
- * TYPO3 SVN ID: $Id$
- */
--->
-<head>
-	<title>Spell Checker</title>
-	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-	<script type="text/javascript" src="../spell-check-ui.js"></script>
-</head>
-<body class="popupwin htmlarea-spell-check" onload="initDocument();">
-<div id="content" class="spellcheck">
-	<form id="spellcheck_form" style="display: none;" action="" method="post" target="framecontent" accept-charset="UTF-8">
-		<input type="hidden" name="content" id="f_content" />
-		<input type="hidden" name="dictionary" id="f_dictionary" />
-		<input type="hidden" name="pspell_charset" id="f_charset" />
-		<input type="hidden" name="pspell_mode" id="f_pspell_mode" />
-		<input type="hidden" name="userUid" id="f_user_uid" />
-		<input type="hidden" name="enablePersonalDicts" id="f_personal_dicts" />
-		<input type="hidden" name="showDictionaries" id="f_show_dictionaries" />
-		<input type="hidden" name="restrictToDictionaries" id="f_restrict_to_dictionaries" />
-		<input type="hidden" name="init" id="f_init" value="1" />
-	</form>
-	<div class="title">Spell Checker</div>
-	<div class="dictionaries">
-		<label for="v_dictionaries">Dictionary</label>
-		<select id="v_dictionaries" name="v_dictionaries"></select>
-		<button id="b_recheck">Re-check</button>
-	</div>
-	<div class="status" id="status">Please wait. Calling spell checker.</div>
-	<div class="controls">
-		<div class="sectitle">Original word</div>
-		<div class="secbody" id="v_currentWord">pliz weit ;-)</div>
-		<div class="secbody">
-			<button id="b_revert" class="long-button">Revert</button>
-		</div>
-		<div class="sectitle"><label for="v_replacement">Replace with</label></div>
-		<div class="secbody">
-			<input type="text" id="v_replacement" name="v_replacement"/>
-			<button id="b_replace" class="long-button">Replace</button>
-			<button id="b_replall" class="long-button">Replace all</button>
-			<button id="b_ignore" class="long-button">Ignore</button>
-			<button id="b_ignall" class="long-button">Ignore all</button>
-			<button id="b_learn" class="long-button">Learn</button>
-		</div>
-		<div class="sectitle"><label for="v_suggestions">Suggestions</label></div>
-		<div class="secbody">
-			<select size="11" id="v_suggestions"></select>
-		</div>
-		<div class="secbody">
-			<button id="b_info">Info</button>
-		</div>
-	</div>
-	<div class="contentframe">
-		<iframe src="../../../popups/blank.html" id="i_framecontent" name="framecontent"></iframe>
-	</div>
-	<div id="statusbar" class="occurrences-found">&nbsp;</div>
-	<div class="space"></div>
-	<div class="buttons">
-		<button type="button" id="b_ok">OK</button>
-		<button type="button" id="b_cancel">Cancel</button>
-	</div>
-</div>
-</body>
-</html>
Index: typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-check-style.css
===================================================================
--- typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-check-style.css	(révision 7101)
+++ typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-check-style.css	(copie de travail)
@@ -1,11 +1,29 @@
-html, body { background-color: white; color: black; }
-
-.HA-spellcheck-error { border-bottom: 1px dashed #f00; cursor: default; }
-.HA-spellcheck-same { background-color: #cef; color: #000; }
-.HA-spellcheck-hover { background-color: #433; color: white; }
-.HA-spellcheck-fixed { border-bottom: 1px dashed #0b8; }
-.HA-spellcheck-current { background-color: #9be; color: #000; }
-.HA-spellcheck-suggestions { display: none; }
-
-#HA-spellcheck-dictionaries { display: none; }
-a:link, a:visited { color: #55e; }
+body {
+	background-color: white;
+	color: black;
+	padding: 3px;
+	margin: 0;
+}
+.htmlarea-spellcheck-error {
+	border-bottom: 1px dashed #f00;
+	cursor: default;
+}
+.htmlarea-spellcheck-same {
+	background-color: #cef;
+	color: #000;
+}
+.htmlarea-spellcheck-hover {
+	background-color: #433;
+	color: white;
+	cursor: pointer;
+}
+.htmlarea-spellcheck-fixed {
+	border-bottom: 1px dashed #0b8;
+}
+.htmlarea-spellcheck-current {
+	background-color: #9be;
+	color: #000;
+}
+a:link, a:visited {
+	color: #55e;
+}
Index: typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-check-ui.js
===================================================================
--- typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-check-ui.js	(révision 7101)
+++ typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-check-ui.js	(copie de travail)
@@ -1,429 +0,0 @@
-/***************************************************************
-*  Copyright notice
-*
-*  (c) 2003 dynarch.com. Authored by Mihai Bazon, sponsored by www.americanbible.org.
-*  (c) 2004-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
-*  All rights reserved
-*
-*  This script is part of the TYPO3 project. The TYPO3 project is
-*  free software; you can redistribute it and/or modify
-*  it under the terms of the GNU General Public License as published by
-*  the Free Software Foundation; either version 2 of the License, or
-*  (at your option) any later version.
-*
-*  The GNU General Public License can be found at
-*  http://www.gnu.org/copyleft/gpl.html.
-*  A copy is found in the textfile GPL.txt and important notices to the license
-*  from the author is found in LICENSE.txt distributed with these scripts.
-*
-*
-*  This script 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 General Public License for more details.
-*
-*  This script is a modified version of a script published under the htmlArea License.
-*  A copy of the htmlArea License may be found in the textfile HTMLAREA_LICENSE.txt.
-*
-*  This copyright notice MUST APPEAR in all copies of the script!
-***************************************************************/
-/*
- * Spell Checker Plugin for TYPO3 htmlArea RTE
- *
- * TYPO3 SVN ID: $Id$
- */
-var dialog = window.opener.HTMLArea.Dialog.SpellChecker;
-var frame = null;
-var currentElement = null;
-var wrongWords = null;
-var modified = false;
-var allWords = {};
-var fixedWords = [];
-var suggested_words = {};
-
-var to_p_dict = []; // List of words to add to personal dictionary
-var to_r_list = []; // List of words to add to replacement list
-
-function makeCleanDoc(leaveFixed) {
-	// document.getElementById("status").innerHTML = 'Please wait: rendering valid HTML';
-	var words = wrongWords.concat(fixedWords);
-	for (var i = words.length; --i >= 0;) {
-		var el = words[i];
-		if (!(leaveFixed && /HA-spellcheck-fixed/.test(el.className))) {
-			el.parentNode.insertBefore(el.firstChild, el);
-			el.parentNode.removeChild(el);
-		} else
-			el.className = "HA-spellcheck-fixed";
-	}
-	return window.opener.HTMLArea.getHTML(frame.contentWindow.document.body, false, dialog.plugin.editor);
-};
-
-function recheckClicked() {
-	document.getElementById("status").innerHTML = dialog.plugin.localize("Please wait: changing dictionary to") + ': "' + document.getElementById("f_dictionary").value + '".';
-	var field = document.getElementById("f_content");
-	field.value = makeCleanDoc(true);
-	field.form.submit();
-};
-
-function saveClicked() {
-	if (modified) {
-		dialog.plugin.editor.setHTML(makeCleanDoc(false));
-	}
-	if ((to_p_dict.length || to_r_list.length) && dialog.plugin.enablePersonalDicts) {
-		var data = {};
-		for (var i = 0;i < to_p_dict.length;i++) {
-			data['to_p_dict[' + i + ']'] = to_p_dict[i];
-		}
-		for (var i = 0;i < to_r_list.length;i++) {
-			data['to_r_list[' + i + '][0]'] = to_r_list[i][0];
-			data['to_r_list[' + i + '][1]'] = to_r_list[i][1];
-		}
-		data['cmd'] = 'learn';
-		data['enablePersonalDicts'] = dialog.plugin.enablePersonalDicts;
-		data['userUid'] = dialog.plugin.userUid;
-		data['dictionary'] = dialog.plugin.contentISOLanguage;
-		data['pspell_charset'] = dialog.plugin.contentCharset;
-		data['pspell_mode'] = dialog.plugin.spellCheckerMode;
-		window.opener.HTMLArea._postback(dialog.plugin.pageTSconfiguration.path, data);
-	}
-	window.close();
-	return false;
-};
-
-function cancelClicked() {
-	var ok = true;
-	if (modified) {
-		ok = confirm(dialog.plugin.localize("QUIT_CONFIRMATION"));
-	}
-	if (ok) {
-		dialog.close();
-	}
-	return false;
-};
-
-function replaceWord(el) {
-	var replacement = document.getElementById("v_replacement").value;
-	var this_word_modified = (el.innerHTML != replacement);
-	if (this_word_modified)
-		modified = true;
-	if (el) {
-		el.className = el.className.replace(/\s*HA-spellcheck-(hover|fixed)\s*/g, " ");
-	}
-	el.className += " HA-spellcheck-fixed";
-	el.__msh_fixed = true;
-	if (!this_word_modified) {
-		return false;
-	}
-	to_r_list.push([el.innerHTML, replacement]);
-	el.innerHTML = replacement;
-};
-
-function replaceClicked() {
-	replaceWord(currentElement);
-	var start = currentElement.__msh_id;
-	var index = start;
-	do {
-		++index;
-		if (index == wrongWords.length) index = 0;
-	} while((index != start) && wrongWords[index].__msh_fixed);
-	if (index == start) {
-		index = 0;
-		alert(dialog.plugin.localize("Finished list of mispelled words"));
-	}
-	wrongWords[index].__msh_wordClicked(true);
-	return false;
-};
-
-function revertClicked() {
-	document.getElementById("v_replacement").value = currentElement.__msh_origWord;
-	replaceWord(currentElement);
-	currentElement.className = "HA-spellcheck-error HA-spellcheck-current";
-	return false;
-};
-
-function replaceAllClicked() {
-	var replacement = document.getElementById("v_replacement").value;
-	var ok = true;
-	var spans = allWords[currentElement.__msh_origWord];
-	if (spans.length == 0) {
-		alert("An impossible condition just happened.  Call FBI.  ;-)");
-	} else if (spans.length == 1) {
-		replaceClicked();
-		return false;
-	}
-	/*
-	var message = "The word \"" + currentElement.__msh_origWord + "\" occurs " + spans.length + " times.\n";
-	if (replacement == currentElement.__msh_origWord) {
-		ok = confirm(message + "Ignore all occurrences?");
-	} else {
-		ok = confirm(message + "Replace all occurrences with \"" + replacement + "\"?");
-	}
-	*/
-	if (ok) {
-		for (var i = 0; i < spans.length; ++i) {
-			if (spans[i] != currentElement) {
-				replaceWord(spans[i]);
-			}
-		}
-		// replace current element the last, so that we jump to the next word ;-)
-		replaceClicked();
-	}
-	return false;
-};
-
-function ignoreClicked() {
-	document.getElementById("v_replacement").value = currentElement.__msh_origWord;
-	replaceClicked();
-	return false;
-};
-
-function ignoreAllClicked() {
-	document.getElementById("v_replacement").value = currentElement.__msh_origWord;
-	replaceAllClicked();
-	return false;
-};
-
-function learnClicked() {
-	to_p_dict.push(currentElement.__msh_origWord);
-	return ignoreAllClicked();
-};
-
-function initDocument() {
-	dialog.initialize();
-	var plugin = dialog.plugin;
-	var editor = plugin.editor;
-
-	modified = false;
-	document.title = dialog.plugin.localize("Spell Checker");
-	document.getElementById("spellcheck_form").action = plugin.pageTSconfiguration.path;
-	frame = document.getElementById("i_framecontent");
-	var field = document.getElementById("f_content");
-	field.value = HTMLArea.getHTML(editor._doc.body, false, editor);
-	document.getElementById("f_init").value = "0";
-	document.getElementById("f_dictionary").value = plugin.defaultDictionary ? plugin.defaultDictionary : plugin.contentISOLanguage;
-	document.getElementById("f_charset").value = plugin.contentCharset;
-	document.getElementById("f_pspell_mode").value = plugin.spellCheckerMode;
-	document.getElementById("f_user_uid").value = plugin.userUid;
-	document.getElementById("f_personal_dicts").value = plugin.enablePersonalDicts;
-	document.getElementById("f_show_dictionaries").value = plugin.showDictionaries;
-	document.getElementById("f_restrict_to_dictionaries").value = plugin.restrictToDictionaries;
-	field.form.submit();
-		// assign some global event handlers
-	var select = document.getElementById("v_suggestions");
-	select.onchange = function() {
-		document.getElementById("v_replacement").value = this.value;
-	};
-	HTMLArea._addEvent(select, "dblclick", replaceClicked);
-
-	document.getElementById("b_replace").onclick = replaceClicked;
-	if (plugin.enablePersonalDicts) document.getElementById("b_learn").onclick = learnClicked;
-		else document.getElementById("b_learn").style.display = 'none';
-	document.getElementById("b_replall").onclick = replaceAllClicked;
-	document.getElementById("b_ignore").onclick = ignoreClicked;
-	document.getElementById("b_ignall").onclick = ignoreAllClicked;
-	document.getElementById("b_recheck").onclick = recheckClicked;
-	document.getElementById("b_revert").onclick = revertClicked;
-	document.getElementById("b_info").onclick = displayInfo;
-
-	document.getElementById("b_ok").onclick = saveClicked;
-	document.getElementById("b_cancel").onclick = cancelClicked;
-
-	select = document.getElementById("v_dictionaries");
-	select.onchange = function() {
-		document.getElementById("f_dictionary").value = this.value;
-	};
-};
-
-function getAbsolutePos(el) {
-	var r = { x: el.offsetLeft, y: el.offsetTop };
-	if (el.offsetParent) {
-		var tmp = getAbsolutePos(el.offsetParent);
-		r.x += tmp.x;
-		r.y += tmp.y;
-	}
-	return r;
-};
-
-function wordClicked(scroll) {
-	var self = this;
-	if (scroll) (function() {
-		var pos = getAbsolutePos(self);
-		var ws = { x: frame.offsetWidth - 4,
-			   y: frame.offsetHeight - 4 };
-		var wp = { x: frame.contentWindow.document.body.scrollLeft,
-			   y: frame.contentWindow.document.body.scrollTop };
-		pos.x -= Math.round(ws.x/2);
-		if (pos.x < 0) pos.x = 0;
-		pos.y -= Math.round(ws.y/2);
-		if (pos.y < 0) pos.y = 0;
-		frame.contentWindow.scrollTo(pos.x, pos.y);
-	})();
-	if (currentElement) {
-		var a = allWords[currentElement.__msh_origWord];
-		currentElement.className = currentElement.className.replace(/\s*HA-spellcheck-current\s*/g, " ");
-		for (var i = 0; i < a.length; ++i) {
-			var el = a[i];
-			if (el != currentElement) {
-				el.className = el.className.replace(/\s*HA-spellcheck-same\s*/g, " ");
-			}
-		}
-	}
-	currentElement = this;
-	this.className += " HA-spellcheck-current";
-	var a = allWords[currentElement.__msh_origWord];
-	for (var i = 0; i < a.length; ++i) {
-		var el = a[i];
-		if (el != currentElement) {
-			el.className += " HA-spellcheck-same";
-		}
-	}
-	// document.getElementById("b_replall").disabled = (a.length <= 1);
-	// document.getElementById("b_ignall").disabled = (a.length <= 1);
-	var txt;
-	var txt2;
-	if (a.length == 1) {
-		txt = dialog.plugin.localize("One occurrence");
-		txt2 = dialog.plugin.localize("was found.");
-	} else if (a.length == 2) {
-		txt = dialog.plugin.localize("Two occurrences");
-		txt2 = dialog.plugin.localize("were found.");
-	} else {
-		txt = a.length + " " + dialog.plugin.localize("occurrences");
-		txt2 = dialog.plugin.localize("were found.");
-	}
-	var suggestions = suggested_words[this.__msh_origWord];
-	if (suggestions) suggestions = suggestions.split(/,/);
-		else suggestions = [];
-	var select = document.getElementById("v_suggestions");
-	document.getElementById("statusbar").innerHTML = txt + " " + dialog.plugin.localize("of the word") +
-		' "<b>' + currentElement.__msh_origWord + '</b>"' + " " + txt2;
-	for (var i = select.length; --i >= 0;) {
-		select.remove(i);
-	}
-	for (var i = 0; i < suggestions.length; ++i) {
-		var txt = suggestions[i];
-		var option = document.createElement("option");
-		option.value = txt;
-		option.appendChild(document.createTextNode(txt));
-		select.appendChild(option);
-	}
-	document.getElementById("v_currentWord").innerHTML = this.__msh_origWord;
-	if (suggestions.length > 0) {
-		select.selectedIndex = 0;
-		select.onchange();
-	} else {
-		document.getElementById("v_replacement").value = this.innerHTML;
-	}
-	select.style.display = "none";
-	select.style.display = "inline";
-	return false;
-};
-
-function wordMouseOver() {
-	this.className += " HA-spellcheck-hover";
-};
-
-function wordMouseOut() {
-	this.className = this.className.replace(/\s*HA-spellcheck-hover\s*/g, " ");
-};
-
-function displayInfo() {
-	var info = frame.contentWindow.spellcheck_info;
-	if (!info)
-		alert(dialog.plugin.localize("No information available"));
-	else {
-		var txt = dialog.plugin.localize("Document information") + "\n" ;
-		for (var i in info) {
-			txt += "\n" + dialog.plugin.localize(i) + " : " + info[i];
-		}
-		txt += " " + dialog.plugin.localize("seconds");
-		alert(txt);
-	}
-	return false;
-};
-
-function finishedSpellChecking() {
-	// initialization of global variables
-	currentElement = null;
-	wrongWords = null;
-	allWords = {};
-	fixedWords = [];
-	suggested_words = frame.contentWindow.suggested_words;
-
-	document.getElementById("status").innerHTML = dialog.plugin.localize("HTMLArea Spell Checker");
-	var doc = frame.contentWindow.document;
-	var spans = doc.getElementsByTagName("span");
-	var sps = [];
-	var id = 0;
-	for (var i = 0; i < spans.length; ++i) {
-		var el = spans[i];
-		if (/HA-spellcheck-error/.test(el.className)) {
-			sps.push(el);
-			el.__msh_wordClicked = wordClicked;
-			el.onclick = function(ev) {
-				ev || (ev = window.event);
-				ev && HTMLArea._stopEvent(ev);
-				return this.__msh_wordClicked(false);
-			};
-			el.onmouseover = wordMouseOver;
-			el.onmouseout = wordMouseOut;
-			el.__msh_id = id++;
-			var txt = (el.__msh_origWord = el.firstChild.data);
-			el.__msh_fixed = false;
-			if (typeof allWords[txt] == "undefined") {
-				allWords[txt] = [el];
-			} else {
-				allWords[txt].push(el);
-			}
-		} else if (/HA-spellcheck-fixed/.test(el.className)) {
-			fixedWords.push(el);
-		}
-	}
-	wrongWords = sps;
-	if (sps.length == 0) {
-		if (!modified) {
-			alert(dialog.plugin.localize("NO_ERRORS_CLOSING"));
-			window.close();
-		} else {
-			alert(dialog.plugin.localize("NO_ERRORS"));
-		}
-		return false;
-	}
-	(currentElement = sps[0]).__msh_wordClicked(true);
-	var as = doc.getElementsByTagName("a");
-	for (var i = as.length; --i >= 0;) {
-		var a = as[i];
-		a.onclick = function() {
-			if (confirm(dialog.plugin.localize("CONFIRM_LINK_CLICK") + ":\n" +
-				    this.href + "\n" + dialog.plugin.localize("I will open it in a new page."))) {
-				window.open(this.href);
-			}
-			return false;
-		};
-	}
-	var dicts = doc.getElementById("HA-spellcheck-dictionaries");
-	if (dicts) {
-		dicts.parentNode.removeChild(dicts);
-		dicts = dicts.innerHTML.split(/,/);
-		var select = document.getElementById("v_dictionaries");
-		for (var i = select.length; --i >= 0;) {
-			select.remove(i);
-		}
-		var selectedOptionIndex = 0;
-		for (var i = 0; i < dicts.length; ++i) {
-			var txt = dicts[i];
-			var option = document.createElement("option");
-			if (/^@(.*)$/.test(txt)) {
-				txt = RegExp.$1;
-				selectedOptionIndex = i;
-				if (HTMLArea.is_ie) option.selected = true;
-				document.getElementById("f_dictionary").value = txt;
-			}
-			option.value = txt;
-			option.appendChild(document.createTextNode(txt));
-			select.appendChild(option);
-		}
-		select.selectedIndex = selectedOptionIndex;
-	}
-};
-
Index: typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-checker.js
===================================================================
--- typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-checker.js	(révision 7101)
+++ typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-checker.js	(copie de travail)
@@ -33,54 +33,64 @@
  * TYPO3 SVN ID: $Id$
  */
 SpellChecker = HTMLArea.Plugin.extend({
-
-	constructor : function(editor, pluginName) {
+	constructor: function(editor, pluginName) {
 		this.base(editor, pluginName);
 	},
-
 	/*
 	 * This function gets called by the class constructor
 	 */
-	configurePlugin : function(editor) {
-
+	configurePlugin: function(editor) {
 		this.pageTSconfiguration = this.editorConfiguration.buttons.spellcheck;
 		this.contentISOLanguage = this.pageTSconfiguration.contentISOLanguage;
 		this.contentCharset = this.pageTSconfiguration.contentCharset;
 		this.spellCheckerMode = this.pageTSconfiguration.spellCheckerMode;
 		this.enablePersonalDicts = this.pageTSconfiguration.enablePersonalDicts;
 		this.userUid = this.editorConfiguration.userUid;
-		this.defaultDictionary = (this.pageTSconfiguration.dictionaries && this.pageTSconfiguration.dictionaries[this.contentISOLanguage] && this.pageTSconfiguration.dictionaries[this.contentISOLanguage].defaultValue) ? this.pageTSconfiguration.dictionaries[this.contentISOLanguage].defaultValue : "";
-		this.showDictionaries = (this.pageTSconfiguration.dictionaries && this.pageTSconfiguration.dictionaries.items) ? this.pageTSconfiguration.dictionaries.items : "";
-		this.restrictToDictionaries = (this.pageTSconfiguration.dictionaries && this.pageTSconfiguration.dictionaries.restrictToItems) ? this.pageTSconfiguration.dictionaries.restrictToItems : "";
-
+		this.defaultDictionary = (this.pageTSconfiguration.dictionaries && this.pageTSconfiguration.dictionaries[this.contentISOLanguage] && this.pageTSconfiguration.dictionaries[this.contentISOLanguage].defaultValue) ? this.pageTSconfiguration.dictionaries[this.contentISOLanguage].defaultValue : '';
+		this.showDictionaries = (this.pageTSconfiguration.dictionaries && this.pageTSconfiguration.dictionaries.items) ? this.pageTSconfiguration.dictionaries.items : '';
+		this.restrictToDictionaries = (this.pageTSconfiguration.dictionaries && this.pageTSconfiguration.dictionaries.restrictToItems) ? this.pageTSconfiguration.dictionaries.restrictToItems : '';
 		/*
 		 * Registering plugin "About" information
 		 */
 		var pluginInformation = {
-			version		: "2.2",
-			developer	: "Mihai Bazon & Stanislas Rolland",
-			developerUrl	: "http://dynarch.com/mishoo/",
-			copyrightOwner	: "Mihai Bazon & Stanislas Rolland",
-			sponsor		: "American Bible Society & SJBR",
-			sponsorUrl	: "http://www.sjbr.ca/",
-			license		: "GPL"
+			version		: '3.0',
+			developer	: 'Mihai Bazon & Stanislas Rolland',
+			developerUrl	: 'http://www.sjbr.ca/',
+			copyrightOwner	: 'Mihai Bazon & Stanislas Rolland',
+			sponsor		: 'American Bible Society & SJBR',
+			sponsorUrl	: 'http://www.sjbr.ca/',
+			license		: 'GPL'
 		};
 		this.registerPluginInformation(pluginInformation);
-
 		/*
 		 * Registering the button
 		 */
-		var buttonId = "SpellCheck";
+		var buttonId = 'SpellCheck';
 		var buttonConfiguration = {
 			id		: buttonId,
-			tooltip		: this.localize("SC-spell-check"),
-			action		: "onButtonPress",
+			tooltip		: this.localize('SC-spell-check'),
+			action		: 'onButtonPress',
 			dialog		: true
 		};
 		this.registerButton(buttonConfiguration);
 	},
-
 	/*
+	 * Sets of default configuration values for dialogue form fields
+	 */
+	configDefaults: {
+		combo: {
+			editable: true,
+			typeAhead: true,
+			triggerAction: 'all',
+			forceSelection: true,
+			mode: 'local',
+			valueField: 'value',
+			displayField: 'text',
+			helpIcon: true,
+			tpl: '<tpl for="."><div ext:qtip="{value}" style="text-align:left;font-size:11px;" class="x-combo-list-item">{text}</div></tpl>'
+		}
+	},
+	/*
 	 * This function gets called when the button was pressed.
 	 *
 	 * @param	object		editor: the editor instance
@@ -88,17 +98,701 @@
 	 *
 	 * @return	boolean		false if action is completed
 	 */
-	onButtonPress : function (editor, id, target) {
+	onButtonPress: function (editor, id, target) {
 			// Could be a button or its hotkey
 		var buttonId = this.translateHotKey(id);
 		buttonId = buttonId ? buttonId : id;
-		switch (buttonId) {
-			case "SpellCheck":
-				var charset = (this.contentCharset.toLowerCase() == 'iso-8859-1') ? "-iso-8859-1" : "";
-				this.dialog = this.openDialog(buttonId, this.makeUrlFromPopupName("spell-check-ui" + charset), null, null, {width:710, height:600});
-				break;
+			// Open dialogue window
+		this.openDialogue(
+			buttonId,
+			'Spell Checker',
+			this.getWindowDimensions(
+				{
+					width: 710,
+					height: 600
+				},
+				buttonId
+			)
+		);
+		return false;
+	},
+	/*
+	 * Open the dialogue window
+	 *
+	 * @param	string		buttonId: the button id
+	 * @param	string		title: the window title
+	 * @param	object		dimensions: the opening dimensions of the window
+	 *
+	 * @return	void
+	 */
+	openDialogue: function (buttonId, title, dimensions) {
+		this.dialog = new Ext.Window({
+			title: this.localize(title),
+			cls: 'htmlarea-window',
+			bodyCssClass: 'spell-check',
+			border: false,
+			width: dimensions.width,
+			height: 'auto',
+				// As of ExtJS 3.1, JS error with IE when the window is resizable
+			resizable: !Ext.isIE,
+			iconCls: buttonId,
+			listeners: {
+				afterrender: {
+					fn: this.onWindowAfterRender,
+					scope: this
+				},
+				resize: {
+					fn: this.onWindowResize
+				},
+				close: {
+					fn: this.onClose,
+					scope: this
+				}
+			},
+			items: [{
+						// The hidden form
+					xtype: 'form',
+					method: 'POST',
+					itemId: 'spell-check-form',
+					url: this.pageTSconfiguration.path,
+					hidden: true,
+					standardSubmit: true,
+					items: [{
+							xtype: 'hidden',
+							name: 'editorId',
+							value: this.editor.editorId
+						},{
+							xtype: 'hidden',
+							itemId: 'content',
+							name: 'content',
+							value: this.editor.getHTML()
+						},{
+							xtype: 'hidden',
+							itemId: 'dictionary',
+							name: 'dictionary',
+							value: this.defaultDictionary ? this.defaultDictionary : this.contentISOLanguage
+						},{
+							xtype: 'hidden',
+							name: 'pspell_charset',
+							value: this.contentCharset
+						},{
+							xtype: 'hidden',
+							name: 'pspell_mode',
+							value: this.spellCheckerMode
+						},{
+							xtype: 'hidden',
+							name: 'userUid',
+							value: this.userUid
+						},{
+							xtype: 'hidden',
+							name:'enablePersonalDicts',
+							value: this.enablePersonalDicts
+						},{
+							xtype: 'hidden',
+							name:'showDictionaries',
+							value: this.showDictionaries
+						},{
+							xtype: 'hidden',
+							name:'restrictToDictionaries',
+							value: this.restrictToDictionaries
+						}
+					]
+				},{
+						// The iframe
+					xtype: 'box',
+					itemId: 'spell-check-iframe',
+					width: dimensions.width - 225,
+					autoEl: {
+						name: 'contentframe',
+						tag: 'iframe',
+						cls: 'contentframe',
+						src: Ext.isGecko ? 'javascript:void(0);' : (Ext.isOpera ? _typo3_host_url : '') + _editor_url + 'popups/blank.html'
+					}
+				},{
+						// The original word
+					xtype: 'fieldset',
+					title: this.localize('Original word'),
+					cls: 'controls',
+					labelWidth: 0,
+					defaults: {
+						hideLabel: true,
+						disabled: true,
+						minWidth: 160
+					},
+					items: [{
+							xtype: 'textfield',
+							itemId: 'word',
+							disabled: false
+						},
+						this.buildButtonConfig('Revert', this.onRevertClick)
+					]
+				},{
+						// The replacement word and actions
+					xtype: 'fieldset',
+					title: this.localize('Replacement'),
+					cls: 'controls',
+					defaultType: 'button',
+					labelWidth: 0,
+					defaults: {
+						hideLabel: true,
+						disabled: true,
+						minWidth: 160
+					},
+					items: [{
+							xtype: 'textfield',
+							disabled: false,
+							width: 160,
+							itemId: 'replacement'
+						},{
+							itemId: 'replace',
+							text: this.localize('Replace'),
+							listeners: {
+								click: {
+									fn: this.onReplaceClick,
+									scope: this
+								}
+							}
+						},{
+							itemId: 'replaceAll',
+							text: this.localize('Replace all'),
+							listeners: {
+								click: {
+									fn: this.onReplaceAllClick,
+									scope: this
+								}
+							}
+						},{
+							itemId: 'ignore',
+							text: this.localize('Ignore'),
+							listeners: {
+								click: {
+									fn: this.onIgnoreClick,
+									scope: this
+								}
+							}
+						},{
+							itemId: 'ignoreAll',
+							text: this.localize('Ignore all'),
+							listeners: {
+								click: {
+									fn: this.onIgnoreAllClick,
+									scope: this
+								}
+							}
+						},{
+							itemId: 'learn',
+							text: this.localize('Learn'),
+							hidden: !this.enablePersonalDicts,
+							listeners: {
+								click: {
+									fn: this.onLearnClick,
+									scope: this
+								}
+							}
+						}
+					]
+				},{
+						// The suggestions
+					xtype: 'fieldset',
+					title: this.localize('Suggestions'),
+					cls: 'controls',
+					labelWidth: 0,
+					defaults: {
+						hideLabel: true,
+						minWidth: 160
+					},
+					items: [
+						Ext.apply({
+							xtype: 'combo',
+							itemId: 'suggestions',
+							store: new Ext.data.ArrayStore({
+								autoDestroy:  true,
+								fields: [{name: 'text'}, {name: 'value'}],
+								data: []
+							}),
+							listeners: {
+								select: {
+									fn: this.onSuggestionSelect,
+									scope: this
+								}
+							}
+						}, this.configDefaults['combo'])
+					]
+				},{
+						// The dictionaries
+					xtype: 'fieldset',
+					title: this.localize('Dictionary'),
+					cls: 'controls',
+					defaultType: 'button',
+					labelWidth: 0,
+					defaults: {
+						hideLabel: true,
+						disabled: true,
+						minWidth: 160
+					},
+					items: [
+						Ext.apply({
+							xtype: 'combo',
+							itemId: 'dictionaries',
+							disabled: false,
+							store: new Ext.data.ArrayStore({
+								autoDestroy:  true,
+								fields: [{name: 'text'}, {name: 'value'}],
+								data: []
+							}),
+							listeners: {
+								select: {
+									fn: this.onDictionarySelect,
+									scope: this
+								}
+							}
+						}, this.configDefaults['combo']),
+						{
+							itemId: 'recheck',
+							text: this.localize('Re-check'),
+							listeners: {
+								click: {
+									fn: this.onRecheckClick,
+									scope: this
+								}
+							}
+						}
+					]
+				}
+			],
+			bbar: new Ext.ux.StatusBar({
+				id: this.editor.editorId + '-spell-check-status',
+				defaultText: this.localize('statusBarReady'),
+				defaultIconCls: 'status-ready',
+				text: this.localize('Please wait. Calling spell checker.'),
+				iconCls: 'status-wait',
+				defaults: {
+					minWidth: 100,
+					disabled: true
+				},
+				items: [
+					this.buildButtonConfig('OK', this.onOK),
+					this.buildButtonConfig('Info', this.onInfoClick),
+					this.buildButtonConfig('Cancel', this.onCancel)
+				]
+			})
+		});
+		this.show();
+	},
+	/*
+	 * Handler invoked after the window has been rendered
+	 */
+	onWindowAfterRender: function () {
+			// True when some word has been modified
+		this.modified = false;
+			// Array of words to add to the personal dictionary
+		this.addToPersonalDictionary = [];
+			// List of word pairs to add to replacement list of the personal dictionary
+		this.addToReplacementList = [];
+			// Initial submit
+		this.dialog.getComponent('spell-check-form').getForm().getEl().set({
+			target: 'contentframe',
+			'accept-charset': this.contentCharset.toUpperCase()
+		});
+		this.dialog.getComponent('spell-check-form').getForm().submit();
+	},
+	/*
+	 * Handler invoked after the window is resized
+	 */
+	onWindowResize: function (window, width, height) {
+		var frame = window.getComponent('spell-check-iframe').getEl();
+		if (frame) {
+			frame.setSize(width - 225, height - 75);
 		}
+	},
+	/*
+	 * Handler invoked when the OK button is pressed
+	 */
+	onOK: function () {
+		if (this.modified) {
+			this.editor.setHTML(this.cleanDocument(false));
+		}
+			// Post additions to the Aspell personal dictionary
+		if ((this.addToPersonalDictionary.length || this.addToReplacementList.length) && this.enablePersonalDicts) {
+			var data = {
+				cmd: 'learn',
+				enablePersonalDicts: this.enablePersonalDicts,
+				userUid: this.userUid,
+				dictionary: this.contentISOLanguage,
+				pspell_charset: this.contentCharset,
+				pspell_mode: this.spellCheckerMode
+			};
+			Ext.each(this.addToPersonalDictionary, function (word, index) {
+				data['to_p_dict[' + index + ']'] = word;
+			});
+			Ext.each(this.addToReplacementList, function (replacement, index) {
+				data['to_r_list[' + index + '][0]'] = replacement[0];
+				data['to_r_list[' + index + '][1]'] = replacement[1];
+			});
+			HTMLArea._postback(this.pageTSconfiguration.path, data);
+		}
+		this.close();
 		return false;
+	},
+	/*
+	 * Handler invoked when the Cancel button is pressed
+	 */
+	onCancel: function () {
+		if (this.modified) {
+			Ext.MessageBox.confirm('', this.localize('QUIT_CONFIRMATION'), function (button) {
+				if (button == 'yes') {
+					this.close();
+				}
+			}, this);
+			return false;
+		} else {
+			return this.base();
+		}
+	},
+	/*
+	 * Clean away span elements from the text before leaving or re-submitting
+	 *
+	 * @param	boolean		leaveFixed: if true, span elements of corrected words will be left in the text (re-submit case)
+	 *
+	 * @return	string		cleaned-up html
+	 */
+	cleanDocument: function (leaveFixed) {
+		var iframeDocument = this.dialog.getComponent('spell-check-iframe').getEl().dom.contentWindow.document;
+		Ext.each(this.misspelledWords.concat(this.correctedWords), function (element) {
+			element.onclick = null;
+			element.onmouseover = null;
+			element.onmouseout = null;
+			if (!leaveFixed || !HTMLArea._hasClass(element, 'htmlarea-spellcheck-fixed')) {
+				element.parentNode.insertBefore(element.firstChild, element);
+				element.parentNode.removeChild(element);
+			} else {
+				HTMLArea._removeClass(element, 'htmlarea-spellcheck-error');
+				HTMLArea._removeClass(element, 'htmlarea-spellcheck-same');
+				HTMLArea._removeClass(element, 'htmlarea-spellcheck-current');
+			}
+		}, this);
+			// Cleanup event handlers on links
+		Ext.each(iframeDocument.getElementsByTagName('a'), function (link) {
+			link.onclick = null;
+		}, this);
+		return HTMLArea.getHTML(iframeDocument.body, false, this.editor);
+	},
+	/*
+	 * Handler invoked when the response from the server has finished loading
+	 */
+	spellCheckComplete: function () {
+		var contentWindow = this.dialog.getComponent('spell-check-iframe').getEl().dom.contentWindow;
+		this.currentElement = null;
+			// Array of misspelled words
+		this.misspelledWords = [];
+			// Array of corrected words
+		this.correctedWords = [];
+			// Object containing array of occurrences of each misspelled word
+		this.allWords = {};
+			// Suggested words
+		this.suggestedWords = contentWindow.suggestedWords;
+			// Set status
+		Ext.getCmp(this.editor.editorId + '-spell-check-status').setStatus({
+		    text: this.localize('statusBarReady'),
+		    iconCls: 'status-ready',
+		    clear: false
+		});
+			// Process all misspelled words
+		var id = 0;
+		var self = this;
+		Ext.each(contentWindow.document.getElementsByTagName('span'), function (span) {
+			if (HTMLArea._hasClass(span, 'htmlarea-spellcheck-error')) {
+				this.misspelledWords.push(span);
+				span.onclick = function (event) { self.setCurrentWord(this, false); };
+				span.onmouseover = function (event) { HTMLArea._addClass(this, 'htmlarea-spellcheck-hover'); };
+				span.onmouseout = function (event) { HTMLArea._removeClass(this, 'htmlarea-spellcheck-hover'); };
+				span.htmlareaId = id++;
+				span.htmlareaOriginalWord = span.firstChild.data;
+				span.htmlareaFixed = false;
+				if (typeof(this.allWords[span.htmlareaOriginalWord]) == 'undefined') {
+					this.allWords[span.htmlareaOriginalWord] = [];
+				}
+				this.allWords[span.htmlareaOriginalWord].push(span);
+			} else if (HTMLArea._hasClass(span, 'htmlarea-spellcheck-fixed')) {
+				this.correctedWords.push(span);
+			}
+		}, this);
+			// Do not open links in the iframe
+		Ext.each(contentWindow.document.getElementsByTagName('a'), function (link) {
+			link.onclick = function (event) { return false; };
+		}, this);
+			// Enable buttons
+		Ext.each(this.dialog.findByType('button'), function (button) {
+			button.setDisabled(false);
+		});
+		Ext.each(Ext.getCmp(this.editor.editorId + '-spell-check-status').findByType('button'), function (button) {
+			button.setDisabled(false);
+		});
+		if (this.misspelledWords.length) {
+				// Set current element to first misspelled word
+			this.currentElement = this.misspelledWords[0];
+			this.setCurrentWord(this.currentElement, true);
+				// Populate the dictionaries combo
+			var dictionaries = contentWindow.dictionaries.split(/,/);
+			if (dictionaries.length) {
+				var select = this.dialog.find('itemId', 'dictionaries')[0];
+				var store = select.getStore();
+				store.removeAll();
+				Ext.each(dictionaries, function (dictionary) {
+					store.add(new store.recordType({
+						text: dictionary,
+						value: dictionary
+					}));
+				});
+				select.setValue(contentWindow.selectedDictionary);
+				var selectedIndex = store.find('value', contentWindow.selectedDictionary);
+				select.fireEvent('select', select, store.getAt(selectedIndex), selectedIndex);
+			}
+		} else {
+			if (!this.modified) {
+				Ext.MessageBox.alert('', this.localize('NO_ERRORS_CLOSING'));
+				this.onOK();
+			} else {
+				Ext.MessageBox.alert('', this.localize('NO_ERRORS'));
+			}
+			return false;
+		}
+	},
+	/*
+	 * Get absolute position of an element inside the iframe
+	 */
+	getAbsolutePosition: function (element) {
+		var position = {
+			x: element.offsetLeft,
+			y: element.offsetTop
+		};
+		if (element.offsetParent) {
+			var tmp = this.getAbsolutePosition(element.offsetParent);
+			position.x += tmp.x;
+			position.y += tmp.y;
+		}
+		return position;
+	},
+	/*
+	 * Update current word
+	 */
+	setCurrentWord: function (element, scroll) {
+			// Scroll element into view
+		if (scroll) {
+			var frame = this.dialog.getComponent('spell-check-iframe').getEl().dom;
+			var position = this.getAbsolutePosition(element);
+			var frameSize = {
+				x: frame.offsetWidth - 4,
+				y: frame.offsetHeight - 4
+			};
+			position.x -= Math.round(frameSize.x/2);
+			if (position.x < 0) {
+				position.x = 0;
+			}
+			position.y -= Math.round(frameSize.y/2);
+			if (position.y < 0) {
+				position.y = 0;
+			}
+			frame.contentWindow.scrollTo(position.x, position.y);
+		}
+			// De-highlight all occurrences of current word
+		if (this.currentElement) {
+			HTMLArea._removeClass(this.currentElement, 'htmlarea-spellcheck-current');
+			Ext.each(this.allWords[this.currentElement.htmlareaOriginalWord], function (word) {
+				HTMLArea._removeClass(word, 'htmlarea-spellcheck-same');
+			});
+		}
+			// Highlight all occurrences of new current word
+		this.currentElement = element;
+		HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-current');
+		var occurrences = this.allWords[this.currentElement.htmlareaOriginalWord];
+		Ext.each(occurrences, function (word) {
+			if (word != this.currentElement) {
+				HTMLArea._addClass(word, 'htmlarea-spellcheck-same');
+			}
+		}, this);
+		this.dialog.find('itemId', 'replaceAll')[0].setDisabled(occurrences.length <= 1);
+		this.dialog.find('itemId', 'ignoreAll')[0].setDisabled(occurrences.length <= 1);
+			// Display status
+		var txt;
+		var txt2;
+		if (occurrences.length == 1) {
+			txt = this.localize('One occurrence');
+			txt2 = this.localize('was found.');
+		} else if (occurrences.length == 2) {
+			txt = this.localize('Two occurrences');
+			txt2 = this.localize('were found.');
+		} else {
+			txt = occurrences.length + ' ' + this.localize('occurrences');
+			txt2 = this.localize('were found.');
+		}
+		Ext.getCmp(this.editor.editorId + '-spell-check-status').setStatus({
+			text: txt + ' ' + this.localize('of the word') + ' "<b>' + this.currentElement.htmlareaOriginalWord + '</b>" ' + txt2,
+			iconCls: 'status-info',
+			clear: false
+		});
+			// Update suggestions
+		var suggestions = this.suggestedWords[this.currentElement.htmlareaOriginalWord];
+		if (suggestions) {
+			suggestions = suggestions.split(/,/);
+		} else {
+			suggestions = [];
+		}
+		var select = this.dialog.find('itemId', 'suggestions')[0];
+		var store = select.getStore();
+		store.removeAll();
+		Ext.each(suggestions, function (suggestion) {
+			store.add(new store.recordType({
+				text: suggestion,
+				value: suggestion
+			}));
+		});
+			// Update the current word
+		this.dialog.find('itemId', 'word')[0].setValue(this.currentElement.htmlareaOriginalWord);
+		if (suggestions.length > 0) {
+			select.setValue(store.getAt(0).get('value'));
+			select.fireEvent('select', select, store.getAt(0), 0);
+		} else {
+			this.dialog.find('itemId', 'replacement')[0].setVvalue(this.currentElement.innerHTML);
+		}
+		return false;
+	},
+	/*
+	 * Handler invoked when the mouse moves over a misspelled word
+	 */
+	onWordMouseOver: function (event, element) {
+		HTMLArea._addClass(element, 'htmlarea-spellcheck-hover');
+	},
+	/*
+	 * Handler invoked when the mouse moves out of a misspelled word
+	 */
+	onWordMouseOut: function (event, element) {
+		HTMLArea._removeClass(element, 'htmlarea-spellcheck-hover');
+	},
+	/*
+	 * Handler invoked when a suggestion is selected
+	 */
+	onSuggestionSelect: function (select, record, index) {
+		this.dialog.find('itemId', 'replacement')[0].setValue(record.get('value'));
+	},
+	/*
+	 * Handler invoked when a dictionary is selected
+	 */
+	onDictionarySelect: function (select, record, index) {
+		this.dialog.find('itemId', 'dictionary')[0].setValue(record.get('value'));
+	},
+	/*
+	 * Handler invoked when the Revert button is clicked
+	 */
+	onRevertClick: function () {
+		this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.htmlareaOriginalWord);
+		this.replaceWord(this.currentElement);
+		HTMLArea._removeClass(this.currentElement, 'htmlarea-spellcheck-fixed');
+		HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-error');
+		HTMLArea._addClass(this.currentElement, 'htmlarea-spellcheck-current');
+		return false;
+	},
+	/*
+	 * Replace the word contained in the element
+	 */
+	replaceWord: function (element) {
+		HTMLArea._removeClass(element, 'htmlarea-spellcheck-hover');
+		HTMLArea._addClass(element, 'htmlarea-spellcheck-fixed');
+		element.htmlareaFixed = true;
+		var replacement = this.dialog.find('itemId', 'replacement')[0].getValue();
+		if (element.innerHTML != replacement) {
+			this.addToReplacementList.push([element.innerHTML, replacement]);
+			element.innerHTML = replacement;
+			this.modified = true;
+		}
+	},
+	/*
+	 * Handler invoked when the Replace button is clicked
+	 */
+	onReplaceClick: function () {
+		this.replaceWord(this.currentElement);
+		var start = this.currentElement.htmlareaId;
+		var index = start;
+		do {
+			++index;
+			if (index == this.misspelledWords.length) {
+				index = 0;
+			}
+		} while (index != start && this.misspelledWords[index].htmlareaFixed);
+		if (index == start) {
+			index = 0;
+			Ext.MessageBox.alert('', this.localize('Finished list of mispelled words'));
+		}
+		this.setCurrentWord(this.misspelledWords[index], true);
+		return false;
+	},
+	/*
+	 * Handler invoked when the Replace all button is clicked
+	 */
+	onReplaceAllClick: function () {
+		Ext.each(this.allWords[this.currentElement.htmlareaOriginalWord], function (element) {
+			if (element != this.currentElement) {
+				this.replaceWord(element);
+			}
+		}, this);
+			// Replace current element last, so that we jump to the next word
+		return this.onReplaceClick();
+	},
+	/*
+	 * Handler invoked when the Ignore button is clicked
+	 */
+	onIgnoreClick: function () {
+		this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.htmlareaOriginalWord);
+		return this.onReplaceClick();
+	},
+	/*
+	 * Handler invoked when the Ignore all button is clicked
+	 */
+	onIgnoreAllClick: function () {
+		this.dialog.find('itemId', 'replacement')[0].setValue(this.currentElement.htmlareaOriginalWord);
+		return this.onReplaceAllClick();
+	},
+	/*
+	 * Handler invoked when the Learn button is clicked
+	 */
+	onLearnClick: function () {
+		this.addToPersonalDictionary.push(this.currentElement.htmlareaOriginalWord);
+		return this.onIgnoreAllClick();
+	},
+	/*
+	 * Handler invoked when the Re-check button is clicked
+	 */
+	onRecheckClick: function () {
+			// Disable buttons
+		Ext.each(this.dialog.findByType('button'), function (button) {
+			button.setDisabled(true);
+		});
+		Ext.each(Ext.getCmp(this.editor.editorId + '-spell-check-status').findByType('button'), function (button) {
+			button.setDisabled(true);
+		});
+		Ext.getCmp(this.editor.editorId + '-spell-check-status').setStatus({
+			text: this.localize('Please wait: changing dictionary to') + ': "' + this.dialog.find('itemId', 'dictionary')[0].getValue() + '".',
+			iconCls: 'status-wait',
+			clear: false
+		});
+		this.dialog.find('itemId', 'content')[0].setValue(this.cleanDocument(true));
+		this.dialog.getComponent('spell-check-form').getForm().submit();
+	},
+	/*
+	 * Handler invoked when the Info button is clicked
+	 */
+	onInfoClick: function () {
+		var info = this.dialog.getComponent('spell-check-iframe').getEl().dom.contentWindow.spellcheckInfo;
+		if (!info) {
+			Ext.MessageBox.alert('', this.localize('No information available'));
+		} else {
+			var txt = this.localize('Document information') + '<br />';
+			Ext.iterate(info, function (key, value) {
+				txt += '<br />' + this.localize(key) + ': ' + value;
+			}, this);
+			txt += ' ' + this.localize('seconds');
+			Ext.MessageBox.alert('', txt);
+		}
+		return false;
 	}
 });
-
Index: typo3/sysext/rtehtmlarea/htmlarea/skins/default/htmlarea.css
===================================================================
--- typo3/sysext/rtehtmlarea/htmlarea/skins/default/htmlarea.css	(révision 7101)
+++ typo3/sysext/rtehtmlarea/htmlarea/skins/default/htmlarea.css	(copie de travail)
@@ -483,56 +483,23 @@
 	border: 1px solid #A2AAB8;
 }
 /* Selectors for the SpellChecker dialogue */
-.htmlarea-spell-check .dictionaries {
-	float:right;
-	padding:2px;
+.htmlarea-window .spell-check .controls {
+	text-align: center;
+	width: 175px;
+	margin: 3px;
 }
-.htmlarea-spell-check .dictionaries #v_dictionaries {
-	width:10em;
-	margin-right:5px;
+.htmlarea-window .spell-check .controls .x-btn {
+	margin-top: 3px;
+	margin-left: 8px;
 }
-.htmlarea-spell-check #b_recheck {
-	vertical-align:middle;
-	width:12em;
+.htmlarea-window .spell-check .contentframe {
+	float: right;
+	height: 450px;
+	margin: 9px 0px;
+	background-color: #FFF;
+	color: #000;
+	border: 1px solid #A2AAB8;
 }
-.htmlarea-spell-check .status {
-	font-weight:bold;
-	padding:2px;
-}
-.htmlarea-spell-check .controls {
-	width:14em;
-	clear:right;float:left;
-	text-align:center;
-	margin:3px;
-}
-.htmlarea-spell-check .controls .sectitle {
-	font-weight:bold;
-	padding:2px 4px;
-}
-.htmlarea-spell-check .controls .secbody {
-	margin-bottom:10px;
-}
-.htmlarea-spell-check .controls #v_currentWord {
-	color:#F00;font-weight:bold;
-	margin-bottom:2px;
-}
-.htmlarea-spell-check .controls #v_replacement {
-	margin-bottom:3px;
-}
-.htmlarea-spell-check .controls #v_suggestions, .controls #v_replacement {
-	width:12em;
-}
-.htmlarea-spell-check .contentframe {
-	float:right; margin:3px;
-}
-.htmlarea-spell-check .contentframe #i_framecontent {
-	background-color:#FFF;color:#000;
-	height:450px;width:480px;
-}
-.htmlarea-spell-check .occurrences-found {
-	padding:7px 0px 0px 5px;
-	clear:both;
-}
 /* Selectors for the ContextMenu plugin */
 .htmlarea-context-menu {
 	background-color:#EFEFF4;
@@ -558,3 +525,57 @@
 	margin-bottom:0;
 	border-color:#A2AAB8;
 }
+/* Window status bar selectors */
+.htmlarea-window .status-ready {
+	padding-left: 21px !important;
+	background-repeat: no-repeat;
+	background-image: url("images/dialog-ok.png");
+	background-position: 0px 2px;
+}
+.htmlarea-window .status-info {
+	padding-left: 21px !important;
+	background-repeat: no-repeat;
+	background-image: url("images/dialog-information.png");
+	background-position: 0px 2px;
+}
+.htmlarea-window .status-wait {
+	padding-left: 45px !important;
+	background-repeat: no-repeat;
+	background-image:url("images/loading-balls.gif");
+	background-position: 0px 6px;
+}
+.x-statusbar .x-btn {
+	margin-left: 5px;
+}
+.x-statusbar .x-status-text {
+    cursor: default;
+}
+
+/* Button background positioning in window status bar*/
+.x-statusbar .x-btn-tl{
+	background-position: 0 0;
+}
+.x-statusbar .x-btn-tr{
+	background-position: -3px 0;
+}
+.x-statusbar .x-btn-tc{
+	background-position: 0 -6px;
+}
+.x-statusbar .x-btn-ml{
+	background-position: 0 -24px;
+}
+.x-statusbar .x-btn-mr{
+	background-position: -3px -24px;
+}
+.x-statusbar .x-btn-mc{
+	background-position: 0 -1096px;
+}
+.x-statusbar .x-btn-bl{
+	background-position: 0 -3px;
+}
+.x-statusbar .x-btn-br{
+	background-position: -3px -3px;
+}
+.x-statusbar .x-btn-bc{
+	background-position: 0 -15px;
+}
Index: typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/dialog-information.png
===================================================================
Impossible d'afficher : fichier considéré comme binaire.
svn:mime-type = application/octet-stream

Modification de propriétés sur typo3\sysext\rtehtmlarea\htmlarea\skins\default\images\dialog-information.png
___________________________________________________________________
Ajouté : svn:mime-type
   + application/octet-stream

Index: typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/dialog-ok.png
===================================================================
Impossible d'afficher : fichier considéré comme binaire.
svn:mime-type = application/octet-stream

Modification de propriétés sur typo3\sysext\rtehtmlarea\htmlarea\skins\default\images\dialog-ok.png
___________________________________________________________________
Ajouté : svn:mime-type
   + application/octet-stream

Index: typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/loading-balls.gif
===================================================================
Impossible d'afficher : fichier considéré comme binaire.
svn:mime-type = application/octet-stream

Modification de propriétés sur typo3\sysext\rtehtmlarea\htmlarea\skins\default\images\loading-balls.gif
___________________________________________________________________
Ajouté : svn:mime-type
   + application/octet-stream

Index: typo3/sysext/rtehtmlarea/pi1/class.tx_rtehtmlarea_pi1.php
===================================================================
--- typo3/sysext/rtehtmlarea/pi1/class.tx_rtehtmlarea_pi1.php	(révision 7101)
+++ typo3/sysext/rtehtmlarea/pi1/class.tx_rtehtmlarea_pi1.php	(copie de travail)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2003-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  (c) 2003-2010 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the Typo3 project. The Typo3 project is
@@ -112,8 +112,6 @@
 		if (empty($this->dictionary) || !in_array($this->dictionary, $dictionaryArray)) {
 			$this->dictionary = 'en';
 		}
-		$dictionaries = substr_replace($dictionaryList, '@'.$this->dictionary, strpos($dictionaryList, $this->dictionary), strlen($this->dictionary));
-
 			// Setting the pspell suggestion mode
 		$this->pspellMode = t3lib_div::_POST('pspell_mode')?t3lib_div::_POST('pspell_mode'): $this->pspellMode;
 			// Now sanitize $this->pspellMode
@@ -214,10 +212,9 @@
      PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . substr($this->dictionary, 0, 2) . '" lang="' . substr($this->dictionary, 0, 2) . '">
-<html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=' . $this->parserCharset . '" />
-<link rel="stylesheet" type="text/css" media="all" href="spell-check-style.css" />
+<link rel="stylesheet" type="text/css" media="all" href="' . (TYPO3_MODE == 'BE' ? '../' : '') . t3lib_extMgm::siteRelPath($this->extKey) . '/htmlarea/plugins/SpellChecker/spell-check-style.css" />
 <script type="text/javascript">
 /*<![CDATA[*/
 <!--
@@ -241,22 +238,24 @@
 			if ($this->pspell_is_available && !$this->forceCommandMode) {
 				pspell_clear_session ($this->pspell_link);
 			}
-			$this->result .= 'var suggested_words = {' . $this->suggestedWords . '};
+			$this->result .= 'var suggestedWords = {' . $this->suggestedWords . '};
+var dictionaries = "' . $dictionaryList . '";
+var selectedDictionary = "' . $this->dictionary . '";
 ';
 
 				// Calculating parsing and spell checkting time
 			$time = number_format(microtime(true) - $time_start, 2, ',', ' ');
 
 				// Insert spellcheck info
-			$this->result .= 'var spellcheck_info = { "Total words":"'.$this->wordCount.'","Misspelled words":"'.sizeof($this->misspelled).'","Total suggestions":"'.$this->suggestionCount.'","Total words suggested":"'.$this->suggestedWordCount.'","Spelling checked in":"'.$time.'" };
+			$this->result .= 'var spellcheckInfo = { "Total words":"'.$this->wordCount.'","Misspelled words":"'.sizeof($this->misspelled).'","Total suggestions":"'.$this->suggestionCount.'","Total words suggested":"'.$this->suggestedWordCount.'","Spelling checked in":"'.$time.'" };
 // -->
 /*]]>*/
 </script>
 </head>
 ';
-			$this->result .= '<body onload="window.parent.finishedSpellChecking();">';
+			$this->result .= '<body onload="window.parent.RTEarea[\'' . t3lib_div::_POST('editorId') . '\'].editor.getPlugin(\'SpellChecker\').spellCheckComplete();">';
 			$this->result .= preg_replace('/'.preg_quote('<?xml').'.*'.preg_quote('?>').'['.preg_quote(chr(10).chr(13).chr(32)).']*/'.(($this->parserCharset == 'utf-8')?'u':''), '', $this->text);
-			$this->result .= '<div id="HA-spellcheck-dictionaries">'.$dictionaries.'</div>';
+			$this->result .= '<div style="display: none;">'.$dictionaries.'</div>';
 
 				// Closing
 			$this->result .= '
@@ -355,7 +354,7 @@
 							unset($suggest);
 						}
 						if( !in_array($word, $incurrent) ) {
-							$stringText = preg_replace('/\b'.$word.'\b/'.(($this->parserCharset == 'utf-8')?'u':''), '<span class="HA-spellcheck-error">'.$word.'</span>', $stringText);
+							$stringText = preg_replace('/\b'.$word.'\b/'.(($this->parserCharset == 'utf-8')?'u':''), '<span class="htmlarea-spellcheck-error">'.$word.'</span>', $stringText);
 							$incurrent[] = $word;
 						}
 					}
@@ -391,7 +390,7 @@
 							unset($suggestions);
 						}
 						if (!in_array($word, $incurrent)) {
-							$stringText = preg_replace('/\b'.$word.'\b/'.(($this->parserCharset == 'utf-8')?'u':''), '<span class="HA-spellcheck-error">'.$word.'</span>', $stringText);
+							$stringText = preg_replace('/\b'.$word.'\b/'.(($this->parserCharset == 'utf-8')?'u':''), '<span class="htmlarea-spellcheck-error">'.$word.'</span>', $stringText);
 							$incurrent[] = $word;
 						}
 					}
Index: typo3/sysext/t3skin/rtehtmlarea/htmlarea.css
===================================================================
--- typo3/sysext/t3skin/rtehtmlarea/htmlarea.css	(révision 7101)
+++ typo3/sysext/t3skin/rtehtmlarea/htmlarea.css	(copie de travail)
@@ -490,56 +490,23 @@
 	border: 1px solid #A2AAB8;
 }
 /* Selectors for the SpellChecker dialogue */
-.htmlarea-spell-check .dictionaries {
-	float:right;
-	padding:2px;
+.htmlarea-window .spell-check .controls {
+	text-align: center;
+	width: 175px;
+	margin: 3px;
 }
-.htmlarea-spell-check .dictionaries #v_dictionaries {
-	width:10em;
-	margin-right:5px;
+.htmlarea-window .spell-check .controls .x-btn {
+	margin-top: 3px;
+	margin-left: 8px;
 }
-.htmlarea-spell-check #b_recheck {
-	vertical-align:middle;
-	width:12em;
+.htmlarea-window .spell-check .contentframe {
+	float: right;
+	height: 450px;
+	margin: 9px 0px;
+	background-color: #FFF;
+	color: #000;
+	border: 1px solid #A2AAB8;
 }
-.htmlarea-spell-check .status {
-	font-weight:bold;
-	padding:2px;
-}
-.htmlarea-spell-check .controls {
-	width:14em;
-	clear:right;float:left;
-	text-align:center;
-	margin:3px;
-}
-.htmlarea-spell-check .controls .sectitle {
-	font-weight:bold;
-	padding:2px 4px;
-}
-.htmlarea-spell-check .controls .secbody {
-	margin-bottom:10px;
-}
-.htmlarea-spell-check .controls #v_currentWord {
-	color:#F00;font-weight:bold;
-	margin-bottom:2px;
-}
-.htmlarea-spell-check .controls #v_replacement {
-	margin-bottom:3px;
-}
-.htmlarea-spell-check .controls #v_suggestions, .controls #v_replacement {
-	width:12em;
-}
-.htmlarea-spell-check .contentframe {
-	float:right; margin:3px;
-}
-.htmlarea-spell-check .contentframe #i_framecontent {
-	background-color:#FFF;color:#000;
-	height:450px;width:480px;
-}
-.htmlarea-spell-check .occurrences-found {
-	padding:7px 0px 0px 5px;
-	clear:both;
-}
 /* Selectors for the ContextMenu plugin */
 .htmlarea-context-menu {
 	background-color:#EFEFF4;
@@ -565,3 +532,57 @@
 	margin-bottom:0;
 	border-color:#A2AAB8;
 }
+/* Window status bar selectors */
+.htmlarea-window .status-ready {
+	padding-left: 21px !important;
+	background-repeat: no-repeat;
+	background-image: url("images/dialog-ok.png");
+	background-position: 0px 2px;
+}
+.htmlarea-window .status-info {
+	padding-left: 21px !important;
+	background-repeat: no-repeat;
+	background-image: url("images/dialog-information.png");
+	background-position: 0px 2px;
+}
+.htmlarea-window .status-wait {
+	padding-left: 45px !important;
+	background-repeat: no-repeat;
+	background-image:url("images/loading-balls.gif");
+	background-position: 0px 6px;
+}
+.x-statusbar .x-btn {
+	margin-left: 5px;
+}
+.x-statusbar .x-status-text {
+    cursor: default;
+}
+
+/* Button background positioning in window status bar*/
+.x-statusbar .x-btn-tl{
+	background-position: 0 0;
+}
+.x-statusbar .x-btn-tr{
+	background-position: -3px 0;
+}
+.x-statusbar .x-btn-tc{
+	background-position: 0 -6px;
+}
+.x-statusbar .x-btn-ml{
+	background-position: 0 -24px;
+}
+.x-statusbar .x-btn-mr{
+	background-position: -3px -24px;
+}
+.x-statusbar .x-btn-mc{
+	background-position: 0 -1096px;
+}
+.x-statusbar .x-btn-bl{
+	background-position: 0 -3px;
+}
+.x-statusbar .x-btn-br{
+	background-position: -3px -3px;
+}
+.x-statusbar .x-btn-bc{
+	background-position: 0 -15px;
+}
Index: typo3/sysext/t3skin/rtehtmlarea/images/dialog-information.png
===================================================================
Impossible d'afficher : fichier considéré comme binaire.
svn:mime-type = application/octet-stream

Modification de propriétés sur typo3\sysext\t3skin\rtehtmlarea\images\dialog-information.png
___________________________________________________________________
Ajouté : svn:mime-type
   + application/octet-stream

Index: typo3/sysext/t3skin/rtehtmlarea/images/dialog-ok.png
===================================================================
Impossible d'afficher : fichier considéré comme binaire.
svn:mime-type = application/octet-stream

Modification de propriétés sur typo3\sysext\t3skin\rtehtmlarea\images\dialog-ok.png
___________________________________________________________________
Ajouté : svn:mime-type
   + application/octet-stream

Index: typo3/sysext/t3skin/rtehtmlarea/images/loading-balls.gif
===================================================================
Impossible d'afficher : fichier considéré comme binaire.
svn:mime-type = application/octet-stream

Modification de propriétés sur typo3\sysext\t3skin\rtehtmlarea\images\loading-balls.gif
___________________________________________________________________
Ajouté : svn:mime-type
   + application/octet-stream

