Added feature #13870: htmlArea RTE: Extjize the spell checker
authorStanislas Rolland <typo3@sjbr.ca>
Sat, 20 Mar 2010 20:55:09 +0000 (20:55 +0000)
committerStanislas Rolland <typo3@sjbr.ca>
Sat, 20 Mar 2010 20:55:09 +0000 (20:55 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@7138 709f56b5-9817-0410-a4d7-c38de5d9e867

19 files changed:
ChangeLog
typo3/sysext/rtehtmlarea/ChangeLog
typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js
typo3/sysext/rtehtmlarea/htmlarea/locallang_dialogs.xml
typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/locallang.xml
typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui-iso-8859-1.html [deleted file]
typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui.html [deleted file]
typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-check-style.css
typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-check-ui.js [deleted file]
typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-checker.js
typo3/sysext/rtehtmlarea/htmlarea/skins/default/htmlarea.css
typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/dialog-information.png [new file with mode: 0644]
typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/dialog-ok.png [new file with mode: 0644]
typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/loading-balls.gif [new file with mode: 0644]
typo3/sysext/rtehtmlarea/pi1/class.tx_rtehtmlarea_pi1.php
typo3/sysext/t3skin/rtehtmlarea/htmlarea.css
typo3/sysext/t3skin/rtehtmlarea/images/dialog-information.png [new file with mode: 0644]
typo3/sysext/t3skin/rtehtmlarea/images/dialog-ok.png [new file with mode: 0644]
typo3/sysext/t3skin/rtehtmlarea/images/loading-balls.gif [new file with mode: 0644]

index e8cec95..741b2d9 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-03-20  Stanislas Rolland  <typo3@sjbr.ca>
+
+       * Added feature #13870: htmlArea RTE: Extjize the spell checker
+
 2010-03-20  Andreas Otto  <andreas@otto-hanika.de>
 
        * Fixed bug #13871: Field data_page_type in table index_phash is too small.
index b2ae1af..7956a28 100644 (file)
@@ -1,3 +1,7 @@
+2010-03-20  Stanislas Rolland  <typo3@sjbr.ca>
+
+       * Added feature #13870: htmlArea RTE: Extjize the spell checker
+
 2010-03-11  Stanislas Rolland  <typo3@sjbr.ca>
 
        * Fixed bug #9218: htmlArea RTE: "Remove format" messes up some inline formats
index 2e1abbd..15ced60 100644 (file)
@@ -1405,6 +1405,424 @@ HTMLArea.Iframe = Ext.extend(Ext.BoxComponent, {
        }
 });
 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 @@ HTMLArea.Plugin = HTMLArea.Base.extend({
         * Dialogue window onClose handler
         */
        onClose: function () {
+               this.editor.focus();
                this.restoreSelection();
                this.editor.updateToolbar();
        },
@@ -4014,6 +4433,7 @@ HTMLArea.Plugin = HTMLArea.Base.extend({
         */
        onCancel: function () {
                this.dialog.close();
+               this.editor.focus();
        },
        /*
         * Save selection
index 37bf8a1..00d520d 100644 (file)
                        <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 a6edded..a7ed951 100644 (file)
@@ -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>
diff --git a/typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui-iso-8859-1.html b/typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui-iso-8859-1.html
deleted file mode 100644 (file)
index 843fa37..0000000
+++ /dev/null
@@ -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>
diff --git a/typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui.html b/typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/popups/spell-check-ui.html
deleted file mode 100644 (file)
index 165164f..0000000
+++ /dev/null
@@ -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 617c609..22964d5 100644 (file)
@@ -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;
+}
diff --git a/typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-check-ui.js b/typo3/sysext/rtehtmlarea/htmlarea/plugins/SpellChecker/spell-check-ui.js
deleted file mode 100644 (file)
index 8c7b8f8..0000000
+++ /dev/null
@@ -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 ddc5b94..2332a14 100644 (file)
  * 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.
         *
@@ -88,17 +98,701 @@ SpellChecker = HTMLArea.Plugin.extend({
         *
         * @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 d2fe84d..b99ada8 100644 (file)
        border: 1px solid #A2AAB8;
 }
 /* Selectors for the SpellChecker dialogue */
-.htmlarea-spell-check .dictionaries {
-       float:right;
-       padding:2px;
-}
-.htmlarea-spell-check .dictionaries #v_dictionaries {
-       width:10em;
-       margin-right:5px;
-}
-.htmlarea-spell-check #b_recheck {
-       vertical-align:middle;
-       width:12em;
-}
-.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-window .spell-check .controls {
+       text-align: center;
+       width: 175px;
+       margin: 3px;
 }
-.htmlarea-spell-check .contentframe #i_framecontent {
-       background-color:#FFF;color:#000;
-       height:450px;width:480px;
+.htmlarea-window .spell-check .controls .x-btn {
+       margin-top: 3px;
+       margin-left: 8px;
 }
-.htmlarea-spell-check .occurrences-found {
-       padding:7px 0px 0px 5px;
-       clear:both;
+.htmlarea-window .spell-check .contentframe {
+       float: right;
+       height: 450px;
+       margin: 9px 0px;
+       background-color: #FFF;
+       color: #000;
+       border: 1px solid #A2AAB8;
 }
 /* Selectors for the ContextMenu plugin */
 .htmlarea-context-menu {
        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;
+}
diff --git a/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/dialog-information.png b/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/dialog-information.png
new file mode 100644 (file)
index 0000000..4d7953a
Binary files /dev/null and b/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/dialog-information.png differ
diff --git a/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/dialog-ok.png b/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/dialog-ok.png
new file mode 100644 (file)
index 0000000..89c8129
Binary files /dev/null and b/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/dialog-ok.png differ
diff --git a/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/loading-balls.gif b/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/loading-balls.gif
new file mode 100644 (file)
index 0000000..046581f
Binary files /dev/null and b/typo3/sysext/rtehtmlarea/htmlarea/skins/default/images/loading-balls.gif differ
index 171ca2e..7bab7f2 100644 (file)
@@ -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 @@ class tx_rtehtmlarea_pi1 {
                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 @@ class tx_rtehtmlarea_pi1 {
      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 @@ class tx_rtehtmlarea_pi1 {
                        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 @@ class tx_rtehtmlarea_pi1 {
                                                        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 @@ class tx_rtehtmlarea_pi1 {
                                                        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 81f626d..a78b39a 100644 (file)
        border: 1px solid #A2AAB8;
 }
 /* Selectors for the SpellChecker dialogue */
-.htmlarea-spell-check .dictionaries {
-       float:right;
-       padding:2px;
-}
-.htmlarea-spell-check .dictionaries #v_dictionaries {
-       width:10em;
-       margin-right:5px;
-}
-.htmlarea-spell-check #b_recheck {
-       vertical-align:middle;
-       width:12em;
-}
-.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-window .spell-check .controls {
+       text-align: center;
+       width: 175px;
+       margin: 3px;
 }
-.htmlarea-spell-check .contentframe #i_framecontent {
-       background-color:#FFF;color:#000;
-       height:450px;width:480px;
+.htmlarea-window .spell-check .controls .x-btn {
+       margin-top: 3px;
+       margin-left: 8px;
 }
-.htmlarea-spell-check .occurrences-found {
-       padding:7px 0px 0px 5px;
-       clear:both;
+.htmlarea-window .spell-check .contentframe {
+       float: right;
+       height: 450px;
+       margin: 9px 0px;
+       background-color: #FFF;
+       color: #000;
+       border: 1px solid #A2AAB8;
 }
 /* Selectors for the ContextMenu plugin */
 .htmlarea-context-menu {
        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;
+}
diff --git a/typo3/sysext/t3skin/rtehtmlarea/images/dialog-information.png b/typo3/sysext/t3skin/rtehtmlarea/images/dialog-information.png
new file mode 100644 (file)
index 0000000..4d7953a
Binary files /dev/null and b/typo3/sysext/t3skin/rtehtmlarea/images/dialog-information.png differ
diff --git a/typo3/sysext/t3skin/rtehtmlarea/images/dialog-ok.png b/typo3/sysext/t3skin/rtehtmlarea/images/dialog-ok.png
new file mode 100644 (file)
index 0000000..89c8129
Binary files /dev/null and b/typo3/sysext/t3skin/rtehtmlarea/images/dialog-ok.png differ
diff --git a/typo3/sysext/t3skin/rtehtmlarea/images/loading-balls.gif b/typo3/sysext/t3skin/rtehtmlarea/images/loading-balls.gif
new file mode 100644 (file)
index 0000000..046581f
Binary files /dev/null and b/typo3/sysext/t3skin/rtehtmlarea/images/loading-balls.gif differ