SpellChecker imple moved to Horde_Ajax.
authorMichael M Slusarz <slusarz@curecanti.org>
Thu, 16 Jul 2009 19:56:52 +0000 (13:56 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Thu, 16 Jul 2009 19:56:52 +0000 (13:56 -0600)
imp/js/src/KeyNavList.js [deleted file]
imp/js/src/SpellChecker.js [deleted file]
imp/lib/Ajax/Imple/SpellChecker.php [deleted file]
imp/lib/UI/Compose.php
imp/themes/screen.css

diff --git a/imp/js/src/KeyNavList.js b/imp/js/src/KeyNavList.js
deleted file mode 100644 (file)
index 1d3d48e..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * Reuseable keyboard or mouse driven list component. Based on
- * Scriptaculous' AutoCompleter.
- *
- * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var KeyNavList = Class.create({
-    // Vars used and defaulting to empty:
-    //     active, entryCount
-
-    initialize: function(element, options)
-    {
-        var clickfunc = this.onClick.bindAsEventListener(this),
-            entry,
-            i = 0,
-            overfunc = this.onHover.bindAsEventListener(this);
-
-        this.element = $(element);
-        this.options = options || {};
-        this.index = -1;
-
-        this.entryCount = this.element.firstDescendant().childElements().size();
-        for (; i < this.entryCount; i++) {
-            entry = this.getEntry(i);
-            entry.writeAttribute('autocompleteIndex', i);
-            entry.observe('click', clickfunc);
-            entry.observe('mouseover', overfunc);
-        }
-
-        this.options.onShow = this.options.onShow ||
-            function(elt) { new Effect.Appear(elt, { duration: 0.15 }); };
-        this.options.onHide = this.options.onHide ||
-            function(elt) { new Effect.Fade(elt, { duration: 0.15 }); };
-
-        this.element.observe('blur', this.onBlur.bind(this));
-        document.observe('keypress', this.onKeyPress.bindAsEventListener(this));
-    },
-
-    show: function()
-    {
-        this.active = true;
-        if (!this.element.visible()) {
-            this.options.onShow(this.element);
-        }
-        if (!this.iefix &&
-            (navigator.appVersion.indexOf('MSIE') > 0) &&
-            (this.element.getStyle('position') == 'absolute')) {
-            this.element.insert({ after:
-                '<iframe id="' + this.element.id + '_iefix" '
-                + 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" '
-                + 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>'});
-            this.iefix = $(this.element.id + '_iefix');
-        }
-        if (this.iefix) {
-            setTimeout(this.fixIEOverlapping.bind(this), 50);
-        }
-    },
-
-    fixIEOverlapping: function()
-    {
-        this.iefix.clonePosition(this.element).setStyle({ zIndex: 1 }).show();
-        this.element.setStyle({ zIndex: 2 });
-    },
-
-    hide: function()
-    {
-        this.active = false;
-        this.stopIndicator();
-        if (this.element.visible()) {
-            this.options.onHide(this.element);
-        }
-        if (this.iefix) {
-            this.iefix.hide();
-        }
-    },
-
-    startIndicator: function()
-    {
-        if (this.options.indicator) {
-            $(this.options.indicator).show();
-        }
-    },
-
-    stopIndicator: function()
-    {
-        if (this.options.indicator) {
-            $(this.options.indicator).hide();
-        }
-    },
-
-    onKeyPress: function(e)
-    {
-        if (!this.active) {
-            return;
-        }
-
-        switch (e.keyCode) {
-        case Event.KEY_TAB:
-        case Event.KEY_RETURN:
-            this.selectEntry();
-            e.stop();
-
-        case Event.KEY_ESC:
-            this.hide();
-            this.active = false;
-            e.stop();
-            return;
-
-        case Event.KEY_LEFT:
-        case Event.KEY_RIGHT:
-            return;
-
-        case Event.KEY_UP:
-            this.markPrevious();
-            this.render();
-            e.stop();
-            return;
-
-        case Event.KEY_DOWN:
-            this.markNext();
-            this.render();
-            e.stop();
-            return;
-        }
-    },
-
-    onHover: function(e)
-    {
-        var element = e.findElement('LI'),
-            index = parseInt(element.readAttribute('autocompleteIndex'));
-        if (this.index != index) {
-            this.index = index;
-            this.render();
-        }
-        e.stop();
-    },
-
-    onClick: function(e)
-    {
-        var element = e.findElement('LI');
-        this.index = parseInt(element.readAttribute('autocompleteIndex'));
-        this.selectEntry();
-        this.hide();
-        e.stop();
-    },
-
-    onBlur: function()
-    {
-        setTimeout(this.hide.bind(this), 250);
-        this.active = false;
-    },
-
-    render: function()
-    {
-        if (this.entryCount > 0) {
-            for (var i = 0; i < this.entryCount; i++) {
-                [ this.getEntry(i) ].invoke(this.index == i ? 'addClassName' : 'removeClassName', 'selected');
-            }
-            this.show();
-            this.active = true;
-        } else {
-            this.hide();
-            this.active = false;
-        }
-    },
-
-    markPrevious: function()
-    {
-        if (this.index > 0) {
-            this.index--;
-        } else {
-            this.index = this.entryCount - 1;
-        }
-    },
-
-    markNext: function()
-    {
-        if (this.index < this.entryCount - 1) {
-            this.index++;
-        } else {
-            this.index = 0;
-        }
-    },
-
-    getEntry: function(index)
-    {
-        return this.element.down().down(index);
-    },
-
-    getCurrentEntry: function()
-    {
-        return this.getEntry(this.index);
-    },
-
-    selectEntry: function()
-    {
-        this.active = false;
-        if (typeof this.options.onChoose == 'function') {
-            this.options.onChoose(this.getCurrentEntry());
-        }
-    }
-
-});
diff --git a/imp/js/src/SpellChecker.js b/imp/js/src/SpellChecker.js
deleted file mode 100644 (file)
index 8213989..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-/**
- * This spell checker was inspired by work done by Garrison Locke, but
- * was rewritten almost completely by Chuck Hagenbuch to use
- * Prototype/Scriptaculous.
- *
- * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- */
-
-var SpellChecker = Class.create({
-
-    // Vars used and defaulting to null:
-    //   bad, choices, choicesDiv, curWord, htmlArea, htmlAreaParent, locale,
-    //   localeChoices, onAfterSpellCheck, onBeforeSpellCheck, onNoError,
-    //   reviewDiv, statusButton, statusClass, suggestions, target, url
-    options: {},
-    resumeOnDblClick: true,
-    state: 'CheckSpelling',
-
-    // url = (string) URL of specllchecker handler
-    // target = (string) DOM ID of message data
-    // statusButton = (string/element) DOM ID or element of the status button
-    // bs = (array) Button states
-    // locales = (array) List of locales
-    // sc = (string) Status class
-    initialize: function(url, target, statusButton, bs, locales, sc)
-    {
-        var d, popdown, ul;
-
-        this.url = url;
-        this.target = target;
-        this.statusButton = $(statusButton);
-        this.buttonStates = bs;
-        this.statusClass = sc || '';
-
-        this.statusButton.observe('click', this.process.bindAsEventListener(this));
-        this.options.onComplete = this.onComplete.bind(this);
-
-        if (locales) {
-            d = new Element('DIV', { className: 'autocomplete', id: 'spellcheckpopdown' }).setStyle({ position: 'absolute' }).hide();
-            ul = new Element('UL');
-            $H(locales).each(function(pair) {
-                ul.insert({ bottom: new Element('LI', { lc: pair.key }).update(pair.value) });
-            });
-            d.insert({ bottom: ul });
-
-            this.localeChoices = new KeyNavList(d, { onChoose: this.setLocale.bindAsEventListener(this) });
-
-            popdown = new Element('SPAN', { className: 'spellcheckPopdownImg' }).observe('click', function() {
-                $('spellcheckpopdown').clonePosition(this.statusButton, {
-                    setHeight: false,
-                    setWidth: false,
-                    offsetTop: this.statusButton.getHeight()
-                });
-                this.localeChoices.show();
-            }.bind(this));
-
-            this.statusButton.insert({ after: popdown });
-
-            $(document.body).insert(d);
-        }
-
-        // We need to monitor clicks to know when to go out of
-        // showSuggestions mode.
-        document.observe('click', this.onClick.bindAsEventListener(this));
-
-        this.setStatus('CheckSpelling');
-    },
-
-    setLocale: function(e)
-    {
-        this.locale = e.readAttribute('lc');
-    },
-
-    targetValue: function()
-    {
-        var input = $(this.target);
-        return (Object.isUndefined(input.value)) ? input.innerHTML : input.value;
-    },
-
-    process: function(e)
-    {
-        switch (this.state) {
-        case 'CheckSpelling':
-            this.spellCheck();
-            break;
-
-        case 'ResumeEdit':
-            this.resume();
-            break;
-        }
-
-        e.stop();
-    },
-
-    // noerror - (function) A callback function to run if no errors are
-    //           identified. If not specified, will remain in spell check
-    //           mode even if no errors are present.
-    spellCheck: function(noerror)
-    {
-        if (this.onBeforeSpellCheck) {
-            this.onBeforeSpellCheck();
-        }
-
-        var opts = Object.clone(this.options),
-            p = $H(),
-            url = this.url;
-
-        this.setStatus('Checking');
-        this.removeChoices();
-
-        this.onNoError = noerror;
-
-        p.set(this.target, this.targetValue());
-        opts.parameters = p.toQueryString();
-
-        if (this.locale) {
-            url += '/locale=' + this.locale;
-        }
-        if (this.htmlAreaParent) {
-            url += '/html=1';
-        }
-
-        new Ajax.Request(url, opts);
-    },
-
-    onClick: function(e)
-    {
-        // If the language dropdown is currently active, and the click
-        // got here, then we should hide the language dropdown.
-        if (this.localeChoices) {
-            this.localeChoices.hide();
-        }
-
-        // If we're not currently showing any choices, then we return
-        // and let the click go.
-        if (!this.choicesDiv) {
-            return true;
-        }
-
-        // If the click was on the word that we're currently showing
-        // results for, then we do nothing and let the list be
-        // redisplayed by the link's own onclick handler.
-        var link = e.findElement('SPAN');
-        if (link && link == this.curWord) {
-            return true;
-        }
-
-        // The KeyNavList will have already handled any valid clicks,
-        // so that just leaves the rest of the window - in this case
-        // we want to hide the KeyNavList and reset curWord without
-        // changing anything.
-        this.removeChoices();
-        this.curWord = null;
-    },
-
-    onComplete: function(request)
-    {
-        var bad, content, d,
-            i = 0,
-            input = $(this.target),
-            result = request.responseJSON;
-
-        this.removeChoices();
-
-        if (Object.isUndefined(result)) {
-            this.setStatus('Error');
-            return;
-        }
-
-        this.suggestions = result.suggestions || [];
-
-        if (this.onNoError && !this.suggestions.size()) {
-            this.setStatus('CheckSpelling');
-            this.onNoError();
-            return;
-        }
-
-        bad = result.bad || [];
-
-        content = this.targetValue();
-        content = this.htmlAreaParent
-            ? content.replace(/\r?\n/g, '')
-            : content.replace(/\r?\n/g, '~~~').escapeHTML();
-
-        $A(bad).each(function(node) {
-            var re_text = '<span index="' + (i++) + '" class="spellcheckIncorrect">' + node + '</span>';
-            content = content.replace(new RegExp("(?:^|\\b)" + RegExp.escape(node) + "(?:\\b|$)", 'g'), re_text);
-
-            // Go through and see if we matched anything inside a tag (i.e.
-            // class/spellcheckIncorrect is often matched if using a
-            // non-English lang).
-            content = content.replace(new RegExp("(<[^>]*)" + RegExp.escape(re_text) + "([^>]*>)", 'g'), '\$1' + node + '\$2');
-        }, this);
-
-        if (!this.reviewDiv) {
-            this.reviewDiv = new Element('div', { className: input.readAttribute('className') + ' spellcheck' }).setStyle({ overflow: 'auto' });
-            if (this.resumeOnDblClick) {
-                this.reviewDiv.observe('dblclick', this.resume.bind(this));
-            }
-        }
-
-        d = input.getDimensions();
-        this.reviewDiv.setStyle({ width: d.width + 'px', height: d.height + 'px'});
-
-        if (!this.htmlAreaParent) {
-            content = content.replace(/~~~/g, '<br />');
-        }
-        this.reviewDiv.update(content);
-
-        // Now attach results behavior to each link.
-        this.reviewDiv.select('span.spellcheckIncorrect').invoke('observe', 'click', this.showSuggestions.bindAsEventListener(this));
-
-        // Falsify links
-        this.reviewDiv.select('A').invoke('observe', 'click', Event.stop);
-
-        if (this.htmlAreaParent) {
-            // Fix for Safari 3/fckeditor - Ticket #6909
-            Element.hide(this.htmlArea);
-            $(this.htmlAreaParent).insert({ bottom: this.reviewDiv });
-        } else {
-            input.hide().insert({ before: this.reviewDiv });
-        }
-
-        this.setStatus('ResumeEdit');
-    },
-
-    showSuggestions: function(e)
-    {
-        var pos,
-            elt = e.element(),
-            ul = new Element('UL');
-
-        try {
-            pos = elt.viewportOffset();
-        } catch (err) {
-            // Fix for Safari 3/fckeditor - Ticket #6909
-            pos = [ e.pointerX(), e.pointerY() ];
-        }
-
-        this.removeChoices();
-        this.choicesDiv = new Element('DIV', { className: 'autocomplete' }).setStyle({ left: pos[0] + 'px', top: (pos[1] + 16) + 'px' }).hide();
-        this.curWord = elt;
-
-        $A(this.suggestions[this.curWord.readAttribute('index')]).each(function(node) {
-            ul.insert({ bottom: new Element('LI').update(node) });
-        });
-        this.choicesDiv.insert({ bottom: ul });
-
-        this.choices = new KeyNavList(this.choicesDiv, { onChoose: function(elt) { this.replaceWord(elt, this.curWord); }.bind(this) }).show();
-        $(document.body).insert(this.choicesDiv);
-    },
-
-    replaceWord: function(li, word)
-    {
-        word.update(li.innerHTML).writeAttribute({ className: 'spellcheckCorrected' });
-        this.removeChoices();
-    },
-
-    removeChoices: function()
-    {
-        if (this.choicesDiv) {
-            this.choicesDiv.remove();
-            this.choicesDiv = null;
-        }
-    },
-
-    resume: function()
-    {
-        this.removeChoices();
-
-        if (!this.reviewDiv) {
-            return;
-        }
-
-        var input = $(this.target),
-            t;
-
-        this.reviewDiv.select('span.spellcheckIncorrect').each(function(n) {
-            n.replace(n.innerHTML);
-        });
-
-        // Unfalsify links
-        this.reviewDiv.select('A').invoke('stopObserving', 'click');
-
-        t = this.reviewDiv.innerHTML;
-        if (!this.htmlAreaParent) {
-            t = t.replace(/<br *\/?>/gi, '~~~').unescapeHTML().replace(/~~~/g, "\n");
-        }
-        input.value = t;
-        input.disabled = false;
-
-        if (this.resumeOnDblClick) {
-            this.reviewDiv.stopObserving('dblclick');
-        }
-        this.reviewDiv.remove();
-        this.reviewDiv = null;
-
-        this.setStatus('CheckSpelling');
-
-        if (this.htmlAreaParent) {
-            // Fix for Safari 3/fckeditor - Ticket #6909
-            Element.show(this.htmlArea);
-        } else {
-            input.show();
-        }
-
-        if (this.onAfterSpellCheck) {
-            this.onAfterSpellCheck();
-        }
-    },
-
-    setStatus: function(state)
-    {
-        if (!this.statusButton) {
-            return;
-        }
-
-        this.state = state;
-        switch (this.statusButton.tagName) {
-        case 'INPUT':
-            this.statusButton.value = this.buttonStates[state];
-            break;
-
-        case 'A':
-            this.statusButton.update(this.buttonStates[state]);
-            break;
-        }
-        this.statusButton.className = this.statusClass + ' spellcheck' + state;
-    },
-
-    isActive: function()
-    {
-        return (this.reviewDiv);
-    }
-
-});
diff --git a/imp/lib/Ajax/Imple/SpellChecker.php b/imp/lib/Ajax/Imple/SpellChecker.php
deleted file mode 100644 (file)
index d0b1494..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-<?php
-/**
- * Attach the spellchecker to a javascript element.
- *
- * Copyright 2005-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author  Michael Slusarz <slusarz@horde.org>
- * @package IMP
- */
-class IMP_Ajax_Imple_SpellChecker extends Horde_Ajax_Imple_Base
-{
-    /**
-     * Constructor.
-     *
-     * @param array $params  Configuration parameters.
-     * <pre>
-     * 'id' => TODO (optional)
-     * 'locales' => TODO (optional)
-     * 'states' => TODO (optional)
-     * 'targetId' => TODO (optional)
-     * 'triggerId' => TODO (optional)
-     * </pre>
-     */
-    public function __construct($params = array())
-    {
-        if (empty($params['id'])) {
-            $params['id'] = $this->_randomid();
-        }
-        if (empty($params['targetId'])) {
-            $params['targetId'] = $this->_randomid();
-        }
-        if (empty($params['triggerId'])) {
-            $params['triggerId'] = $params['targetId'] . '_trigger';
-        }
-        if (empty($params['states'])) {
-            $params['states'] = '""';
-        } else {
-            $params['states'] = Horde_Serialize::serialize($params['states'], Horde_Serialize::JSON, Horde_Nls::getCharset());
-        }
-        if (empty($params['locales'])) {
-            $params['locales'] = array();
-            foreach (array_keys(Horde_Nls::$config['spelling']) as $lcode) {
-                $params['locales'][$lcode] = Horde_Nls::$config['languages'][$lcode];
-            }
-        }
-        asort($params['locales'], SORT_LOCALE_STRING);
-        $params['locales'] = Horde_Serialize::serialize($params['locales'], Horde_Serialize::JSON, Horde_Nls::getCharset());
-
-        parent::__construct($params);
-    }
-
-    /**
-     */
-    public function attach()
-    {
-        Horde::addScriptFile('prototype.js', 'horde', true);
-        Horde::addScriptFile('effects.js', 'horde', true);
-        Horde::addScriptFile('KeyNavList.js', 'imp', true);
-        Horde::addScriptFile('SpellChecker.js', 'imp', true);
-
-        $url = $this->_getUrl('SpellChecker', 'imp', array('input' => $this->_params['targetId']));
-
-        IMP::addInlineScript($this->_params['id'] . ' = new SpellChecker("' . $url . '", "' . $this->_params['targetId'] . '", "' . $this->_params['triggerId'] . '", ' . $this->_params['states'] . ', ' . $this->_params['locales'] . ', \'widget\');', 'dom');
-    }
-
-    /**
-     */
-    public function handle($args)
-    {
-        $spellArgs = array();
-
-        if (!empty($GLOBALS['conf']['spell']['params'])) {
-            $spellArgs = $GLOBALS['conf']['spell']['params'];
-        }
-
-        if (isset($args['locale'])) {
-            $spellArgs['locale'] = $args['locale'];
-        } elseif (isset($GLOBALS['language'])) {
-            $spellArgs['locale'] = $GLOBALS['language'];
-        }
-
-        /* Add local dictionary words. */
-        try {
-            $result = Horde::loadConfiguration('spelling.php', 'ignore_list', 'horde');
-            $spellArgs['localDict'] = $result;
-        } catch (Horde_Exception $e) {}
-
-        if (!empty($args['html'])) {
-            $spellArgs['html'] = true;
-        }
-
-        try {
-            $speller = Horde_SpellChecker::getInstance($GLOBALS['conf']['spell']['driver'], $spellArgs);
-        } catch (Horde_Exception $e) {
-            Horde::logMessage($e, __FILE__, __LINE__, PEAR_LOG_ERR);
-            return array();
-        }
-
-        try {
-            return $speller->spellCheck(Horde_Util::getPost($args['input']));
-        } catch (Horde_Exception $e) {
-            Horde::logMessage($e, __FILE__, __LINE__, PEAR_LOG_ERR);
-            return array('bad' => array(), 'suggestions' => array());
-        }
-    }
-
-}
index 6f2cd6c..e14681f 100644 (file)
@@ -124,7 +124,7 @@ class IMP_UI_Compose
             )
         );
 
-        $imple = Horde_Ajax_Imple::getInstance(array('imp', 'SpellChecker'), $args);
+        $imple = Horde_Ajax_Imple::getInstance('SpellChecker', $args);
         $imple->attach();
     }
 
index f5384fc..848120e 100644 (file)
@@ -370,18 +370,6 @@ table.multipleMsgs td.msgheader {
     vertical-align: top;
 }
 
-/* SpellChecker styles. */
-.spellcheckChecking, .spellcheckIncorrect {
-    color: #f00;
-}
-.spellcheckIncorrect, .spellcheckCorrected {
-    text-decoration: underline;
-    cursor: pointer;
-}
-.spellcheckCorrected {
-    color: #090;
-}
-
 /* Contacts styles. */
 #contactstable #search {
     width: 150px;